quantum-framework 0.18.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.
Files changed (333) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/admin.py +131 -0
  4. quantum/cli/check.py +223 -0
  5. quantum/cli/commands/__init__.py +15 -0
  6. quantum/cli/commands/build.py +414 -0
  7. quantum/cli/commands/dev.py +185 -0
  8. quantum/cli/commands/docs.py +329 -0
  9. quantum/cli/commands/lint.py +523 -0
  10. quantum/cli/commands/migrate.py +548 -0
  11. quantum/cli/commands/new.py +622 -0
  12. quantum/cli/commands/serve.py +190 -0
  13. quantum/cli/commands/test.py +193 -0
  14. quantum/cli/deploy.py +810 -0
  15. quantum/cli/hot_reload.py +951 -0
  16. quantum/cli/jobs.py +356 -0
  17. quantum/cli/mq.py +582 -0
  18. quantum/cli/pkg.py +390 -0
  19. quantum/cli/runner.py +565 -0
  20. quantum/cli/server_process.py +159 -0
  21. quantum/cli/utils.py +334 -0
  22. quantum/compiler/__init__.py +30 -0
  23. quantum/compiler/base_generator.py +367 -0
  24. quantum/compiler/cli.py +295 -0
  25. quantum/compiler/expression_transformer.py +444 -0
  26. quantum/compiler/javascript/__init__.py +10 -0
  27. quantum/compiler/javascript/generator.py +659 -0
  28. quantum/compiler/optimizer.py +270 -0
  29. quantum/compiler/python/__init__.py +10 -0
  30. quantum/compiler/python/generator.py +883 -0
  31. quantum/compiler/python/runtime.py +863 -0
  32. quantum/compiler/transpiler.py +330 -0
  33. quantum/core/__init__.py +3 -0
  34. quantum/core/ast_nodes.py +2619 -0
  35. quantum/core/config_env.py +54 -0
  36. quantum/core/docs_links.py +8 -0
  37. quantum/core/expression_diagnostics.py +87 -0
  38. quantum/core/expression_stdlib.py +208 -0
  39. quantum/core/expressions.py +677 -0
  40. quantum/core/features/agents/src/__init__.py +30 -0
  41. quantum/core/features/agents/src/ast_node.py +540 -0
  42. quantum/core/features/conditionals/src/__init__.py +8 -0
  43. quantum/core/features/conditionals/src/ast_node.py +68 -0
  44. quantum/core/features/data_import/src/__init__.py +0 -0
  45. quantum/core/features/data_import/src/ast_node.py +292 -0
  46. quantum/core/features/data_import/src/runtime.py +533 -0
  47. quantum/core/features/dump/src/__init__.py +12 -0
  48. quantum/core/features/dump/src/ast_node.py +106 -0
  49. quantum/core/features/dump/src/parser.py +61 -0
  50. quantum/core/features/dump/src/runtime.py +246 -0
  51. quantum/core/features/functions/src/__init__.py +8 -0
  52. quantum/core/features/functions/src/ast_node.py +149 -0
  53. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  54. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  55. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  56. quantum/core/features/invocation/src/__init__.py +0 -0
  57. quantum/core/features/invocation/src/ast_node.py +147 -0
  58. quantum/core/features/invocation/src/runtime.py +332 -0
  59. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  60. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  61. quantum/core/features/knowledge_base/src/parser.py +82 -0
  62. quantum/core/features/logging/src/__init__.py +12 -0
  63. quantum/core/features/logging/src/ast_node.py +111 -0
  64. quantum/core/features/logging/src/parser.py +50 -0
  65. quantum/core/features/logging/src/runtime.py +190 -0
  66. quantum/core/features/loops/src/__init__.py +8 -0
  67. quantum/core/features/loops/src/ast_node.py +60 -0
  68. quantum/core/features/query/src/__init__.py +0 -0
  69. quantum/core/features/query/src/query_validators.py +20 -0
  70. quantum/core/features/state_management/src/__init__.py +11 -0
  71. quantum/core/features/state_management/src/ast_node.py +121 -0
  72. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  73. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  74. quantum/core/features/terminal_engine/src/parser.py +361 -0
  75. quantum/core/features/testing_engine/src/__init__.py +41 -0
  76. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  77. quantum/core/features/testing_engine/src/parser.py +604 -0
  78. quantum/core/features/theming/src/__init__.py +48 -0
  79. quantum/core/features/theming/src/ast_node.py +137 -0
  80. quantum/core/features/theming/src/presets.py +405 -0
  81. quantum/core/features/ui_engine/src/__init__.py +20 -0
  82. quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
  83. quantum/core/features/ui_engine/src/parser.py +1192 -0
  84. quantum/core/features/websocket/src/__init__.py +24 -0
  85. quantum/core/features/websocket/src/ast_node.py +247 -0
  86. quantum/core/guards.py +53 -0
  87. quantum/core/html_compat.py +299 -0
  88. quantum/core/parser.py +1551 -0
  89. quantum/core/parser_registry.py +213 -0
  90. quantum/core/parsers/__init__.py +76 -0
  91. quantum/core/parsers/ai/__init__.py +12 -0
  92. quantum/core/parsers/ai/agent_parser.py +106 -0
  93. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  94. quantum/core/parsers/ai/llm_parser.py +78 -0
  95. quantum/core/parsers/ai/team_parser.py +88 -0
  96. quantum/core/parsers/base.py +322 -0
  97. quantum/core/parsers/composition/__init__.py +10 -0
  98. quantum/core/parsers/composition/import_parser.py +50 -0
  99. quantum/core/parsers/composition/slot_parser.py +48 -0
  100. quantum/core/parsers/control_flow/__init__.py +11 -0
  101. quantum/core/parsers/control_flow/if_parser.py +71 -0
  102. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  103. quantum/core/parsers/control_flow/set_parser.py +93 -0
  104. quantum/core/parsers/data/__init__.py +12 -0
  105. quantum/core/parsers/data/data_parser.py +229 -0
  106. quantum/core/parsers/data/invoke_parser.py +133 -0
  107. quantum/core/parsers/data/query_parser.py +213 -0
  108. quantum/core/parsers/data/transaction_parser.py +86 -0
  109. quantum/core/parsers/events/__init__.py +9 -0
  110. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  111. quantum/core/parsers/forms/__init__.py +11 -0
  112. quantum/core/parsers/forms/action_parser.py +79 -0
  113. quantum/core/parsers/forms/flash_parser.py +34 -0
  114. quantum/core/parsers/forms/redirect_parser.py +33 -0
  115. quantum/core/parsers/functions/__init__.py +11 -0
  116. quantum/core/parsers/functions/function_parser.py +98 -0
  117. quantum/core/parsers/functions/param_parser.py +73 -0
  118. quantum/core/parsers/functions/return_parser.py +31 -0
  119. quantum/core/parsers/html/__init__.py +10 -0
  120. quantum/core/parsers/html/component_call_parser.py +130 -0
  121. quantum/core/parsers/html/html_parser.py +115 -0
  122. quantum/core/parsers/jobs/__init__.py +11 -0
  123. quantum/core/parsers/jobs/job_parser.py +71 -0
  124. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  125. quantum/core/parsers/jobs/thread_parser.py +57 -0
  126. quantum/core/parsers/messaging/__init__.py +17 -0
  127. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  128. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_parser.py +114 -0
  130. quantum/core/parsers/messaging/queue_parser.py +61 -0
  131. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  132. quantum/core/parsers/routing/__init__.py +9 -0
  133. quantum/core/parsers/routing/route_parser.py +41 -0
  134. quantum/core/parsers/scripting/__init__.py +12 -0
  135. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  136. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  137. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  138. quantum/core/parsers/scripting/python_parser.py +49 -0
  139. quantum/core/parsers/services/__init__.py +12 -0
  140. quantum/core/parsers/services/dump_parser.py +52 -0
  141. quantum/core/parsers/services/file_parser.py +48 -0
  142. quantum/core/parsers/services/log_parser.py +46 -0
  143. quantum/core/parsers/services/mail_parser.py +65 -0
  144. quantum/core/tiers.py +164 -0
  145. quantum/core/xml_lines.py +81 -0
  146. quantum/packages/__init__.py +28 -0
  147. quantum/packages/manager.py +413 -0
  148. quantum/packages/manifest.py +351 -0
  149. quantum/packages/registry.py +399 -0
  150. quantum/packages/resolver.py +336 -0
  151. quantum/plugins/__init__.py +33 -0
  152. quantum/plugins/hooks.py +329 -0
  153. quantum/plugins/loader.py +479 -0
  154. quantum/plugins/manifest.py +336 -0
  155. quantum/plugins/registry.py +371 -0
  156. quantum/runtime/__init__.py +25 -0
  157. quantum/runtime/action_handler.py +532 -0
  158. quantum/runtime/adapters/__init__.py +88 -0
  159. quantum/runtime/adapters/memory_adapter.py +690 -0
  160. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  161. quantum/runtime/adapters/redis_adapter.py +582 -0
  162. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  163. quantum/runtime/agent_service.py +1133 -0
  164. quantum/runtime/ast_cache.py +506 -0
  165. quantum/runtime/auth_service.py +267 -0
  166. quantum/runtime/component.py +1048 -0
  167. quantum/runtime/component_composer.py +133 -0
  168. quantum/runtime/component_resolver.py +174 -0
  169. quantum/runtime/conditions.py +54 -0
  170. quantum/runtime/database_service.py +595 -0
  171. quantum/runtime/db_schema.py +100 -0
  172. quantum/runtime/dev_panel.py +178 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +283 -0
  176. quantum/runtime/executor_registry.py +178 -0
  177. quantum/runtime/executors/__init__.py +71 -0
  178. quantum/runtime/executors/ai/__init__.py +12 -0
  179. quantum/runtime/executors/ai/agent_executor.py +217 -0
  180. quantum/runtime/executors/ai/knowledge_executor.py +114 -0
  181. quantum/runtime/executors/ai/llm_executor.py +153 -0
  182. quantum/runtime/executors/ai/team_executor.py +171 -0
  183. quantum/runtime/executors/base.py +264 -0
  184. quantum/runtime/executors/control_flow/__init__.py +12 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +98 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +308 -0
  187. quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
  188. quantum/runtime/executors/control_flow/set_executor.py +464 -0
  189. quantum/runtime/executors/data/__init__.py +12 -0
  190. quantum/runtime/executors/data/data_executor.py +156 -0
  191. quantum/runtime/executors/data/invoke_executor.py +228 -0
  192. quantum/runtime/executors/data/query_executor.py +290 -0
  193. quantum/runtime/executors/data/transaction_executor.py +91 -0
  194. quantum/runtime/executors/jobs/__init__.py +11 -0
  195. quantum/runtime/executors/jobs/job_executor.py +190 -0
  196. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  197. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  198. quantum/runtime/executors/messaging/__init__.py +17 -0
  199. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  200. quantum/runtime/executors/messaging/message_executor.py +174 -0
  201. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  202. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  203. quantum/runtime/executors/scripting/__init__.py +11 -0
  204. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  205. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  206. quantum/runtime/executors/scripting/python_executor.py +249 -0
  207. quantum/runtime/executors/services/__init__.py +12 -0
  208. quantum/runtime/executors/services/dump_executor.py +72 -0
  209. quantum/runtime/executors/services/file_executor.py +89 -0
  210. quantum/runtime/executors/services/log_executor.py +77 -0
  211. quantum/runtime/executors/services/mail_executor.py +81 -0
  212. quantum/runtime/expression_cache.py +498 -0
  213. quantum/runtime/file_upload_service.py +326 -0
  214. quantum/runtime/function_registry.py +118 -0
  215. quantum/runtime/game_builder.py +166 -0
  216. quantum/runtime/game_code_generator.py +2371 -0
  217. quantum/runtime/game_templates.py +2006 -0
  218. quantum/runtime/godot_code_generator.py +4681 -0
  219. quantum/runtime/godot_templates.py +1449 -0
  220. quantum/runtime/job_executor.py +1599 -0
  221. quantum/runtime/knowledge_service.py +546 -0
  222. quantum/runtime/llm_cache.py +100 -0
  223. quantum/runtime/llm_providers.py +704 -0
  224. quantum/runtime/llm_service.py +287 -0
  225. quantum/runtime/local_server.py +28 -0
  226. quantum/runtime/logging_setup.py +141 -0
  227. quantum/runtime/message_broker.py +364 -0
  228. quantum/runtime/message_queue_service.py +571 -0
  229. quantum/runtime/param_validation.py +218 -0
  230. quantum/runtime/pypy_compat.py +317 -0
  231. quantum/runtime/python_bridge.py +698 -0
  232. quantum/runtime/query_validators.py +304 -0
  233. quantum/runtime/renderer.py +734 -0
  234. quantum/runtime/service_container.py +470 -0
  235. quantum/runtime/table_params.py +163 -0
  236. quantum/runtime/terminal_builder.py +76 -0
  237. quantum/runtime/terminal_code_generator.py +607 -0
  238. quantum/runtime/terminal_templates.py +243 -0
  239. quantum/runtime/testing_builder.py +77 -0
  240. quantum/runtime/testing_code_generator.py +833 -0
  241. quantum/runtime/testing_templates.py +85 -0
  242. quantum/runtime/ui_builder.py +222 -0
  243. quantum/runtime/ui_console.py +405 -0
  244. quantum/runtime/ui_desktop.py +56 -0
  245. quantum/runtime/ui_form_rules.py +193 -0
  246. quantum/runtime/ui_html_adapter.py +2567 -0
  247. quantum/runtime/ui_html_templates.py +2106 -0
  248. quantum/runtime/ui_mobile_adapter.py +1832 -0
  249. quantum/runtime/ui_mobile_templates.py +1003 -0
  250. quantum/runtime/ui_page_renderer.py +392 -0
  251. quantum/runtime/ui_pager.py +73 -0
  252. quantum/runtime/ui_table_edit.py +139 -0
  253. quantum/runtime/ui_textual_adapter.py +1866 -0
  254. quantum/runtime/ui_textual_templates.py +45 -0
  255. quantum/runtime/ui_tokens.py +465 -0
  256. quantum/runtime/ui_validator.py +365 -0
  257. quantum/runtime/ui_view.py +221 -0
  258. quantum/runtime/validators.py +256 -0
  259. quantum/runtime/web_server.py +2131 -0
  260. quantum/runtime/websocket_adapter.py +501 -0
  261. quantum/runtime/websocket_service.py +585 -0
  262. quantum/runtime/websocket_transport.py +289 -0
  263. quantum/runtime/wsgi.py +101 -0
  264. quantum/services.py +109 -0
  265. quantum/utils/__init__.py +1 -0
  266. quantum_admin/__init__.py +4 -0
  267. quantum_admin/assets/quantum-admin-connectors.js +123 -0
  268. quantum_admin/assets/quantum-admin.css +2058 -0
  269. quantum_admin/assets/quantum-source-highlight.js +106 -0
  270. quantum_admin/backend/__init__.py +4 -0
  271. quantum_admin/backend/audit_service.py +346 -0
  272. quantum_admin/backend/auth_service.py +394 -0
  273. quantum_admin/backend/component_discovery.py +766 -0
  274. quantum_admin/backend/config_generator.py +586 -0
  275. quantum_admin/backend/connector_service.py +1016 -0
  276. quantum_admin/backend/crud.py +557 -0
  277. quantum_admin/backend/database.py +226 -0
  278. quantum_admin/backend/db_setup_service.py +193 -0
  279. quantum_admin/backend/deploy_service.py +698 -0
  280. quantum_admin/backend/docker_service.py +422 -0
  281. quantum_admin/backend/environment_service.py +418 -0
  282. quantum_admin/backend/git_service.py +370 -0
  283. quantum_admin/backend/health_service.py +390 -0
  284. quantum_admin/backend/job_service.py +347 -0
  285. quantum_admin/backend/log_service.py +331 -0
  286. quantum_admin/backend/main.py +14426 -0
  287. quantum_admin/backend/models.py +986 -0
  288. quantum_admin/backend/pipeline_service.py +812 -0
  289. quantum_admin/backend/resource_manager.py +1118 -0
  290. quantum_admin/backend/schemas.py +419 -0
  291. quantum_admin/backend/secret_manager.py +277 -0
  292. quantum_admin/backend/settings_service.py +488 -0
  293. quantum_admin/backend/template_service.py +710 -0
  294. quantum_admin/backend/test_execution_service.py +364 -0
  295. quantum_admin/backend/test_generator.py +782 -0
  296. quantum_admin/backend/webhook_service.py +454 -0
  297. quantum_admin/backend/websocket_manager.py +360 -0
  298. quantum_admin/components/admin/_layout/AdminShell.q +121 -0
  299. quantum_admin/components/admin/agents.q +107 -0
  300. quantum_admin/components/admin/app/[name].q +558 -0
  301. quantum_admin/components/admin/applications.q +160 -0
  302. quantum_admin/components/admin/component/[...path].q +205 -0
  303. quantum_admin/components/admin/components.q +59 -0
  304. quantum_admin/components/admin/connectors.q +283 -0
  305. quantum_admin/components/admin/dashboard.q +86 -0
  306. quantum_admin/components/admin/database.q +95 -0
  307. quantum_admin/components/admin/features.q +69 -0
  308. quantum_admin/components/admin/index.q +12 -0
  309. quantum_admin/components/admin/jobs.q +75 -0
  310. quantum_admin/components/admin/login.q +65 -0
  311. quantum_admin/components/admin/logout.q +11 -0
  312. quantum_admin/components/admin/settings.q +174 -0
  313. quantum_admin/components/admin/source.q +45 -0
  314. quantum_admin/components/admin/tests.q +73 -0
  315. quantum_admin/run.py +13 -0
  316. quantum_admin/services/__init__.py +16 -0
  317. quantum_admin/services/_base.py +84 -0
  318. quantum_admin/services/_component_test_generator.py +205 -0
  319. quantum_admin/services/_yaml_editor.py +82 -0
  320. quantum_admin/services/apps.py +330 -0
  321. quantum_admin/services/auth.py +61 -0
  322. quantum_admin/services/components.py +210 -0
  323. quantum_admin/services/connectors.py +164 -0
  324. quantum_admin/services/projects.py +189 -0
  325. quantum_admin/services/repository.py +223 -0
  326. quantum_admin/services/settings.py +150 -0
  327. quantum_admin/services/yaml_import.py +118 -0
  328. quantum_framework-0.18.0.dist-info/METADATA +281 -0
  329. quantum_framework-0.18.0.dist-info/RECORD +333 -0
  330. quantum_framework-0.18.0.dist-info/WHEEL +5 -0
  331. quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
  332. quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
  333. quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,283 @@
