supython 0.1.0__py3-none-any.whl
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.
- supython/__init__.py +24 -0
- supython/admin/__init__.py +3 -0
- supython/admin/api/__init__.py +24 -0
- supython/admin/api/auth.py +118 -0
- supython/admin/api/auth_templates.py +67 -0
- supython/admin/api/auth_users.py +225 -0
- supython/admin/api/db.py +174 -0
- supython/admin/api/functions.py +92 -0
- supython/admin/api/jobs.py +192 -0
- supython/admin/api/ops.py +224 -0
- supython/admin/api/realtime.py +281 -0
- supython/admin/api/service_auth.py +49 -0
- supython/admin/api/service_auth_templates.py +83 -0
- supython/admin/api/service_auth_users.py +346 -0
- supython/admin/api/service_db.py +214 -0
- supython/admin/api/service_functions.py +287 -0
- supython/admin/api/service_jobs.py +282 -0
- supython/admin/api/service_ops.py +213 -0
- supython/admin/api/service_realtime.py +30 -0
- supython/admin/api/service_storage.py +220 -0
- supython/admin/api/storage.py +117 -0
- supython/admin/api/system.py +37 -0
- supython/admin/audit.py +29 -0
- supython/admin/deps.py +22 -0
- supython/admin/errors.py +16 -0
- supython/admin/schemas.py +310 -0
- supython/admin/session.py +52 -0
- supython/admin/spa.py +38 -0
- supython/admin/static/assets/Alert-dluGVkos.js +49 -0
- supython/admin/static/assets/Audit-Njung3HI.js +2 -0
- supython/admin/static/assets/Backups-DzPlFgrm.js +2 -0
- supython/admin/static/assets/Buckets-ByacGkU1.js +2 -0
- supython/admin/static/assets/Channels-BoIuTtam.js +353 -0
- supython/admin/static/assets/ChevronRight-CtQH1EQ1.js +2 -0
- supython/admin/static/assets/CodeViewer-Bqy7-wvH.js +2 -0
- supython/admin/static/assets/Crons-B67vc39F.js +2 -0
- supython/admin/static/assets/DashboardView-CUTFVL6k.js +2 -0
- supython/admin/static/assets/DataTable-COAAWEft.js +747 -0
- supython/admin/static/assets/DescriptionsItem-P8JUDaBs.js +75 -0
- supython/admin/static/assets/DrawerContent-TpYTFgF1.js +139 -0
- supython/admin/static/assets/Empty-cr2r7e2u.js +25 -0
- supython/admin/static/assets/EmptyState-DeDck-OL.js +2 -0
- supython/admin/static/assets/Grid-hFkp9F4P.js +2 -0
- supython/admin/static/assets/Input-DppYTq9C.js +259 -0
- supython/admin/static/assets/Invoke-DW3Nveeh.js +2 -0
- supython/admin/static/assets/JsonField-DibyJgun.js +2 -0
- supython/admin/static/assets/LoginView-BjLyE3Ds.css +1 -0
- supython/admin/static/assets/LoginView-CoOjECT_.js +111 -0
- supython/admin/static/assets/Logs-D9WYrnIT.js +2 -0
- supython/admin/static/assets/Logs-DS1XPa0h.css +1 -0
- supython/admin/static/assets/Migrations-DOSC2ddQ.js +2 -0
- supython/admin/static/assets/ObjectBrowser-_5w8vOX8.js +2 -0
- supython/admin/static/assets/Queue-CywZs6vI.js +2 -0
- supython/admin/static/assets/RefreshTokens-Ccjr53jg.js +2 -0
- supython/admin/static/assets/RlsEditor-BSlH9vSc.js +2 -0
- supython/admin/static/assets/Routes-BiLXE49D.js +2 -0
- supython/admin/static/assets/Routes-C-ianIGD.css +1 -0
- supython/admin/static/assets/SchemaBrowser-DKy2_KQi.css +1 -0
- supython/admin/static/assets/SchemaBrowser-XFvFbtDB.js +2 -0
- supython/admin/static/assets/Select-DIzZyRZb.js +434 -0
- supython/admin/static/assets/Space-n5-XcguU.js +400 -0
- supython/admin/static/assets/SqlEditor-b8pTsILY.js +3 -0
- supython/admin/static/assets/SqlWorkspace-BUS7IntH.js +104 -0
- supython/admin/static/assets/TableData-CQIagLKn.js +2 -0
- supython/admin/static/assets/Tag-D1fOKpTH.js +72 -0
- supython/admin/static/assets/Templates-BS-ugkdq.js +2 -0
- supython/admin/static/assets/Thing-CEAniuMg.js +107 -0
- supython/admin/static/assets/Users-wzwajhlh.js +2 -0
- supython/admin/static/assets/_plugin-vue_export-helper-DGA9ry_j.js +1 -0
- supython/admin/static/assets/dist-VXIJLCYq.js +13 -0
- supython/admin/static/assets/format-length-CGCY1rMh.js +2 -0
- supython/admin/static/assets/get-Ca6unauB.js +2 -0
- supython/admin/static/assets/index-CeE6v959.js +951 -0
- supython/admin/static/assets/pinia-COXwfrOX.js +2 -0
- supython/admin/static/assets/resources-Bt6thQCD.js +44 -0
- supython/admin/static/assets/use-locale-mtgM0a3a.js +2 -0
- supython/admin/static/assets/use-merged-state-BvhkaHNX.js +2 -0
- supython/admin/static/assets/useConfirm-tMjvBFXR.js +2 -0
- supython/admin/static/assets/useResource-C_rJCY8C.js +2 -0
- supython/admin/static/assets/useTable-CnZc5zhi.js +363 -0
- supython/admin/static/assets/useTable-Dg0XlRlq.css +1 -0
- supython/admin/static/assets/useToast-DsZKx0IX.js +2 -0
- supython/admin/static/assets/utils-sbXoq7Ir.js +2 -0
- supython/admin/static/favicon.svg +1 -0
- supython/admin/static/icons.svg +24 -0
- supython/admin/static/index.html +24 -0
- supython/app.py +162 -0
- supython/auth/__init__.py +3 -0
- supython/auth/_email_job.py +11 -0
- supython/auth/providers/__init__.py +34 -0
- supython/auth/providers/github.py +22 -0
- supython/auth/providers/google.py +19 -0
- supython/auth/providers/oauth.py +56 -0
- supython/auth/providers/registry.py +16 -0
- supython/auth/ratelimit.py +39 -0
- supython/auth/router.py +282 -0
- supython/auth/schemas.py +79 -0
- supython/auth/service.py +587 -0
- supython/backups/__init__.py +24 -0
- supython/backups/_backup_job.py +170 -0
- supython/backups/schemas.py +18 -0
- supython/backups/service.py +217 -0
- supython/body_size.py +184 -0
- supython/cli.py +1663 -0
- supython/client/__init__.py +67 -0
- supython/client/_auth.py +249 -0
- supython/client/_client.py +145 -0
- supython/client/_config.py +92 -0
- supython/client/_functions.py +69 -0
- supython/client/_storage.py +255 -0
- supython/client/py.typed +0 -0
- supython/db.py +151 -0
- supython/db_admin.py +8 -0
- supython/extensions.py +36 -0
- supython/functions/__init__.py +19 -0
- supython/functions/context.py +262 -0
- supython/functions/loader.py +307 -0
- supython/functions/router.py +228 -0
- supython/functions/schemas.py +50 -0
- supython/gen/__init__.py +5 -0
- supython/gen/_introspect.py +137 -0
- supython/gen/types_py.py +270 -0
- supython/gen/types_ts.py +365 -0
- supython/health.py +229 -0
- supython/hooks.py +117 -0
- supython/jobs/__init__.py +31 -0
- supython/jobs/backends.py +97 -0
- supython/jobs/context.py +58 -0
- supython/jobs/cron.py +152 -0
- supython/jobs/cron_inproc.py +119 -0
- supython/jobs/decorators.py +76 -0
- supython/jobs/registry.py +79 -0
- supython/jobs/router.py +136 -0
- supython/jobs/schemas.py +92 -0
- supython/jobs/service.py +311 -0
- supython/jobs/worker.py +219 -0
- supython/jwks.py +257 -0
- supython/keyset.py +279 -0
- supython/logging_config.py +291 -0
- supython/mail.py +33 -0
- supython/mailer.py +65 -0
- supython/migrate.py +81 -0
- supython/migrations/0001_extensions_and_roles.sql +46 -0
- supython/migrations/0002_auth_schema.sql +66 -0
- supython/migrations/0003_demo_todos.sql +42 -0
- supython/migrations/0004_auth_v0_2.sql +47 -0
- supython/migrations/0005_storage_schema.sql +117 -0
- supython/migrations/0006_realtime_schema.sql +206 -0
- supython/migrations/0007_jobs_schema.sql +254 -0
- supython/migrations/0008_jobs_last_error.sql +56 -0
- supython/migrations/0009_auth_rate_limits.sql +33 -0
- supython/migrations/0010_worker_heartbeat.sql +14 -0
- supython/migrations/0011_admin_schema.sql +45 -0
- supython/migrations/0012_auth_banned_until.sql +10 -0
- supython/migrations/0013_email_templates.sql +19 -0
- supython/migrations/0014_realtime_payload_warning.sql +96 -0
- supython/migrations/0015_backups_schema.sql +14 -0
- supython/passwords.py +15 -0
- supython/realtime/__init__.py +6 -0
- supython/realtime/broker.py +814 -0
- supython/realtime/protocol.py +234 -0
- supython/realtime/router.py +184 -0
- supython/realtime/schemas.py +207 -0
- supython/realtime/service.py +261 -0
- supython/realtime/topics.py +175 -0
- supython/realtime/websocket.py +586 -0
- supython/scaffold/__init__.py +5 -0
- supython/scaffold/init_project.py +144 -0
- supython/scaffold/templates/Caddyfile.tmpl +4 -0
- supython/scaffold/templates/README.md.tmpl +22 -0
- supython/scaffold/templates/apps_hooks.py.tmpl +11 -0
- supython/scaffold/templates/apps_jobs.py.tmpl +8 -0
- supython/scaffold/templates/asgi.py.tmpl +14 -0
- supython/scaffold/templates/docker-compose.prod.yml.tmpl +84 -0
- supython/scaffold/templates/docker-compose.yml.tmpl +45 -0
- supython/scaffold/templates/docker_postgres_Dockerfile.tmpl +9 -0
- supython/scaffold/templates/docker_postgres_postgresql.conf.tmpl +3 -0
- supython/scaffold/templates/env.example.tmpl +168 -0
- supython/scaffold/templates/functions_README.md.tmpl +21 -0
- supython/scaffold/templates/gitignore.tmpl +14 -0
- supython/scaffold/templates/manage.py.tmpl +11 -0
- supython/scaffold/templates/migrations/.gitkeep +0 -0
- supython/scaffold/templates/package_init.py.tmpl +1 -0
- supython/scaffold/templates/settings.py.tmpl +31 -0
- supython/secretset.py +347 -0
- supython/security_headers.py +78 -0
- supython/settings.py +244 -0
- supython/settings_module.py +117 -0
- supython/storage/__init__.py +5 -0
- supython/storage/backends.py +392 -0
- supython/storage/router.py +341 -0
- supython/storage/schemas.py +50 -0
- supython/storage/service.py +445 -0
- supython/storage/signing.py +119 -0
- supython/tokens.py +85 -0
- supython-0.1.0.dist-info/METADATA +756 -0
- supython-0.1.0.dist-info/RECORD +200 -0
- supython-0.1.0.dist-info/WHEEL +4 -0
- supython-0.1.0.dist-info/entry_points.txt +2 -0
- supython-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Literal
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, EmailStr, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LoginRequest(BaseModel):
|
|
9
|
+
email: EmailStr
|
|
10
|
+
password: str
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SessionResponse(BaseModel):
|
|
14
|
+
admin_id: UUID
|
|
15
|
+
email: str
|
|
16
|
+
expires_at: datetime
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SchemaInfo(BaseModel):
|
|
20
|
+
name: str
|
|
21
|
+
owner: str
|
|
22
|
+
is_user: bool
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TableInfo(BaseModel):
|
|
26
|
+
name: str
|
|
27
|
+
rls_enabled: bool
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RowsPage(BaseModel):
|
|
31
|
+
columns: list[str]
|
|
32
|
+
rows: list[list[Any]]
|
|
33
|
+
total: int
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SqlExecRequest(BaseModel):
|
|
37
|
+
statement: str
|
|
38
|
+
read_only: bool = True
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SqlExecResponse(BaseModel):
|
|
42
|
+
columns: list[str]
|
|
43
|
+
rows: list[list[Any]]
|
|
44
|
+
row_count: int
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class DryRunRequest(BaseModel):
|
|
48
|
+
ddl: str
|
|
49
|
+
sample_query: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class DryRunResponse(BaseModel):
|
|
53
|
+
columns: list[str]
|
|
54
|
+
rows: list[list[Any]]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class RlsPolicy(BaseModel):
|
|
58
|
+
schemaname: str
|
|
59
|
+
tablename: str
|
|
60
|
+
policyname: str
|
|
61
|
+
permissive: str | None = None
|
|
62
|
+
roles: list[str] | None = None
|
|
63
|
+
cmd: str | None = None
|
|
64
|
+
qual: str | None = None
|
|
65
|
+
with_check: str | None = None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class MigrationRecord(BaseModel):
|
|
69
|
+
version: str
|
|
70
|
+
applied_at: datetime | None = None
|
|
71
|
+
source: str
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class SystemStatus(BaseModel):
|
|
75
|
+
pool_size: int
|
|
76
|
+
jwks_kid: str
|
|
77
|
+
broker: bool
|
|
78
|
+
jobs: bool
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class SystemVersion(BaseModel):
|
|
82
|
+
version: str
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class AdminUser(BaseModel):
|
|
86
|
+
id: UUID
|
|
87
|
+
email: str
|
|
88
|
+
created_at: datetime
|
|
89
|
+
last_sign_in_at: datetime | None = None
|
|
90
|
+
banned_until: datetime | None = None
|
|
91
|
+
email_confirmed_at: datetime | None = None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class AdminUsersPage(BaseModel):
|
|
95
|
+
rows: list[AdminUser]
|
|
96
|
+
total: int
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Identity(BaseModel):
|
|
100
|
+
id: UUID
|
|
101
|
+
user_id: UUID
|
|
102
|
+
provider: str
|
|
103
|
+
provider_user_id: str
|
|
104
|
+
identity_data: dict[str, Any]
|
|
105
|
+
created_at: datetime
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class AuditEvent(BaseModel):
|
|
109
|
+
id: UUID
|
|
110
|
+
user_id: UUID | None = None
|
|
111
|
+
event: str
|
|
112
|
+
ip: str | None = None
|
|
113
|
+
ua: str | None = None
|
|
114
|
+
payload: dict[str, Any]
|
|
115
|
+
created_at: datetime
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class AdminUserDetail(BaseModel):
|
|
119
|
+
user: AdminUser
|
|
120
|
+
identities: list[Identity]
|
|
121
|
+
recent_audit: list[AuditEvent]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class BanRequest(BaseModel):
|
|
125
|
+
duration_seconds: int | None = None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class RefreshToken(BaseModel):
|
|
129
|
+
id: int
|
|
130
|
+
user_id: UUID
|
|
131
|
+
token: str
|
|
132
|
+
parent: str | None = None
|
|
133
|
+
revoked: bool
|
|
134
|
+
created_at: datetime
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class RefreshTokensPage(BaseModel):
|
|
138
|
+
rows: list[RefreshToken]
|
|
139
|
+
total: int
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class AdminAuditPage(BaseModel):
|
|
143
|
+
rows: list[AuditEvent]
|
|
144
|
+
total: int
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class EmailTemplate(BaseModel):
|
|
148
|
+
name: str
|
|
149
|
+
subject: str
|
|
150
|
+
text_body: str
|
|
151
|
+
updated_at: datetime
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class EmailTemplateUpdate(BaseModel):
|
|
155
|
+
subject: str | None = None
|
|
156
|
+
text_body: str | None = None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class AdminBucket(BaseModel):
|
|
160
|
+
id: UUID
|
|
161
|
+
name: str
|
|
162
|
+
owner: UUID | None = None
|
|
163
|
+
public: bool
|
|
164
|
+
object_count: int
|
|
165
|
+
total_size: int
|
|
166
|
+
file_size_limit: int | None = None
|
|
167
|
+
allowed_mime_types: list[str] | None = None
|
|
168
|
+
created_at: datetime
|
|
169
|
+
updated_at: datetime
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class AdminObject(BaseModel):
|
|
173
|
+
id: UUID
|
|
174
|
+
bucket: str
|
|
175
|
+
name: str
|
|
176
|
+
owner: UUID
|
|
177
|
+
size: int
|
|
178
|
+
mime_type: str | None = None
|
|
179
|
+
etag: str | None = None
|
|
180
|
+
created_at: datetime
|
|
181
|
+
updated_at: datetime
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class AdminObjectsPage(BaseModel):
|
|
185
|
+
rows: list[AdminObject]
|
|
186
|
+
total: int
|
|
187
|
+
prefix: str | None = None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class AdminSignObjectRequest(BaseModel):
|
|
191
|
+
expires_in: int | None = Field(default=None, ge=1)
|
|
192
|
+
role: Literal["service_role", "authenticated", "anon"] = "service_role"
|
|
193
|
+
impersonate_sub: UUID | None = None
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class AdminSignedUrlResponse(BaseModel):
|
|
197
|
+
signed_url: str
|
|
198
|
+
token: str
|
|
199
|
+
expires_at: datetime
|
|
200
|
+
expires_in: int
|
|
201
|
+
signed_under_role: str
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class FunctionRoute(BaseModel):
|
|
205
|
+
name: str
|
|
206
|
+
path: str
|
|
207
|
+
methods: list[str]
|
|
208
|
+
auth: Literal["authenticated", "anon"]
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class FunctionSourceResponse(BaseModel):
|
|
212
|
+
name: str
|
|
213
|
+
path: str
|
|
214
|
+
source: str
|
|
215
|
+
size: int
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class FunctionInvokeRequest(BaseModel):
|
|
219
|
+
method: str = "POST"
|
|
220
|
+
headers: dict[str, str] = Field(default_factory=dict)
|
|
221
|
+
body: Any | None = None
|
|
222
|
+
query: str | None = None
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class FunctionInvokeResponse(BaseModel):
|
|
226
|
+
status: int
|
|
227
|
+
headers: dict[str, str]
|
|
228
|
+
body: Any | None = None
|
|
229
|
+
body_text: str
|
|
230
|
+
elapsed_ms: float
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class AdminBroadcastRequest(BaseModel):
|
|
234
|
+
"""Body for POST /admin/api/v1/realtime/broadcast."""
|
|
235
|
+
|
|
236
|
+
topic: str = Field(min_length=1)
|
|
237
|
+
event: str = Field(min_length=1, max_length=255)
|
|
238
|
+
payload: dict[str, Any] = Field(default_factory=dict)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class AdminJobRow(BaseModel):
|
|
242
|
+
id: UUID
|
|
243
|
+
name: str
|
|
244
|
+
version: int = 1
|
|
245
|
+
status: str
|
|
246
|
+
payload: dict[str, Any] | None = None
|
|
247
|
+
queue: str = "default"
|
|
248
|
+
user_id: UUID | None = None
|
|
249
|
+
attempts: int = 0
|
|
250
|
+
max_attempts: int = 3
|
|
251
|
+
run_at: datetime | None = None
|
|
252
|
+
locked_at: datetime | None = None
|
|
253
|
+
locked_by: str | None = None
|
|
254
|
+
role: str = "service_role"
|
|
255
|
+
finished_at: datetime | None = None
|
|
256
|
+
created_at: datetime | None = None
|
|
257
|
+
last_error: str | None = None
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class AdminJobsPage(BaseModel):
|
|
261
|
+
rows: list[AdminJobRow]
|
|
262
|
+
total: int
|
|
263
|
+
counts: dict[str, int] = {}
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class AdminCronRow(BaseModel):
|
|
267
|
+
id: UUID
|
|
268
|
+
name: str
|
|
269
|
+
cron_expr: str
|
|
270
|
+
job_name: str
|
|
271
|
+
job_version: int = 1
|
|
272
|
+
payload: dict[str, Any] | None = None
|
|
273
|
+
queue: str = "default"
|
|
274
|
+
enabled: bool = True
|
|
275
|
+
last_fire_at: datetime | None = None
|
|
276
|
+
created_at: datetime | None = None
|
|
277
|
+
pg_cron_active: bool | None = None
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class PgCronHealth(BaseModel):
|
|
281
|
+
installed: bool
|
|
282
|
+
active_jobs: int = 0
|
|
283
|
+
extension_version: str | None = None
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class AdminBackupRow(BaseModel):
|
|
287
|
+
id: UUID
|
|
288
|
+
kind: str
|
|
289
|
+
status: str
|
|
290
|
+
size: int | None = None
|
|
291
|
+
file_path: str | None = None
|
|
292
|
+
error_message: str | None = None
|
|
293
|
+
started_at: datetime
|
|
294
|
+
finished_at: datetime | None = None
|
|
295
|
+
created_at: datetime
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class AdminBackupsPage(BaseModel):
|
|
299
|
+
rows: list[AdminBackupRow]
|
|
300
|
+
total: int
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class StartBackupRequest(BaseModel):
|
|
304
|
+
kind: Literal["full", "schema-only"] = "full"
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class BackupDownloadResponse(BaseModel):
|
|
308
|
+
download_url: str
|
|
309
|
+
expires_in: int
|
|
310
|
+
backup_id: UUID
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import secrets
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
import asyncpg
|
|
7
|
+
|
|
8
|
+
SESSION_COOKIE = "supython_admin"
|
|
9
|
+
SESSION_PATH = "/admin"
|
|
10
|
+
SESSION_TTL = timedelta(hours=8)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _hash(token: str) -> bytes:
|
|
14
|
+
return hashlib.sha256(token.encode("utf-8")).digest()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def issue(
|
|
18
|
+
conn: asyncpg.Connection, *, admin_id: UUID, ip: str | None, ua: str | None
|
|
19
|
+
) -> tuple[str, datetime]:
|
|
20
|
+
raw = secrets.token_urlsafe(32)
|
|
21
|
+
expires = datetime.now(timezone.utc) + SESSION_TTL
|
|
22
|
+
await conn.execute(
|
|
23
|
+
"""
|
|
24
|
+
insert into admin.admin_sessions (admin_id, token_hash, expires_at, ip, user_agent)
|
|
25
|
+
values ($1, $2, $3, $4, $5)
|
|
26
|
+
""",
|
|
27
|
+
admin_id, _hash(raw), expires, ip, ua,
|
|
28
|
+
)
|
|
29
|
+
return raw, expires
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async def resolve(
|
|
33
|
+
conn: asyncpg.Connection, raw: str
|
|
34
|
+
) -> tuple[UUID, datetime] | None:
|
|
35
|
+
row = await conn.fetchrow(
|
|
36
|
+
"""
|
|
37
|
+
select admin_id, expires_at
|
|
38
|
+
from admin.admin_sessions
|
|
39
|
+
where token_hash = $1
|
|
40
|
+
and revoked_at is null
|
|
41
|
+
and expires_at > now()
|
|
42
|
+
""",
|
|
43
|
+
_hash(raw),
|
|
44
|
+
)
|
|
45
|
+
return (row["admin_id"], row["expires_at"]) if row else None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def revoke(conn: asyncpg.Connection, raw: str) -> None:
|
|
49
|
+
await conn.execute(
|
|
50
|
+
"update admin.admin_sessions set revoked_at = now() where token_hash = $1",
|
|
51
|
+
_hash(raw),
|
|
52
|
+
)
|
supython/admin/spa.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from importlib.resources import files
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from fastapi import FastAPI, HTTPException, status
|
|
6
|
+
from fastapi.responses import FileResponse
|
|
7
|
+
from fastapi.staticfiles import StaticFiles
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def mount(app: FastAPI) -> None:
|
|
13
|
+
static_dir = Path(str(files("supython.admin").joinpath("static")))
|
|
14
|
+
assets_path = static_dir / "assets"
|
|
15
|
+
index = static_dir / "index.html"
|
|
16
|
+
|
|
17
|
+
if assets_path.exists():
|
|
18
|
+
app.mount(
|
|
19
|
+
"/admin/assets",
|
|
20
|
+
StaticFiles(directory=assets_path),
|
|
21
|
+
name="admin-assets",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
@app.get("/admin", include_in_schema=False)
|
|
25
|
+
@app.get("/admin/{full_path:path}", include_in_schema=False)
|
|
26
|
+
async def spa_fallback(full_path: str = "") -> FileResponse:
|
|
27
|
+
if not index.exists():
|
|
28
|
+
raise HTTPException(
|
|
29
|
+
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
30
|
+
detail="Admin SPA bundle not built. Run `npm run build` in admin-ui/.",
|
|
31
|
+
)
|
|
32
|
+
return FileResponse(index)
|
|
33
|
+
|
|
34
|
+
if not index.exists():
|
|
35
|
+
logger.warning(
|
|
36
|
+
"Admin SPA index.html not found at %s — /admin will return 503 until the bundle is built.",
|
|
37
|
+
index,
|
|
38
|
+
)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import{Bt as e,E as t,Ft as n,Gt as r,It as i,Jt as a,Kt as o,O as s,On as c,S as l,Sn as u,Yt as d,Zt as f,_ as p,_t as m,ht as h,j as g,lt as _,mn as v,tr as y,ut as b,wn as x,x as S}from"./Space-n5-XcguU.js";import{F as C,I as w,L as T,M as E,N as D,P as O}from"./index-CeE6v959.js";function k(e){let{lineHeight:t,borderRadius:r,fontWeightStrong:a,baseColor:o,dividerColor:s,actionColor:c,textColor1:l,textColor2:u,closeColorHover:d,closeColorPressed:f,closeIconColor:p,closeIconColorHover:m,closeIconColorPressed:h,infoColor:g,successColor:_,warningColor:v,errorColor:y,fontSize:b}=e;return Object.assign(Object.assign({},D),{fontSize:b,lineHeight:t,titleFontWeight:a,borderRadius:r,border:`1px solid ${s}`,color:c,titleTextColor:l,iconColor:u,contentTextColor:u,closeBorderRadius:r,closeColorHover:d,closeColorPressed:f,closeIconColor:p,closeIconColorHover:m,closeIconColorPressed:h,borderInfo:`1px solid ${i(o,n(g,{alpha:.25}))}`,colorInfo:i(o,n(g,{alpha:.08})),titleTextColorInfo:l,iconColorInfo:g,contentTextColorInfo:u,closeColorHoverInfo:d,closeColorPressedInfo:f,closeIconColorInfo:p,closeIconColorHoverInfo:m,closeIconColorPressedInfo:h,borderSuccess:`1px solid ${i(o,n(_,{alpha:.25}))}`,colorSuccess:i(o,n(_,{alpha:.08})),titleTextColorSuccess:l,iconColorSuccess:_,contentTextColorSuccess:u,closeColorHoverSuccess:d,closeColorPressedSuccess:f,closeIconColorSuccess:p,closeIconColorHoverSuccess:m,closeIconColorPressedSuccess:h,borderWarning:`1px solid ${i(o,n(v,{alpha:.33}))}`,colorWarning:i(o,n(v,{alpha:.08})),titleTextColorWarning:l,iconColorWarning:v,contentTextColorWarning:u,closeColorHoverWarning:d,closeColorPressedWarning:f,closeIconColorWarning:p,closeIconColorHoverWarning:m,closeIconColorPressedWarning:h,borderError:`1px solid ${i(o,n(y,{alpha:.25}))}`,colorError:i(o,n(y,{alpha:.08})),titleTextColorError:l,iconColorError:y,contentTextColorError:u,closeColorHoverError:d,closeColorPressedError:f,closeIconColorError:p,closeIconColorHoverError:m,closeIconColorPressedError:h})}var A={name:`Alert`,common:p,self:k},j=o(`alert`,`
|
|
2
|
+
line-height: var(--n-line-height);
|
|
3
|
+
border-radius: var(--n-border-radius);
|
|
4
|
+
position: relative;
|
|
5
|
+
transition: background-color .3s var(--n-bezier);
|
|
6
|
+
background-color: var(--n-color);
|
|
7
|
+
text-align: start;
|
|
8
|
+
word-break: break-word;
|
|
9
|
+
`,[a(`border`,`
|
|
10
|
+
border-radius: inherit;
|
|
11
|
+
position: absolute;
|
|
12
|
+
left: 0;
|
|
13
|
+
right: 0;
|
|
14
|
+
top: 0;
|
|
15
|
+
bottom: 0;
|
|
16
|
+
transition: border-color .3s var(--n-bezier);
|
|
17
|
+
border: var(--n-border);
|
|
18
|
+
pointer-events: none;
|
|
19
|
+
`),d(`closable`,[o(`alert-body`,[a(`title`,`
|
|
20
|
+
padding-right: 24px;
|
|
21
|
+
`)])]),a(`icon`,{color:`var(--n-icon-color)`}),o(`alert-body`,{padding:`var(--n-padding)`},[a(`title`,{color:`var(--n-title-text-color)`}),a(`content`,{color:`var(--n-content-text-color)`})]),E({originalTransition:`transform .3s var(--n-bezier)`,enterToProps:{transform:`scale(1)`},leaveToProps:{transform:`scale(0.9)`}}),a(`icon`,`
|
|
22
|
+
position: absolute;
|
|
23
|
+
left: 0;
|
|
24
|
+
top: 0;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
display: flex;
|
|
28
|
+
width: var(--n-icon-size);
|
|
29
|
+
height: var(--n-icon-size);
|
|
30
|
+
font-size: var(--n-icon-size);
|
|
31
|
+
margin: var(--n-icon-margin);
|
|
32
|
+
`),a(`close`,`
|
|
33
|
+
transition:
|
|
34
|
+
color .3s var(--n-bezier),
|
|
35
|
+
background-color .3s var(--n-bezier);
|
|
36
|
+
position: absolute;
|
|
37
|
+
right: 0;
|
|
38
|
+
top: 0;
|
|
39
|
+
margin: var(--n-close-margin);
|
|
40
|
+
`),d(`show-icon`,[o(`alert-body`,{paddingLeft:`calc(var(--n-icon-margin-left) + var(--n-icon-size) + var(--n-icon-margin-right))`})]),d(`right-adjust`,[o(`alert-body`,{paddingRight:`calc(var(--n-close-size) + var(--n-padding) + 2px)`})]),o(`alert-body`,`
|
|
41
|
+
border-radius: var(--n-border-radius);
|
|
42
|
+
transition: border-color .3s var(--n-bezier);
|
|
43
|
+
`,[a(`title`,`
|
|
44
|
+
transition: color .3s var(--n-bezier);
|
|
45
|
+
font-size: 16px;
|
|
46
|
+
line-height: 19px;
|
|
47
|
+
font-weight: var(--n-title-font-weight);
|
|
48
|
+
`,[r(`& +`,[a(`content`,{marginTop:`9px`})])]),a(`content`,{transition:`color .3s var(--n-bezier)`,fontSize:`var(--n-font-size)`})]),a(`icon`,{transition:`color .3s var(--n-bezier)`})]),M=u({name:`Alert`,inheritAttrs:!1,props:Object.assign(Object.assign({},s.props),{title:String,showIcon:{type:Boolean,default:!0},type:{type:String,default:`default`},bordered:{type:Boolean,default:!0},closable:Boolean,onClose:Function,onAfterLeave:Function,onAfterHide:Function}),slots:Object,setup(t){let{mergedClsPrefixRef:n,mergedBorderedRef:r,inlineThemeDisabled:i,mergedRtlRef:a}=b(t),o=s(`Alert`,`-alert`,j,A,t,n),c=g(`Alert`,a,n),l=v(()=>{let{common:{cubicBezierEaseInOut:n},self:r}=o.value,{fontSize:i,borderRadius:a,titleFontWeight:s,lineHeight:c,iconSize:l,iconMargin:u,iconMarginRtl:d,closeIconSize:p,closeBorderRadius:m,closeSize:h,closeMargin:g,closeMarginRtl:_,padding:v}=r,{type:y}=t,{left:b,right:x}=e(u);return{"--n-bezier":n,"--n-color":r[f(`color`,y)],"--n-close-icon-size":p,"--n-close-border-radius":m,"--n-close-color-hover":r[f(`closeColorHover`,y)],"--n-close-color-pressed":r[f(`closeColorPressed`,y)],"--n-close-icon-color":r[f(`closeIconColor`,y)],"--n-close-icon-color-hover":r[f(`closeIconColorHover`,y)],"--n-close-icon-color-pressed":r[f(`closeIconColorPressed`,y)],"--n-icon-color":r[f(`iconColor`,y)],"--n-border":r[f(`border`,y)],"--n-title-text-color":r[f(`titleTextColor`,y)],"--n-content-text-color":r[f(`contentTextColor`,y)],"--n-line-height":c,"--n-border-radius":a,"--n-font-size":i,"--n-title-font-weight":s,"--n-icon-size":l,"--n-icon-margin":u,"--n-icon-margin-rtl":d,"--n-close-size":h,"--n-close-margin":g,"--n-close-margin-rtl":_,"--n-padding":v,"--n-icon-margin-left":b,"--n-icon-margin-right":x}}),u=i?_(`alert`,v(()=>t.type[0]),l,t):void 0,d=y(!0),p=()=>{let{onAfterLeave:e,onAfterHide:n}=t;e&&e(),n&&n()};return{rtlEnabled:c,mergedClsPrefix:n,mergedBordered:r,visible:d,handleCloseClick:()=>{Promise.resolve(t.onClose?.call(t)).then(e=>{e!==!1&&(d.value=!1)})},handleAfterLeave:()=>{p()},mergedTheme:o,cssVars:i?void 0:l,themeClass:u?.themeClass,onRender:u?.onRender}},render(){var e;return(e=this.onRender)==null||e.call(this),x(S,{onAfterLeave:this.handleAfterLeave},{default:()=>{let{mergedClsPrefix:e,$slots:n}=this,r={class:[`${e}-alert`,this.themeClass,this.closable&&`${e}-alert--closable`,this.showIcon&&`${e}-alert--show-icon`,!this.title&&this.closable&&`${e}-alert--right-adjust`,this.rtlEnabled&&`${e}-alert--rtl`],style:this.cssVars,role:`alert`};return this.visible?x(`div`,Object.assign({},c(this.$attrs,r)),this.closable&&x(l,{clsPrefix:e,class:`${e}-alert__close`,onClick:this.handleCloseClick}),this.bordered&&x(`div`,{class:`${e}-alert__border`}),this.showIcon&&x(`div`,{class:`${e}-alert__icon`,"aria-hidden":`true`},h(n.icon,()=>[x(t,{clsPrefix:e},{default:()=>{switch(this.type){case`success`:return x(C,null);case`info`:return x(w,null);case`warning`:return x(O,null);case`error`:return x(T,null);default:return null}}})])),x(`div`,{class:[`${e}-alert-body`,this.mergedBordered&&`${e}-alert-body--bordered`]},m(n.header,t=>{let n=t||this.title;return n?x(`div`,{class:`${e}-alert-body__title`},n):null}),n.default&&x(`div`,{class:`${e}-alert-body__content`},n))):null}})}});export{M as t};
|
|
49
|
+
//# sourceMappingURL=Alert-dluGVkos.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Gn as e,In as t,Sn as n,bn as r,gn as i,mn as a,r as o,sr as s,t as c,tr as l,un as u,ur as d,vn as f,wn as p,xn as m}from"./Space-n5-XcguU.js";import{t as h}from"./Tag-D1fOKpTH.js";import{n as g,t as _}from"./DataTable-COAAWEft.js";import{n as v,t as y}from"./DescriptionsItem-P8JUDaBs.js";import{n as b,t as x}from"./useTable-CnZc5zhi.js";import{n as S,t as C}from"./DrawerContent-TpYTFgF1.js";import{t as w}from"./resources-Bt6thQCD.js";import{c as T}from"./index-CeE6v959.js";import{t as E}from"./JsonField-DibyJgun.js";var D=n({__name:`Audit`,setup(n){let D=[{type:`text`,key:`event`,label:`Event`,placeholder:`e.g. login, signup`,debounceMs:300,width:200},{type:`text`,key:`ip`,label:`IP`,placeholder:`e.g. 192.168`,debounceMs:300,width:160},{type:`date`,key:`from`,label:`From`,width:160},{type:`date`,key:`to`,label:`To`,width:160}],{q:O,data:k,loading:A,error:j,refresh:M}=x(e=>w.audit({event:e.filters.event||void 0,ip:e.filters.ip||void 0,from_date:e.filters.from||void 0,to_date:e.filters.to||void 0,limit:e.limit,offset:e.offset}),{event:null,ip:null,from:null,to:null}),N=a(()=>k.value?.rows??[]),P=a(()=>k.value?.total??0),F=[{title:`Time`,key:`created_at`,width:170,render:e=>new Date(e.created_at).toLocaleString()},{title:`Actor`,key:`user_id`,width:320,render:e=>e.user_id?e.user_id:`—`,ellipsis:{tooltip:!0}},{title:`Event`,key:`event`,width:160,render:e=>p(h,{type:`info`,size:`small`},{default:()=>e.event})},{title:`IP`,key:`ip`,width:130,render:e=>e.ip??`—`},{title:`UA`,key:`ua`,width:200,ellipsis:{tooltip:!0},render:e=>e.ua?e.ua.slice(0,40)+(e.ua.length>40?`…`:``):`—`}],I=l(!1),L=l(null);function R(e){L.value=e,I.value=!0}function z(){I.value=!1,L.value=null}return(n,a)=>(t(),i(s(o),{title:`Audit Log`,size:`small`},{default:e(()=>[m(s(c),{vertical:``,size:16},{default:e(()=>[m(b,{q:s(O),rows:N.value,total:P.value,loading:s(A),error:s(j),columns:F,filters:D,"search-placeholder":`Filter rows…`,onRefresh:s(M)},{default:e(()=>[m(s(_),{columns:F,data:N.value,bordered:!1,"row-props":e=>({style:`cursor: pointer`,onClick:()=>R(e)})},null,8,[`data`,`row-props`]),m(s(g),{page:Math.floor(s(O).offset/s(O).limit)+1,"page-count":Math.max(1,Math.ceil(P.value/s(O).limit)),style:{"margin-top":`12px`},"onUpdate:page":a[0]||=e=>s(O).offset=(e-1)*s(O).limit},null,8,[`page`,`page-count`])]),_:1},8,[`q`,`rows`,`total`,`loading`,`error`,`onRefresh`])]),_:1}),m(s(S),{show:I.value,width:520,placement:`right`,"mask-closable":!0,"onUpdate:show":a[1]||=e=>{e||z()}},{default:e(()=>[m(s(C),{title:L.value?`Event: ${L.value.event}`:`Event detail`,closable:``,onClose:z},{default:e(()=>[L.value?(t(),f(u,{key:0},[m(s(v),{bordered:``,"label-placement":`top`,column:1,size:`small`,style:{"margin-bottom":`16px`}},{default:e(()=>[m(s(y),{label:`ID`},{default:e(()=>[m(s(T),{code:``},{default:e(()=>[r(d(L.value.id),1)]),_:1})]),_:1}),m(s(y),{label:`Event`},{default:e(()=>[r(d(L.value.event),1)]),_:1}),m(s(y),{label:`Actor (user_id)`},{default:e(()=>[r(d(L.value.user_id??`—`),1)]),_:1}),m(s(y),{label:`Time`},{default:e(()=>[r(d(new Date(L.value.created_at).toLocaleString()),1)]),_:1}),m(s(y),{label:`IP`},{default:e(()=>[r(d(L.value.ip??`—`),1)]),_:1}),m(s(y),{label:`User-Agent`},{default:e(()=>[r(d(L.value.ua??`—`),1)]),_:1})]),_:1}),m(s(T),{strong:``,style:{display:`block`,"margin-bottom":`8px`}},{default:e(()=>[...a[2]||=[r(` Payload `,-1)]]),_:1}),m(E,{value:L.value.payload},null,8,[`value`])],64)):(t(),i(s(T),{key:1,depth:`3`},{default:e(()=>[...a[3]||=[r(`Click a row to see full event details.`,-1)]]),_:1}))]),_:1},8,[`title`])]),_:1},8,[`show`])]),_:1}))}});export{D as default};
|
|
2
|
+
//# sourceMappingURL=Audit-Njung3HI.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Fn as e,Gn as t,In as n,Sn as r,Un as i,_n as a,bn as o,c as s,gn as c,mn as l,r as u,sr as d,t as f,tr as p,un as m,ur as h,vn as g,wn as _,xn as v}from"./Space-n5-XcguU.js";import{t as y}from"./Tag-D1fOKpTH.js";import{n as b,t as x}from"./DataTable-COAAWEft.js";import{n as S,t as C}from"./DescriptionsItem-P8JUDaBs.js";import{n as w,t as T}from"./useTable-CnZc5zhi.js";import{n as E,t as D}from"./DrawerContent-TpYTFgF1.js";import{a as O}from"./resources-Bt6thQCD.js";import{c as k,y as A}from"./index-CeE6v959.js";import{t as j}from"./useToast-DsZKx0IX.js";import{t as M}from"./useConfirm-tMjvBFXR.js";var N=3e3,P=r({__name:`Backups`,setup(r){let P=j(),F=M(),I={running:`info`,completed:`success`,failed:`error`,pending:`warning`};function L(e){return e?new Date(e).toLocaleString():`—`}function R(e){if(e==null)return`—`;if(e===0)return`0 B`;let t=[`B`,`KB`,`MB`,`GB`],n=Math.floor(Math.log10(e)/3),r=t[Math.min(n,t.length-1)];return`${(e/1e3**Math.min(n,t.length-1)).toFixed(2)} ${r}`}let{q:z,data:B,loading:V,error:H,refresh:U}=T(e=>O.backups({limit:e.limit,offset:e.offset}),{}),W=l(()=>B.value?.rows??[]),G=l(()=>B.value?.total??0),K=[{title:`Kind`,key:`kind`,width:120,render:e=>_(y,{type:e.kind===`full`?`primary`:`default`,size:`small`},{default:()=>e.kind})},{title:`Status`,key:`status`,width:120,render:e=>_(y,{type:I[e.status]??`default`,size:`small`},{default:()=>e.status})},{title:`Size`,key:`size`,width:110,render:e=>R(e.size)},{title:`Started`,key:`started_at`,width:160,render:e=>L(e.started_at)},{title:`Finished`,key:`finished_at`,width:160,render:e=>L(e.finished_at)},{title:``,key:`actions`,width:110,render:e=>e.status!==`completed`||!e.file_path?null:_(s,{size:`tiny`,type:`primary`,secondary:!0,onClick:t=>{t.stopPropagation(),Q(e)}},{default:()=>`Download`})}],q=p(!1),J=p(null);function Y(e){J.value=e,q.value=!0}function X(){q.value=!1,J.value=null}async function Z(e){let t=e===`full`?`Full backup`:`Schema-only backup`;if(await F(`Start ${t.toLowerCase()}?`,`The backup will run in the background. You can monitor its status in the list.`))try{await O.startBackup(e),P.success(`${t} started.`),await U()}catch(e){P.error(e.message??`Start backup failed`)}}async function Q(e){try{let t=await O.downloadUrl(e.id);window.open(t.download_url,`_blank`)}catch(e){P.error(e.message??`Download failed`)}}let ee=l(()=>W.value.some(e=>e.status===`running`)),$=null;async function te(){try{B.value=await O.backups({limit:z.limit,offset:z.offset})}catch{}}return i(ee,e=>{e&&$===null?$=setInterval(()=>{te()},N):!e&&$!==null&&(clearInterval($),$=null)},{immediate:!0}),i(W,e=>{if(!J.value)return;let t=e.find(e=>e.id===J.value.id);t&&(J.value=t)}),e(()=>{$!==null&&(clearInterval($),$=null)}),(e,r)=>(n(),c(d(u),{title:`Backups`,size:`small`},{default:t(()=>[v(d(f),{style:{"margin-bottom":`16px`}},{default:t(()=>[v(d(s),{type:`primary`,size:`small`,onClick:r[0]||=e=>Z(`full`)},{default:t(()=>[...r[5]||=[o(` Start Full Backup `,-1)]]),_:1}),v(d(s),{size:`small`,onClick:r[1]||=e=>Z(`schema-only`)},{default:t(()=>[...r[6]||=[o(` Start Schema-only Backup `,-1)]]),_:1})]),_:1}),v(w,{q:d(z),rows:W.value,total:G.value,loading:d(V),error:d(H),columns:K,onRefresh:d(U)},{default:t(()=>[v(d(x),{columns:K,data:W.value,bordered:!1,"row-props":e=>({style:`cursor: pointer`,onClick:()=>Y(e)})},null,8,[`data`,`row-props`]),v(d(b),{page:Math.floor(d(z).offset/d(z).limit)+1,"page-count":Math.max(1,Math.ceil(G.value/d(z).limit)),style:{"margin-top":`12px`},"onUpdate:page":r[2]||=e=>d(z).offset=(e-1)*d(z).limit},null,8,[`page`,`page-count`])]),_:1},8,[`q`,`rows`,`total`,`loading`,`error`,`onRefresh`]),v(d(E),{show:q.value,width:520,placement:`right`,"mask-closable":!0,"onUpdate:show":r[4]||=e=>{e||X()}},{default:t(()=>[v(d(D),{title:`Backup detail`,closable:``,onClose:X},{default:t(()=>[J.value?(n(),g(m,{key:0},[v(d(f),{style:{"margin-bottom":`20px`}},{default:t(()=>[J.value.status===`completed`&&J.value.file_path?(n(),c(d(s),{key:0,type:`primary`,size:`small`,onClick:r[3]||=e=>Q(J.value)},{default:t(()=>[...r[7]||=[o(` Download `,-1)]]),_:1})):a(``,!0)]),_:1}),v(d(S),{bordered:``,"label-placement":`top`,column:1,size:`small`},{default:t(()=>[v(d(C),{label:`id`},{default:t(()=>[v(d(k),{code:``},{default:t(()=>[o(h(J.value.id),1)]),_:1})]),_:1}),v(d(C),{label:`kind`},{default:t(()=>[v(d(y),{type:J.value.kind===`full`?`primary`:`default`,size:`small`},{default:t(()=>[o(h(J.value.kind),1)]),_:1},8,[`type`])]),_:1}),v(d(C),{label:`status`},{default:t(()=>[v(d(y),{type:I[J.value.status]??`default`,size:`small`},{default:t(()=>[o(h(J.value.status),1)]),_:1},8,[`type`])]),_:1}),v(d(C),{label:`size`},{default:t(()=>[o(h(R(J.value.size)),1)]),_:1}),v(d(C),{label:`started_at`},{default:t(()=>[o(h(L(J.value.started_at)),1)]),_:1}),v(d(C),{label:`finished_at`},{default:t(()=>[o(h(L(J.value.finished_at)),1)]),_:1}),v(d(C),{label:`created_at`},{default:t(()=>[o(h(L(J.value.created_at)),1)]),_:1}),v(d(C),{label:`file_path`},{default:t(()=>[o(h(J.value.file_path??`—`),1)]),_:1})]),_:1}),J.value.error_message?(n(),g(m,{key:0},[v(d(A)),v(d(k),{strong:``,style:{display:`block`,"margin-bottom":`8px`}},{default:t(()=>[...r[8]||=[o(` Error `,-1)]]),_:1}),v(d(k),{type:`error`,style:{"white-space":`pre-wrap`,"font-size":`13px`}},{default:t(()=>[o(h(J.value.error_message),1)]),_:1})],64)):a(``,!0)],64)):(n(),c(d(k),{key:1,depth:`3`},{default:t(()=>[...r[9]||=[o(`Select a backup row to see details.`,-1)]]),_:1}))]),_:1})]),_:1},8,[`show`])]),_:1}))}});export{P as default};
|
|
2
|
+
//# sourceMappingURL=Backups-DzPlFgrm.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Gn as e,In as t,Rn as n,Sn as r,_n as i,bn as a,gn as o,hn as s,r as c,sr as l,un as u,ur as d,vn as f,xn as p}from"./Space-n5-XcguU.js";import{t as m}from"./Tag-D1fOKpTH.js";import{n as h,t as g}from"./Grid-hFkp9F4P.js";import{l as _,s as v}from"./resources-Bt6thQCD.js";import{c as y,s as b}from"./index-CeE6v959.js";import{t as x}from"./useResource-C_rJCY8C.js";import{n as S,t as C}from"./EmptyState-DeDck-OL.js";var w={style:{display:`flex`,"align-items":`center`,gap:`8px`}},T={style:{display:`grid`,"grid-template-columns":`1fr 1fr`,gap:`12px`}},E={style:{"margin-top":`12px`}},D={style:{"margin-top":`8px`}},O=r({__name:`Buckets`,setup(r){let O=b(),{data:k,loading:A,error:j,refresh:M}=x(()=>v.buckets());function N(e){if(e===0)return`0 B`;let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=Math.min(Math.floor(Math.log(e)/Math.log(1024)),t.length-1);return`${(e/1024**n).toFixed(n===0?0:1)} ${t[n]}`}function P(e){O.push(`/storage/${encodeURIComponent(e.name)}`)}function F(e,t){return e?`success`:t.object_count>0?`warning`:`default`}return(r,v)=>(t(),f(`div`,null,[v[3]||=s(`div`,{style:{display:`flex`,"align-items":`center`,"justify-content":`space-between`,"margin-bottom":`16px`}},[s(`h1`,{style:{margin:`0`,"font-size":`20px`,"font-weight":`600`}},` Storage Buckets `)],-1),p(S,{error:l(j),retry:l(M)},null,8,[`error`,`retry`]),p(l(_),{show:l(A)},{default:e(()=>[l(k)&&l(k).length?(t(),o(l(g),{key:0,cols:`1 s:2 m:3 l:4`,responsive:`screen`,"x-gap":16,"y-gap":16},{default:e(()=>[(t(!0),f(u,null,n(l(k),n=>(t(),o(l(h),{key:n.id},{default:e(()=>[p(l(c),{size:`small`,hoverable:``,segmented:{content:!0},onClick:e=>P(n)},{header:e(()=>[s(`div`,w,[p(l(m),{type:F(n.public,n),size:`small`,bordered:!1},{default:e(()=>[a(d(n.public?`Public`:`Private`),1)]),_:2},1032,[`type`]),p(l(y),{strong:``,style:{"font-size":`14px`,flex:`1`,"min-width":`0`,overflow:`hidden`,"text-overflow":`ellipsis`,"white-space":`nowrap`}},{default:e(()=>[a(d(n.name),1)]),_:2},1024)])]),default:e(()=>[s(`div`,T,[s(`div`,null,[p(l(y),{depth:`3`,style:{"font-size":`11px`,display:`block`,"margin-bottom":`2px`}},{default:e(()=>[...v[0]||=[a(` Objects `,-1)]]),_:1}),p(l(y),{strong:``,style:{"font-size":`20px`}},{default:e(()=>[a(d(n.object_count.toLocaleString()),1)]),_:2},1024)]),s(`div`,null,[p(l(y),{depth:`3`,style:{"font-size":`11px`,display:`block`,"margin-bottom":`2px`}},{default:e(()=>[...v[1]||=[a(` Total Size `,-1)]]),_:1}),p(l(y),{strong:``,style:{"font-size":`16px`}},{default:e(()=>[a(d(N(n.total_size)),1)]),_:2},1024)])]),s(`div`,E,[p(l(y),{depth:`3`,style:{"font-size":`11px`,display:`block`,"margin-bottom":`2px`}},{default:e(()=>[...v[2]||=[a(` Owner `,-1)]]),_:1}),p(l(y),{code:``,style:{"font-size":`12px`}},{default:e(()=>[a(d(n.owner?n.owner.slice(0,8)+`…`:`(none)`),1)]),_:2},1024)]),s(`div`,D,[p(l(y),{depth:`3`,style:{"font-size":`11px`}},{default:e(()=>[a(` Created `+d(new Date(n.created_at).toLocaleDateString()),1)]),_:2},1024)])]),_:2},1032,[`onClick`])]),_:2},1024))),128))]),_:1})):l(k)&&!l(k).length?(t(),o(C,{key:1,description:`No storage buckets found.`})):i(``,!0)]),_:1},8,[`show`])]))}});export{O as default};
|
|
2
|
+
//# sourceMappingURL=Buckets-ByacGkU1.js.map
|