1
+ <q:component name="AdminConnectors" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!--
3
+ Connectors de infraestrutura (admin.connectors.*), guardados em
4
+ settings/connectors.yaml por connector_service. A versão anterior
5
+ reimplementava o arquivo em q:python e gravava a senha em texto puro;
6
+ connector_service cifra, e nenhuma resposta traz a senha de volta.
7
+ Aqui se criam connectors públicos; os de uma aplicação ficam na tela dela.
8
+ -->
9
+ <q:import component="AdminShell" from="admin/_layout" />
10
+
11
+ <q:action name="createConnector" method="POST">
12
+ <q:param name="name" type="string" required="true" />
13
+ <q:param name="conn_type" type="string" required="true" />
14
+ <q:param name="provider" type="string" required="true" />
15
+ <q:param name="port" type="integer" default="0" />
16
+ <q:param name="is_default" type="boolean" default="false" />
17
+ <q:invoke name="criado" service="admin.connectors.create" onerror="continue">
18
+ <q:param name="name" value="{name}" />
19
+ <q:param name="type" value="{conn_type}" />
20
+ <q:param name="provider" value="{provider}" />
21
+ <q:param name="host" value="{form.host}" />
22
+ <q:param name="port" value="{port}" type="integer" />
23
+ <q:param name="database" value="{form.database}" />
24
+ <q:param name="username" value="{form.username}" />
25
+ <q:param name="password" value="{form.password}" />
26
+ <q:param name="is_default" value="{is_default}" type="boolean" />
27
+ </q:invoke>
28
+ <q:if condition="criado_result.success">
29
+ <q:redirect url="/admin/connectors" flash="Connector {criado.name} created" />
30
+ </q:if>
31
+ <q:flash type="error" message="{criado_result.error.message}" />
32
+ <q:redirect url="/admin/connectors" />
33
+ </q:action>
34
+
35
+ <q:action name="updateConnector" method="POST">
36
+ <q:param name="connector_id" type="string" required="true" />
37
+ <q:param name="port" type="integer" default="0" />
38
+ <q:param name="is_default" type="boolean" default="false" />
39
+ <q:invoke name="alterado" service="admin.connectors.update" onerror="continue">
40
+ <q:param name="connector_id" value="{connector_id}" />
41
+ <q:param name="name" value="{form.name}" />
42
+ <q:param name="type" value="{form.conn_type}" />
43
+ <q:param name="provider" value="{form.provider}" />
44
+ <q:param name="host" value="{form.host}" />
45
+ <q:param name="port" value="{port}" type="integer" />
46
+ <q:param name="database" value="{form.database}" />
47
+ <q:param name="username" value="{form.username}" />
48
+ <q:param name="password" value="{form.password}" />
49
+ <q:param name="is_default" value="{is_default}" type="boolean" />
50
+ </q:invoke>
51
+ <q:if condition="alterado_result.success">
52
+ <q:redirect url="/admin/connectors" flash="Connector {alterado.name} updated" />
53
+ </q:if>
54
+ <q:flash type="error" message="{alterado_result.error.message}" />
55
+ <q:redirect url="/admin/connectors?edit={connector_id}#edit-form" />
56
+ </q:action>
57
+
58
+ <q:action name="deleteConnector" method="POST">
59
+ <q:param name="connector_id" type="string" required="true" />
60
+ <q:invoke name="removido" service="admin.connectors.delete" onerror="continue">
61
+ <q:param name="connector_id" value="{connector_id}" />
62
+ </q:invoke>
63
+ <q:if condition="removido_result.success">
64
+ <q:redirect url="/admin/connectors" flash="Connector deleted" />
65
+ </q:if>
66
+ <q:flash type="error" message="{removido_result.error.message}" />
67
+ <q:redirect url="/admin/connectors" />
68
+ </q:action>
69
+
70
+ <q:action name="testConnector" method="POST">
71
+ <q:param name="connector_id" type="string" required="true" />
72
+ <q:invoke name="teste" service="admin.connectors.test" onerror="continue">
73
+ <q:param name="connector_id" value="{connector_id}" />
74
+ </q:invoke>
75
+ <q:if condition="not teste_result.success">
76
+ <q:flash type="error" message="{teste_result.error.message}" />
77
+ <q:redirect url="/admin/connectors" />
78
+ </q:if>
79
+ <q:if condition="teste.success">
80
+ <q:redirect url="/admin/connectors" flash="Connection OK" />
81
+ </q:if>
82
+ <q:flash type="error" message="Connection failed: {teste.error}" />
83
+ <q:redirect url="/admin/connectors" />
84
+ </q:action>
85
+
86
+ <q:action name="testAll" method="POST">
87
+ <q:invoke name="testes" service="admin.connectors.test_all" />
88
+ <q:redirect url="/admin/connectors" flash="Tested {len(testes)} connector(s)" />
89
+ </q:action>
90
+
91
+ <q:invoke name="painel" service="admin.connectors.overview" />
92
+ <q:set name="editar" value="{query.edit}" />
93
+ <q:if condition="editar">
94
+ <q:invoke name="edicao" service="admin.connectors.get" onerror="continue">
95
+ <q:param name="connector_id" value="{editar}" />
96
+ </q:invoke>
97
+ </q:if>
98
+
99
+ <!-- Um formulário só: com ?edit=<id> vem preenchido e altera; sem, cria. -->
100
+ <q:set name="emEdicao" value="{editar and edicao_result.success}" type="boolean" />
101
+
102
+ <AdminShell title="Connectors" active="connectors" flash="{flash}" flashType="{flashType}">
103
+
104
+ <div class="qa-flex qa-items-center qa-mb-6" style="gap: 8px; flex-wrap: wrap;">
105
+ <span class="qa-badge qa-badge-primary">{painel.total} registered</span>
106
+ <span class="qa-badge qa-badge-success">{painel.connected} connected</span>
107
+ <q:if condition="painel.errors &gt; 0">
108
+ <span class="qa-badge qa-badge-danger">{painel.errors} with errors</span>
109
+ </q:if>
110
+ <q:if condition="painel.total &gt; 0">
111
+ <form method="POST" action="/admin/connectors" style="margin: 0 0 0 auto;">
112
+ <input type="hidden" name="action" value="testAll" />
113
+ <button type="submit" class="qa-btn qa-btn-primary qa-btn-sm">Test All</button>
114
+ </form>
115
+ </q:if>
116
+ </div>
117
+
118
+ <div class="qa-grid qa-grid-5 qa-mb-6">
119
+ <q:loop type="array" var="grupo" items="{painel.types}">
120
+ <div class="qa-stat-card">
121
+ <div class="qa-flex qa-items-center qa-justify-between">
122
+ <div class="qa-stat-label">{grupo.label}</div>
123
+ <span class="qa-badge qa-type-{grupo.type}">{len(grupo.connectors)}</span>
124
+ </div>
125
+ <q:loop type="array" var="c" items="{grupo.connectors}">
126
+ <div class="qa-stat-connector-item">
127
+ <span class="qa-status-dot {c.status}"></span>
128
+ <span>{c.name}</span>
129
+ <q:if condition="c.is_default"><span title="default for this type">&#9733;</span></q:if>
130
+ </div>
131
+ </q:loop>
132
+ <q:if condition="len(grupo.connectors) == 0">
133
+ <div class="qa-text-sm qa-text-muted">None configured</div>
134
+ </q:if>
135
+ </div>
136
+ </q:loop>
137
+ </div>
138
+
139
+ <q:if condition="painel.total &gt; 0">
140
+ <div class="qa-card qa-mb-6">
141
+ <div class="qa-card-body qa-p-0" style="overflow-x: auto;">
142
+ <table class="qa-table">
143
+ <thead><tr><th>Name</th><th>Type</th><th>Provider</th><th>Host:Port</th><th>Status</th><th>Scope</th><th></th></tr></thead>
144
+ <tbody>
145
+ <q:loop type="array" var="grupo" items="{painel.types}">
146
+ <q:loop type="array" var="conn" items="{grupo.connectors}">
147
+ <tr>
148
+ <td><span class="qa-font-medium">{conn.name}</span></td>
149
+ <td><span class="qa-badge qa-type-{conn.type}">{conn.type_label}</span></td>
150
+ <td><span class="qa-text-sm">{conn.provider_name}</span></td>
151
+ <td><span class="qa-font-mono qa-text-sm">{conn.host}:{conn.port}</span></td>
152
+ <td>
153
+ <div class="qa-status-badge" title="{'last tested ' + conn.last_tested if conn.last_tested else 'never tested'}">
154
+ <span class="qa-status-dot {conn.status}"></span>
155
+ <span class="qa-status-text">{conn.status}</span>
156
+ </div>
157
+ </td>
158
+ <td><span class="qa-text-sm qa-text-muted">{'application #' + str(conn.application_id) if conn.application_id else 'public'}</span></td>
159
+ <td>
160
+ <div class="qa-flex" style="gap: 4px;">
161
+ <form method="POST" action="/admin/connectors" style="margin: 0;">
162
+ <input type="hidden" name="action" value="testConnector" />
163
+ <input type="hidden" name="connector_id" value="{conn.id}" />
164
+ <button type="submit" class="qa-btn qa-btn-ghost qa-btn-sm">Test</button>
165
+ </form>
166
+ <a href="/admin/connectors?edit={conn.id}#edit-form" class="qa-btn qa-btn-ghost qa-btn-sm">Edit</a>
167
+ <form method="POST" action="/admin/connectors" style="margin: 0;" onsubmit="return confirm('Delete this connector?');">
168
+ <input type="hidden" name="action" value="deleteConnector" />
169
+ <input type="hidden" name="connector_id" value="{conn.id}" />
170
+ <button type="submit" class="qa-btn qa-btn-danger qa-btn-sm" aria-label="Delete {conn.name}">Delete</button>
171
+ </form>
172
+ </div>
173
+ </td>
174
+ </tr>
175
+ </q:loop>
176
+ </q:loop>
177
+ </tbody>
178
+ </table>
179
+ </div>
180
+ </div>
181
+ </q:if>
182
+
183
+ <q:if condition="editar and not edicao_result.success">
184
+ <div class="qa-flash qa-flash-error" role="alert">{edicao_result.error.message}</div>
185
+ </q:if>
186
+
187
+ <div class="qa-card" id="edit-form">
188
+ <div class="qa-card-header">
189
+ <div>
190
+ <div class="qa-card-title">{'Edit ' + edicao.name if emEdicao else 'New Connector'}</div>
191
+ <div class="qa-card-subtitle">{'Blank password keeps the current one' if emEdicao else 'Public: available to every application'}</div>
192
+ </div>
193
+ <q:if condition="emEdicao">
194
+ <a href="/admin/connectors" class="qa-btn qa-btn-ghost qa-btn-sm">Cancel</a>
195
+ </q:if>
196
+ </div>
197
+ <div class="qa-card-body">
198
+ <form method="POST" action="/admin/connectors">
199
+ <q:if condition="emEdicao">
200
+ <input type="hidden" name="action" value="updateConnector" />
201
+ <input type="hidden" name="connector_id" value="{edicao.id}" />
202
+ <q:else>
203
+ <input type="hidden" name="action" value="createConnector" />
204
+ </q:else>
205
+ </q:if>
206
+ <div class="qa-form-row qa-mb-4">
207
+ <div class="qa-form-group">
208
+ <label class="qa-label" for="name">Name</label>
209
+ <input id="name" type="text" name="name" class="qa-input" placeholder="e.g. Production Redis" required="" value="{edicao.name if emEdicao else ''}" />
210
+ </div>
211
+ <div class="qa-form-group">
212
+ <label class="qa-label" for="conn_type">Type</label>
213
+ <select id="conn_type" name="conn_type" class="qa-input qa-select" required="">
214
+ <option value="">Select type...</option>
215
+ <q:loop type="array" var="grupo" items="{painel.types}">
216
+ <q:if condition="emEdicao and edicao.type == grupo.type">
217
+ <option value="{grupo.type}" selected="selected">{grupo.label}</option>
218
+ <q:else><option value="{grupo.type}">{grupo.label}</option></q:else>
219
+ </q:if>
220
+ </q:loop>
221
+ </select>
222
+ </div>
223
+ </div>
224
+ <div class="qa-form-row qa-mb-4">
225
+ <div class="qa-form-group">
226
+ <label class="qa-label" for="provider">Provider</label>
227
+ <select id="provider" name="provider" class="qa-input qa-select" required="">
228
+ <option value="">Select provider...</option>
229
+ <q:loop type="array" var="grupo" items="{painel.types}">
230
+ <optgroup label="{grupo.label}">
231
+ <q:loop type="array" var="p" items="{grupo.providers}">
232
+ <q:if condition="emEdicao and edicao.provider == p.provider">
233
+ <option value="{p.provider}" selected="selected">{p.name}</option>
234
+ <q:else><option value="{p.provider}">{p.name}</option></q:else>
235
+ </q:if>
236
+ </q:loop>
237
+ </optgroup>
238
+ </q:loop>
239
+ </select>
240
+ </div>
241
+ <div class="qa-form-group">
242
+ <label class="qa-label" for="port">Port</label>
243
+ <input id="port" type="number" name="port" class="qa-input" min="0" max="65535" placeholder="provider default" value="{edicao.port if emEdicao else ''}" />
244
+ </div>
245
+ </div>
246
+ <div class="qa-form-row qa-mb-4">
247
+ <div class="qa-form-group">
248
+ <label class="qa-label" for="host">Host</label>
249
+ <input id="host" type="text" name="host" class="qa-input" placeholder="localhost" value="{edicao.host if emEdicao else ''}" />
250
+ </div>
251
+ <div class="qa-form-group">
252
+ <label class="qa-label" for="database">Database</label>
253
+ <input id="database" type="text" name="database" class="qa-input" placeholder="Database, bucket or path" value="{edicao.database if emEdicao else ''}" />
254
+ </div>
255
+ </div>
256
+ <div class="qa-form-row qa-mb-4">
257
+ <div class="qa-form-group">
258
+ <label class="qa-label" for="username">Username</label>
259
+ <input id="username" type="text" name="username" class="qa-input" autocomplete="off" value="{edicao.username if emEdicao else ''}" />
260
+ </div>
261
+ <div class="qa-form-group">
262
+ <label class="qa-label" for="password">Password or API key</label>
263
+ <input id="password" type="password" name="password" class="qa-input" autocomplete="new-password"
264
+ placeholder="{'saved — leave blank to keep' if emEdicao and edicao.has_password else ''}" />
265
+ </div>
266
+ </div>
267
+ <div class="qa-mb-4">
268
+ <label class="qa-flex qa-items-center" style="gap: 8px;">
269
+ <q:if condition="emEdicao and edicao.is_default">
270
+ <input type="checkbox" name="is_default" value="true" checked="checked" />
271
+ <q:else><input type="checkbox" name="is_default" value="true" /></q:else>
272
+ </q:if>
273
+ <span class="qa-text-sm">Default for this type</span>
274
+ </label>
275
+ </div>
276
+ <button type="submit" class="qa-btn qa-btn-primary">{'Save Changes' if emEdicao else 'Create Connector'}</button>
277
+ </form>
278
+ </div>
279
+ </div>
280
+
281
+ <script src="/static/quantum-admin-connectors.js"></script>
282
+ </AdminShell>
283
+ </q:component>
@@ -0,0 +1,86 @@
1
+ <q:component name="AdminDashboard" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!--
3
+ Números do repositório, medidos por admin.dashboard.stats
4
+ (quantum_admin/services/repository.py). A versão anterior procurava
5
+ src/core/... e mostrava 0 features, 0 parsers e 0 executores.
6
+ -->
7
+ <q:import component="AdminShell" from="admin/_layout" />
8
+
9
+ <q:invoke name="stats" service="admin.dashboard.stats" />
10
+ <q:invoke name="catalogo" service="admin.features.list" />
11
+
12
+ <AdminShell title="Dashboard" active="dashboard" flash="{flash}" flashType="{flashType}">
13
+
14
+ <div class="qa-grid qa-grid-4 qa-mb-6">
15
+ <div class="qa-stat-card">
16
+ <div class="qa-stat-label">Components</div>
17
+ <div class="qa-stat-value">{stats.components}</div>
18
+ <div class="qa-stat-change"><span class="qa-text-muted">.q files in components/</span></div>
19
+ </div>
20
+ <div class="qa-stat-card">
21
+ <div class="qa-stat-label">Features</div>
22
+ <div class="qa-stat-value">{stats.features}</div>
23
+ <div class="qa-stat-change"><span class="qa-text-muted">manifests in quantum/core/features/</span></div>
24
+ </div>
25
+ <div class="qa-stat-card">
26
+ <div class="qa-stat-label">Test Files</div>
27
+ <div class="qa-stat-value">{stats.tests}</div>
28
+ <div class="qa-stat-change"><span class="qa-text-muted">test_*.py in tests/</span></div>
29
+ </div>
30
+ <div class="qa-stat-card">
31
+ <div class="qa-stat-label">Examples</div>
32
+ <div class="qa-stat-value">{stats.examples}</div>
33
+ <div class="qa-stat-change"><span class="qa-text-muted">.q files in examples/</span></div>
34
+ </div>
35
+ </div>
36
+
37
+ <div class="qa-grid qa-grid-2 qa-mb-6">
38
+ <div class="qa-stat-card">
39
+ <div class="qa-stat-label">Tags with a parser</div>
40
+ <div class="qa-stat-value">{stats.parser_tags}</div>
41
+ <div class="qa-stat-change"><span class="qa-text-muted">registered in the parser registry</span></div>
42
+ </div>
43
+ <div class="qa-stat-card">
44
+ <div class="qa-stat-label">Executors</div>
45
+ <div class="qa-stat-value">{stats.executors}</div>
46
+ <div class="qa-stat-change"><span class="qa-text-muted">registered in the executor registry</span></div>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="qa-grid qa-grid-2">
51
+ <div class="qa-card">
52
+ <div class="qa-card-header">
53
+ <div>
54
+ <div class="qa-card-title">Project Components</div>
55
+ <div class="qa-card-subtitle">{stats.components} .q files</div>
56
+ </div>
57
+ </div>
58
+ <div class="qa-card-body" style="max-height: 360px; overflow-y: auto;">
59
+ <q:loop type="array" var="comp" items="{stats.component_list}">
60
+ <div class="qa-activity-item">
61
+ <a class="qa-text-sm qa-font-medium qa-font-mono" href="/admin/component/components/{comp}">{comp}</a>
62
+ </div>
63
+ </q:loop>
64
+ </div>
65
+ </div>
66
+
67
+ <div class="qa-card">
68
+ <div class="qa-card-header">
69
+ <div>
70
+ <div class="qa-card-title">Features</div>
71
+ <div class="qa-card-subtitle">{len(catalogo.features)} feature modules</div>
72
+ </div>
73
+ </div>
74
+ <div class="qa-card-body" style="max-height: 360px; overflow-y: auto;">
75
+ <q:loop type="array" var="feat" items="{catalogo.features}">
76
+ <div class="qa-activity-item">
77
+ <span class="qa-text-sm qa-font-medium">{feat.display_name}</span>
78
+ <span class="{'qa-badge qa-badge-success' if feat.status == 'active' else 'qa-badge qa-badge-gray'}">{feat.status}</span>
79
+ </div>
80
+ </q:loop>
81
+ </div>
82
+ </div>
83
+ </div>
84
+
85
+ </AdminShell>
86
+ </q:component>
@@ -0,0 +1,95 @@
1
+ <q:component name="AdminDatabase" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!--
3
+ Bancos SQLite da raiz e datasources declarados (admin.databases.list).
4
+ Os bancos são abertos somente leitura — a versão anterior abria em modo
5
+ escrita, inclusive bancos de aplicações rodando.
6
+ -->
7
+ <q:import component="AdminShell" from="admin/_layout" />
8
+
9
+ <q:invoke name="dados" service="admin.databases.list" />
10
+
11
+ <AdminShell title="Database" active="database" flash="{flash}" flashType="{flashType}">
12
+
13
+ <div class="qa-grid qa-grid-3 qa-mb-6">
14
+ <div class="qa-stat-card">
15
+ <div class="qa-stat-label">Database Files</div>
16
+ <div class="qa-stat-value">{len(dados.databases)}</div>
17
+ <div class="qa-stat-change"><span class="qa-text-muted">.db files, opened read-only</span></div>
18
+ </div>
19
+ <div class="qa-stat-card">
20
+ <div class="qa-stat-label">Total Tables</div>
21
+ <div class="qa-stat-value">{dados.total_tables}</div>
22
+ <div class="qa-stat-change"><span class="qa-text-muted">across all databases</span></div>
23
+ </div>
24
+ <div class="qa-stat-card">
25
+ <div class="qa-stat-label">Datasources</div>
26
+ <div class="qa-stat-value">{len(dados.datasources)}</div>
27
+ <div class="qa-stat-change"><span class="qa-text-muted">declared in quantum.config.yaml</span></div>
28
+ </div>
29
+ </div>
30
+
31
+ <q:loop type="array" var="banco" items="{dados.databases}">
32
+ <div class="qa-card qa-mb-4">
33
+ <div class="qa-card-header">
34
+ <div>
35
+ <div class="qa-card-title"><span class="qa-font-mono">{banco.path}</span></div>
36
+ <div class="qa-card-subtitle">{banco.size} · modified {banco.modified} · {len(banco.tables)} tables</div>
37
+ </div>
38
+ </div>
39
+ <q:if condition="banco.error">
40
+ <div class="qa-card-body"><span class="qa-text-sm" style="color: var(--q-danger);">Could not be read: {banco.error}</span></div>
41
+ </q:if>
42
+ <q:if condition="len(banco.tables) &gt; 0">
43
+ <div class="qa-card-body qa-p-0">
44
+ <table class="qa-table">
45
+ <thead><tr><th>Table</th><th>Rows</th></tr></thead>
46
+ <tbody>
47
+ <q:loop type="array" var="tabela" items="{banco.tables}">
48
+ <tr>
49
+ <td><span class="qa-font-mono">{tabela.name}</span></td>
50
+ <td style="font-variant-numeric: tabular-nums;">{'?' if tabela.rows == None else tabela.rows}</td>
51
+ </tr>
52
+ </q:loop>
53
+ </tbody>
54
+ </table>
55
+ </div>
56
+ </q:if>
57
+ </div>
58
+ </q:loop>
59
+
60
+ <q:if condition="len(dados.datasources) &gt; 0">
61
+ <div class="qa-card qa-mb-4">
62
+ <div class="qa-card-header">
63
+ <div>
64
+ <div class="qa-card-title">Declared Datasources</div>
65
+ <div class="qa-card-subtitle">name, driver and database only — credentials are not shown</div>
66
+ </div>
67
+ </div>
68
+ <div class="qa-card-body qa-p-0">
69
+ <table class="qa-table">
70
+ <thead><tr><th>Name</th><th>Driver</th><th>Database</th></tr></thead>
71
+ <tbody>
72
+ <q:loop type="array" var="fonte" items="{dados.datasources}">
73
+ <tr>
74
+ <td><span class="qa-font-mono">{fonte.name}</span></td>
75
+ <td><span class="qa-badge qa-badge-info">{fonte.driver or '-'}</span></td>
76
+ <td><span class="qa-font-mono">{fonte.database or '-'}</span></td>
77
+ </tr>
78
+ </q:loop>
79
+ </tbody>
80
+ </table>
81
+ </div>
82
+ </div>
83
+ </q:if>
84
+
85
+ <q:if condition="len(dados.databases) == 0 and len(dados.datasources) == 0">
86
+ <div class="qa-card">
87
+ <div class="qa-empty">
88
+ <div class="qa-empty-title">No Databases Found</div>
89
+ <div class="qa-empty-text">No .db file under the project root and no datasource in quantum.config.yaml.</div>
90
+ </div>
91
+ </div>
92
+ </q:if>
93
+
94
+ </AdminShell>
95
+ </q:component>
@@ -0,0 +1,69 @@
1
+ <q:component name="AdminFeatures" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!--
3
+ Features de quantum/core/features, pelo manifest.yaml de cada uma
4
+ (admin.features.list). A versão anterior lia src/core/features, que não
5
+ existe mais, e a tabela vinha vazia.
6
+ -->
7
+ <q:import component="AdminShell" from="admin/_layout" />
8
+
9
+ <q:invoke name="catalogo" service="admin.features.list" />
10
+
11
+ <AdminShell title="Features" active="features" flash="{flash}" flashType="{flashType}">
12
+
13
+ <div class="qa-grid qa-grid-4 qa-mb-6">
14
+ <div class="qa-stat-card">
15
+ <div class="qa-stat-label">Total Features</div>
16
+ <div class="qa-stat-value">{len(catalogo.features)}</div>
17
+ <div class="qa-stat-change"><span class="qa-text-muted">with manifest.yaml</span></div>
18
+ </div>
19
+ <div class="qa-stat-card">
20
+ <div class="qa-stat-label">Active</div>
21
+ <div class="qa-stat-value">{catalogo.summary.active}</div>
22
+ <div class="qa-stat-change"><span class="qa-text-muted">status: active</span></div>
23
+ </div>
24
+ <div class="qa-stat-card">
25
+ <div class="qa-stat-label">Planned</div>
26
+ <div class="qa-stat-value">{catalogo.summary.planned}</div>
27
+ <div class="qa-stat-change"><span class="qa-text-muted">status: planned</span></div>
28
+ </div>
29
+ <div class="qa-stat-card">
30
+ <div class="qa-stat-label">Other</div>
31
+ <div class="qa-stat-value">{catalogo.summary.other}</div>
32
+ <div class="qa-stat-change"><span class="qa-text-muted">experimental, draft or unreadable</span></div>
33
+ </div>
34
+ </div>
35
+
36
+ <div class="qa-card">
37
+ <div class="qa-card-header">
38
+ <div>
39
+ <div class="qa-card-title">All Features</div>
40
+ <div class="qa-card-subtitle">status as declared in each manifest</div>
41
+ </div>
42
+ </div>
43
+ <div class="qa-card-body qa-p-0" style="overflow-x: auto;">
44
+ <table class="qa-table">
45
+ <thead>
46
+ <tr><th>Feature</th><th>Description</th><th>Version</th><th>Status</th><th>Category</th><th></th></tr>
47
+ </thead>
48
+ <tbody>
49
+ <q:loop type="array" var="feat" items="{catalogo.features}">
50
+ <tr>
51
+ <td><span class="qa-font-mono">{feat.name}</span><div class="qa-text-xs qa-text-muted">{feat.display_name}</div></td>
52
+ <td class="qa-text-sm">{feat.short_desc}</td>
53
+ <td><span class="qa-font-mono">{feat.version or '-'}</span></td>
54
+ <td><span class="{'qa-badge qa-badge-success' if feat.status == 'active' else ('qa-badge qa-badge-danger' if feat.status == 'error' else ('qa-badge qa-badge-warning' if feat.status == 'planned' else 'qa-badge qa-badge-info'))}">{feat.status}</span></td>
55
+ <td><span class="qa-badge qa-badge-info">{feat.category or '-'}</span></td>
56
+ <td>
57
+ <q:if condition="feat.source">
58
+ <a href="/admin/source?file={feat.source}" class="qa-text-sm">Manifest</a>
59
+ </q:if>
60
+ </td>
61
+ </tr>
62
+ </q:loop>
63
+ </tbody>
64
+ </table>
65
+ </div>
66
+ </div>
67
+
68
+ </AdminShell>
69
+ </q:component>
@@ -0,0 +1,12 @@
1
+ <q:component name="AdminIndex" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!-- /admin: sem sessão, AUTH-4 manda para /admin/login; com sessão, para as aplicações. -->
3
+ <html lang="en">
4
+ <head>
5
+ <meta http-equiv="refresh" content="0;url=/admin/applications" />
6
+ <title>Quantum Admin</title>
7
+ </head>
8
+ <body>
9
+ <p>Opening <a href="/admin/applications">Applications</a>…</p>
10
+ </body>
11
+ </html>
12
+ </q:component>
@@ -0,0 +1,75 @@
1
+ <q:component name="AdminJobs" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!-- Fila de q:job em quantum_jobs.db, somente leitura (admin.jobs.list). -->
3
+ <q:import component="AdminShell" from="admin/_layout" />
4
+
5
+ <q:invoke name="fila" service="admin.jobs.list" />
6
+
7
+ <AdminShell title="Jobs" active="jobs" flash="{flash}" flashType="{flashType}">
8
+
9
+ <div class="qa-grid qa-grid-4 qa-mb-6">
10
+ <div class="qa-stat-card">
11
+ <div class="qa-stat-label">Pending</div>
12
+ <div class="qa-stat-value" style="color: var(--q-warning);">{fila.counts.pending}</div>
13
+ <div class="qa-stat-change"><span class="qa-text-muted">waiting in queue</span></div>
14
+ </div>
15
+ <div class="qa-stat-card">
16
+ <div class="qa-stat-label">Running</div>
17
+ <div class="qa-stat-value" style="color: var(--q-info);">{fila.counts.running}</div>
18
+ <div class="qa-stat-change"><span class="qa-text-muted">currently executing</span></div>
19
+ </div>
20
+ <div class="qa-stat-card">
21
+ <div class="qa-stat-label">Completed</div>
22
+ <div class="qa-stat-value" style="color: var(--q-success);">{fila.counts.completed}</div>
23
+ <div class="qa-stat-change"><span class="qa-text-muted">finished successfully</span></div>
24
+ </div>
25
+ <div class="qa-stat-card">
26
+ <div class="qa-stat-label">Failed</div>
27
+ <div class="qa-stat-value" style="color: var(--q-danger);">{fila.counts.failed}</div>
28
+ <div class="qa-stat-change"><span class="qa-text-muted">out of attempts</span></div>
29
+ </div>
30
+ </div>
31
+
32
+ <q:if condition="fila.error">
33
+ <div class="qa-flash qa-flash-error" role="alert">quantum_jobs.db could not be read: {fila.error}</div>
34
+ </q:if>
35
+
36
+ <q:if condition="fila.found">
37
+ <div class="qa-card">
38
+ <div class="qa-card-header">
39
+ <div>
40
+ <div class="qa-card-title">Recent Jobs</div>
41
+ <div class="qa-card-subtitle">{fila.total} jobs in total, newest {len(fila.jobs)} shown</div>
42
+ </div>
43
+ </div>
44
+ <div class="qa-card-body qa-p-0" style="overflow-x: auto;">
45
+ <table class="qa-table">
46
+ <thead><tr><th>ID</th><th>Name</th><th>Queue</th><th>Status</th><th>Attempts</th><th>Created</th><th>Error</th></tr></thead>
47
+ <tbody>
48
+ <q:loop type="array" var="job" items="{fila.jobs}">
49
+ <tr>
50
+ <td><span class="qa-font-mono">{job.id}</span></td>
51
+ <td>{job.name or '-'}</td>
52
+ <td><span class="qa-badge qa-badge-info">{job.queue or 'default'}</span></td>
53
+ <td><span class="{'qa-badge qa-badge-success' if job.status == 'completed' else ('qa-badge qa-badge-danger' if job.status == 'failed' else ('qa-badge qa-badge-warning' if job.status == 'pending' else 'qa-badge qa-badge-info'))}">{job.status}</span></td>
54
+ <td style="font-variant-numeric: tabular-nums;">{job.attempts}/{job.max_attempts}</td>
55
+ <td><span class="qa-text-sm qa-text-muted">{job.created_at or '-'}</span></td>
56
+ <td><span class="qa-text-sm qa-text-muted qa-truncate" style="max-width: 320px; display: inline-block;" title="{job.error or ''}">{job.error or '-'}</span></td>
57
+ </tr>
58
+ </q:loop>
59
+ </tbody>
60
+ </table>
61
+ </div>
62
+ </div>
63
+ </q:if>
64
+
65
+ <q:if condition="not fila.found">
66
+ <div class="qa-card">
67
+ <div class="qa-empty">
68
+ <div class="qa-empty-title">No Job Queue Yet</div>
69
+ <div class="qa-empty-text">quantum_jobs.db does not exist in the project root. It is created the first time a q:job is dispatched.</div>
70
+ </div>
71
+ </div>
72
+ </q:if>
73
+
74
+ </AdminShell>
75
+ </q:component>