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,160 @@
1
+ <q:component name="AdminApplications" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!--
3
+ Aplicações. A lógica está em quantum_admin/services/projects.py
4
+ (admin.projects.*); esta tela só chama os serviços e mostra o resultado.
5
+ Os dados ficam no banco do admin — antes, em settings/projects.yaml.
6
+ -->
7
+ <q:import component="AdminShell" from="admin/_layout" />
8
+
9
+ <q:action name="createProject" method="POST">
10
+ <q:param name="name" type="string" required="true" minlength="2" />
11
+ <q:param name="description" type="string" />
12
+ <q:param name="source_path" type="string" />
13
+ <q:invoke name="criado" service="admin.projects.create" onerror="continue">
14
+ <q:param name="name" value="{name}" />
15
+ <q:param name="description" value="{form.description}" />
16
+ <q:param name="source_path" value="{form.source_path}" />
17
+ </q:invoke>
18
+ <q:if condition="criado_result.success">
19
+ <q:redirect url="/admin/applications" flash="Application {criado.name} created" />
20
+ </q:if>
21
+ <q:flash type="error" message="{criado_result.error.message}" />
22
+ <q:redirect url="/admin/applications" />
23
+ </q:action>
24
+
25
+ <q:action name="deleteProject" method="POST">
26
+ <q:param name="project_id" type="integer" required="true" />
27
+ <q:invoke name="removido" service="admin.projects.delete">
28
+ <q:param name="project_id" value="{project_id}" type="integer" />
29
+ </q:invoke>
30
+ <q:redirect url="/admin/applications" flash="Application record removed (files were kept)" />
31
+ </q:action>
32
+
33
+ <q:action name="syncProjects" method="POST">
34
+ <q:invoke name="sincronia" service="admin.projects.sync" />
35
+ <q:redirect url="/admin/applications" flash="{len(sincronia.created)} new application(s) found on disk" />
36
+ </q:action>
37
+
38
+ <q:action name="importYaml" method="POST">
39
+ <q:invoke name="importacao" service="admin.import.run" />
40
+ <q:redirect url="/admin/applications" flash="{len(importacao.projects)} application(s) imported; database backup at {importacao.backup}" />
41
+ </q:action>
42
+
43
+ <!-- query.search pode não existir: a referência pura vale '' (EXPR-3) -->
44
+ <q:set name="busca" value="{query.search}" />
45
+ <q:invoke name="apps" service="admin.projects.list">
46
+ <q:param name="search" value="{busca}" />
47
+ </q:invoke>
48
+ <q:invoke name="totais" service="admin.projects.summary" />
49
+ <q:invoke name="pendentes" service="admin.import.pending" />
50
+
51
+ <AdminShell title="Applications" active="applications" flash="{flash}" flashType="{flashType}">
52
+
53
+ <q:if condition="len(pendentes.projects) &gt; 0">
54
+ <div class="qa-card qa-mb-6">
55
+ <div class="qa-card-body">
56
+ <p class="qa-text-sm">
57
+ {len(pendentes.projects)} application(s) exist only in the old settings/projects.yaml:
58
+ <span class="qa-font-mono">{join(pendentes.projects)}</span>.
59
+ Importing copies them into the admin database (a backup of the database is made first; the YAML file is not changed).
60
+ </p>
61
+ <form method="POST" action="/admin/applications">
62
+ <input type="hidden" name="action" value="importYaml" />
63
+ <button type="submit" class="qa-btn qa-btn-primary qa-btn-sm">Import</button>
64
+ </form>
65
+ </div>
66
+ </div>
67
+ </q:if>
68
+
69
+ <div class="qa-grid qa-grid-4 qa-mb-6">
70
+ <div class="qa-stat-card"><div class="qa-stat-label">Total Apps</div><div class="qa-stat-value">{totais.total}</div></div>
71
+ <div class="qa-stat-card"><div class="qa-stat-label">Active</div><div class="qa-stat-value">{totais.active}</div></div>
72
+ <div class="qa-stat-card"><div class="qa-stat-label">Running</div><div class="qa-stat-value">{totais.running}</div></div>
73
+ <div class="qa-stat-card"><div class="qa-stat-label">Connectors</div><div class="qa-stat-value">{totais.connectors}</div></div>
74
+ </div>
75
+
76
+ <div style="display: flex; gap: 12px; margin-bottom: 24px; flex-wrap: wrap;">
77
+ <form method="GET" action="/admin/applications" style="flex: 1; min-width: 200px;">
78
+ <div class="qa-search-bar">
79
+ <input type="text" name="search" placeholder="Search applications..." value="{busca}" aria-label="Search applications" />
80
+ </div>
81
+ </form>
82
+ <form method="POST" action="/admin/applications">
83
+ <input type="hidden" name="action" value="syncProjects" />
84
+ <button type="submit" class="qa-btn qa-btn-secondary qa-btn-sm">Sync from Disk</button>
85
+ </form>
86
+ </div>
87
+
88
+ <div class="qa-card qa-mb-6">
89
+ <div class="qa-card-header">
90
+ <div>
91
+ <div class="qa-card-title">New Application</div>
92
+ <div class="qa-card-subtitle">Create a new Quantum project</div>
93
+ </div>
94
+ </div>
95
+ <div class="qa-card-body">
96
+ <form method="POST" action="/admin/applications">
97
+ <input type="hidden" name="action" value="createProject" />
98
+ <div class="qa-form-row qa-mb-4">
99
+ <div class="qa-form-group">
100
+ <label class="qa-label" for="name">Name</label>
101
+ <input id="name" type="text" name="name" class="qa-input" placeholder="my-app" required="" minlength="2" />
102
+ </div>
103
+ <div class="qa-form-group">
104
+ <label class="qa-label" for="source_path">Source Path</label>
105
+ <input id="source_path" type="text" name="source_path" class="qa-input" placeholder="projects/my-app (optional)" />
106
+ </div>
107
+ </div>
108
+ <div class="qa-form-group qa-mb-4">
109
+ <label class="qa-label" for="description">Description</label>
110
+ <input id="description" type="text" name="description" class="qa-input" placeholder="Brief description of the application" />
111
+ </div>
112
+ <button type="submit" class="qa-btn qa-btn-primary">Create Application</button>
113
+ </form>
114
+ </div>
115
+ </div>
116
+
117
+ <q:if condition="len(apps) &gt; 0">
118
+ <div class="qa-card qa-mb-6">
119
+ <div class="qa-card-body" style="padding: 0;">
120
+ <q:loop type="array" var="proj" items="{apps}">
121
+ <div class="qa-app-card">
122
+ <div class="qa-app-card-icon">{proj.initial}</div>
123
+ <div style="flex: 1; min-width: 0;">
124
+ <div style="display: flex; align-items: center; gap: 8px; margin-bottom: 2px;">
125
+ <a href="/admin/app/{proj.name}" style="font-weight: 600; color: var(--q-text-primary); font-size: 0.9375rem;">{proj.name}</a>
126
+ <span class="{'qa-badge qa-badge-success' if proj.status == 'active' else ('qa-badge qa-badge-danger' if proj.status == 'error' else 'qa-badge qa-badge-gray')}" style="font-size: 0.65rem;">{proj.status}</span>
127
+ <span class="{'qa-process-running' if proj.running else 'qa-process-stopped'}">{'Running' if proj.running else 'Stopped'}</span>
128
+ </div>
129
+ <div style="display: flex; align-items: center; gap: 10px;">
130
+ <span class="qa-font-mono qa-text-xs qa-text-muted">{proj.source_path}</span>
131
+ <span class="qa-text-xs qa-text-muted qa-truncate" style="max-width: 300px;">{proj.description or 'No description'}</span>
132
+ </div>
133
+ </div>
134
+ <div class="qa-app-metrics">
135
+ <div class="qa-app-metric"><span class="qa-app-metric-value">{proj.component_count}</span><span class="qa-app-metric-label">Comps</span></div>
136
+ <div class="qa-app-metric"><span class="qa-app-metric-value">{proj.connector_count}</span><span class="qa-app-metric-label">Conns</span></div>
137
+ <div class="qa-app-metric"><span class="qa-app-metric-value">{proj.port or '-'}</span><span class="qa-app-metric-label">Port</span></div>
138
+ </div>
139
+ <form method="POST" action="/admin/applications" style="flex-shrink: 0; margin: 0;" onsubmit="return confirm('Remove this application record? Files on disk will NOT be deleted.');">
140
+ <input type="hidden" name="action" value="deleteProject" />
141
+ <input type="hidden" name="project_id" value="{proj.id}" />
142
+ <button type="submit" class="qa-btn qa-btn-ghost qa-btn-sm" style="color: var(--q-danger);" title="Remove record" aria-label="Remove {proj.name}">Remove</button>
143
+ </form>
144
+ </div>
145
+ </q:loop>
146
+ </div>
147
+ </div>
148
+ </q:if>
149
+
150
+ <q:if condition="len(apps) == 0">
151
+ <div class="qa-card qa-mb-6">
152
+ <div class="qa-empty">
153
+ <div class="qa-empty-title">{'No Results' if busca else 'No Applications Found'}</div>
154
+ <div class="qa-empty-text">{'No applications match your search.' if busca else 'Use Sync from Disk to discover existing projects, or create one above.'}</div>
155
+ </div>
156
+ </div>
157
+ </q:if>
158
+
159
+ </AdminShell>
160
+ </q:component>
@@ -0,0 +1,205 @@
1
+ <q:component name="AdminComponentDetail" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!--
3
+ Detalhe de um componente: /admin/component/components/loja.q.
4
+ admin.components.get lê; admin.tests.generate e admin.tests.run agem.
5
+ `path` vem da URL também dentro das actions (ROUTE-2) — antes ia num
6
+ campo escondido do formulário. Rodar testes só aceita test_*.py de
7
+ tests/ (a versão anterior rodava pytest em qualquer caminho absoluto), e
8
+ gerar não sobrescreve um teste existente sem o botão Regenerate.
9
+ -->
10
+ <q:import component="AdminShell" from="admin/_layout" />
11
+
12
+ <q:action name="generateTests" method="POST">
13
+ <q:param name="overwrite" type="boolean" default="false" />
14
+ <q:invoke name="gerado" service="admin.tests.generate" onerror="continue">
15
+ <q:param name="comp_path" value="{path}" />
16
+ <q:param name="overwrite" value="{overwrite}" type="boolean" />
17
+ </q:invoke>
18
+ <q:if condition="gerado_result.success">
19
+ <q:redirect url="/admin/component/{path}?tab=tests" flash="{gerado.test_file} {'regenerated' if gerado.overwritten else 'created'}" />
20
+ </q:if>
21
+ <q:flash type="error" message="{gerado_result.error.message}" />
22
+ <q:redirect url="/admin/component/{path}?tab=tests" />
23
+ </q:action>
24
+
25
+ <q:action name="runTests" method="POST">
26
+ <q:invoke name="alvo" service="admin.components.get">
27
+ <q:param name="path" value="{path}" />
28
+ </q:invoke>
29
+ <q:invoke name="execucao" service="admin.tests.run" onerror="continue">
30
+ <q:param name="test_file" value="{alvo.test_file or ''}" />
31
+ </q:invoke>
32
+ <q:if condition="not execucao_result.success">
33
+ <q:flash type="error" message="{execucao_result.error.message}" />
34
+ <q:redirect url="/admin/component/{path}?tab=tests" />
35
+ </q:if>
36
+ <q:if condition="execucao.passed">
37
+ <q:redirect url="/admin/component/{path}?tab=tests" flash="{execucao.summary.passed} passed in {execucao.summary.duration}s" />
38
+ </q:if>
39
+ <q:flash type="error" message="{execucao.summary.failed} failed, {execucao.summary.errors} errors, {execucao.summary.passed} passed" />
40
+ <q:redirect url="/admin/component/{path}?tab=tests" />
41
+ </q:action>
42
+
43
+ <q:set name="aba" value="{query.tab}" />
44
+ <q:invoke name="comp" service="admin.components.get" onerror="continue">
45
+ <q:param name="path" value="{path}" />
46
+ </q:invoke>
47
+
48
+ <AdminShell title="Component" active="components" flash="{flash}" flashType="{flashType}">
49
+
50
+ <q:if condition="not comp_result.success">
51
+ <div class="qa-card">
52
+ <div class="qa-empty">
53
+ <div class="qa-empty-title">Cannot Load Component</div>
54
+ <div class="qa-empty-text">{comp_result.error.message}</div>
55
+ <a href="/admin/components" class="qa-text-sm">Back to Components</a>
56
+ </div>
57
+ </div>
58
+ </q:if>
59
+
60
+ <q:if condition="comp_result.success">
61
+ <div class="qa-flex qa-items-center qa-mb-4" style="gap: 12px; flex-wrap: wrap;">
62
+ <span class="qa-font-medium">{comp.name}</span>
63
+ <span class="qa-font-mono qa-text-sm qa-text-muted">{comp.path}</span>
64
+ <span class="qa-badge qa-badge-primary">{comp.type}</span>
65
+ <a href="/admin/components" class="qa-text-sm">Back to Components</a>
66
+ </div>
67
+
68
+ <q:if condition="aba == 'tests'">
69
+ <input type="radio" name="cdtabs" id="cdtab-general" class="qa-tab-radio" />
70
+ <input type="radio" name="cdtabs" id="cdtab-tests" class="qa-tab-radio" checked="checked" />
71
+ <q:else>
72
+ <input type="radio" name="cdtabs" id="cdtab-general" class="qa-tab-radio" checked="checked" />
73
+ <input type="radio" name="cdtabs" id="cdtab-tests" class="qa-tab-radio" />
74
+ </q:else>
75
+ </q:if>
76
+ <div class="qa-tabs-bar">
77
+ <label for="cdtab-general" class="qa-tab-label">General</label>
78
+ <label for="cdtab-tests" class="qa-tab-label">Tests</label>
79
+ </div>
80
+
81
+ <div class="qa-tabs-content">
82
+ <div class="qa-panel-cd-general">
83
+ <div class="qa-card qa-mb-6">
84
+ <div class="qa-card-header"><div class="qa-card-title">Metadata</div></div>
85
+ <div class="qa-card-body">
86
+ <div class="qa-grid qa-grid-3" style="gap: 20px;">
87
+ <div><div class="qa-text-xs qa-text-muted">Size</div><div class="qa-text-sm">{comp.size}</div></div>
88
+ <div><div class="qa-text-xs qa-text-muted">Lines</div><div class="qa-text-sm">{comp.lines}</div></div>
89
+ <div><div class="qa-text-xs qa-text-muted">Last Modified</div><div class="qa-text-sm">{comp.modified}</div></div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+
94
+ <q:if condition="len(comp.actions) &gt; 0">
95
+ <div class="qa-card qa-mb-6">
96
+ <div class="qa-card-header"><div class="qa-card-title">Actions</div></div>
97
+ <div class="qa-card-body">
98
+ <div class="qa-flex" style="flex-wrap: wrap; gap: 8px;">
99
+ <q:loop type="array" var="acao" items="{comp.actions}">
100
+ <span class="qa-badge qa-badge-info qa-font-mono">{acao}</span>
101
+ </q:loop>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </q:if>
106
+
107
+ <q:if condition="len(comp.queries) &gt; 0">
108
+ <div class="qa-card qa-mb-6">
109
+ <div class="qa-card-header"><div class="qa-card-title">Queries</div></div>
110
+ <div class="qa-card-body">
111
+ <div class="qa-flex" style="flex-wrap: wrap; gap: 8px;">
112
+ <q:loop type="array" var="consulta" items="{comp.queries}">
113
+ <span class="qa-badge qa-badge-info qa-font-mono">{consulta}</span>
114
+ </q:loop>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ </q:if>
119
+
120
+ <q:if condition="len(comp.feature_tags) &gt; 0">
121
+ <div class="qa-card qa-mb-6">
122
+ <div class="qa-card-header"><div class="qa-card-title">Tags Used</div></div>
123
+ <div class="qa-card-body">
124
+ <div class="qa-flex" style="flex-wrap: wrap; gap: 8px;">
125
+ <q:loop type="array" var="tag" items="{comp.feature_tags}">
126
+ <span class="qa-badge qa-badge-primary">q:{tag}</span>
127
+ </q:loop>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ </q:if>
132
+
133
+ <a href="/admin/source?file={comp.path}" class="qa-text-sm">View Full Source</a>
134
+ </div>
135
+
136
+ <div class="qa-panel-cd-tests">
137
+ <div class="qa-card qa-mb-6">
138
+ <div class="qa-card-header">
139
+ <div>
140
+ <div class="qa-card-title">Tests</div>
141
+ <div class="qa-card-subtitle qa-font-mono">{comp.test_file or 'no test file yet'}</div>
142
+ </div>
143
+ <div class="qa-flex qa-items-center" style="gap: 8px;">
144
+ <q:if condition="comp.test_file">
145
+ <form method="POST" action="/admin/component/{comp.path}" style="margin: 0;"
146
+ onsubmit="return confirm('Replace the test file? Changes made by hand will be lost.');">
147
+ <input type="hidden" name="action" value="generateTests" />
148
+ <input type="hidden" name="overwrite" value="true" />
149
+ <button type="submit" class="qa-btn qa-btn-ghost qa-btn-sm">Regenerate</button>
150
+ </form>
151
+ <form method="POST" action="/admin/component/{comp.path}" style="margin: 0;">
152
+ <input type="hidden" name="action" value="runTests" />
153
+ <button type="submit" class="qa-btn qa-btn-primary qa-btn-sm">Run Tests</button>
154
+ </form>
155
+ <q:else>
156
+ <form method="POST" action="/admin/component/{comp.path}" style="margin: 0;">
157
+ <input type="hidden" name="action" value="generateTests" />
158
+ <button type="submit" class="qa-btn qa-btn-primary qa-btn-sm">Generate Tests</button>
159
+ </form>
160
+ </q:else>
161
+ </q:if>
162
+ </div>
163
+ </div>
164
+ </div>
165
+
166
+ <q:if condition="comp.last_run">
167
+ <div class="qa-grid qa-grid-4 qa-mb-6">
168
+ <div class="qa-stat-card"><div class="qa-stat-label">Passed</div><div class="qa-stat-value" style="color: var(--q-success);">{comp.last_run.summary.passed}</div></div>
169
+ <div class="qa-stat-card"><div class="qa-stat-label">Failed</div><div class="qa-stat-value" style="color: var(--q-danger);">{comp.last_run.summary.failed + comp.last_run.summary.errors}</div></div>
170
+ <div class="qa-stat-card"><div class="qa-stat-label">Skipped</div><div class="qa-stat-value" style="color: var(--q-warning);">{comp.last_run.summary.skipped}</div></div>
171
+ <div class="qa-stat-card"><div class="qa-stat-label">Ran at</div><div class="qa-text-sm">{comp.last_run.ran_at}</div></div>
172
+ </div>
173
+ </q:if>
174
+
175
+ <q:if condition="len(comp.test_status) &gt; 0">
176
+ <div class="qa-card qa-mb-6">
177
+ <div class="qa-card-body qa-p-0">
178
+ <table class="qa-table">
179
+ <thead><tr><th style="width: 110px;">Status</th><th>Test</th></tr></thead>
180
+ <tbody>
181
+ <q:loop type="array" var="caso" items="{comp.test_status}">
182
+ <tr>
183
+ <td><span class="{'qa-badge qa-badge-success' if caso.status == 'PASSED' else ('qa-badge qa-badge-danger' if caso.status in ['FAILED', 'ERROR'] else 'qa-badge qa-badge-gray')}">{caso.status}</span></td>
184
+ <td><span class="qa-font-mono qa-text-sm">{caso.name}</span></td>
185
+ </tr>
186
+ </q:loop>
187
+ </tbody>
188
+ </table>
189
+ </div>
190
+ </div>
191
+ <a href="/admin/source?file={comp.test_file}" class="qa-text-sm">View test source</a>
192
+ </q:if>
193
+
194
+ <q:if condition="comp.last_run">
195
+ <details class="qa-card qa-mb-6">
196
+ <summary class="qa-text-sm" style="padding: 12px 16px; cursor: pointer;">Raw pytest output</summary>
197
+ <pre class="qa-log-viewer">{comp.last_run.output}</pre>
198
+ </details>
199
+ </q:if>
200
+ </div>
201
+ </div>
202
+ </q:if>
203
+
204
+ </AdminShell>
205
+ </q:component>
@@ -0,0 +1,59 @@
1
+ <q:component name="AdminComponents" require_auth="true" require_role="admin" login_url="/admin/login">
2
+ <!-- Os .q de components/ (admin.components.list). -->
3
+ <q:import component="AdminShell" from="admin/_layout" />
4
+
5
+ <q:invoke name="lista" service="admin.components.list" />
6
+
7
+ <AdminShell title="Components" active="components" flash="{flash}" flashType="{flashType}">
8
+
9
+ <div class="qa-grid qa-grid-3 qa-mb-6">
10
+ <div class="qa-stat-card">
11
+ <div class="qa-stat-label">Total Components</div>
12
+ <div class="qa-stat-value">{len(lista.components)}</div>
13
+ <div class="qa-stat-change"><span class="qa-text-muted">.q files in components/</span></div>
14
+ </div>
15
+ <div class="qa-stat-card">
16
+ <div class="qa-stat-label">Directories</div>
17
+ <div class="qa-stat-value">{lista.directories}</div>
18
+ <div class="qa-stat-change"><span class="qa-text-muted">component groups</span></div>
19
+ </div>
20
+ <div class="qa-stat-card">
21
+ <div class="qa-stat-label">Examples</div>
22
+ <div class="qa-stat-value">{lista.examples}</div>
23
+ <div class="qa-stat-change"><span class="qa-text-muted">.q files in examples/</span></div>
24
+ </div>
25
+ </div>
26
+
27
+ <q:if condition="len(lista.components) &gt; 0">
28
+ <div class="qa-card">
29
+ <div class="qa-card-body qa-p-0" style="overflow-x: auto;">
30
+ <table class="qa-table">
31
+ <thead><tr><th>Path</th><th>Lines</th><th>Size</th><th>Group</th><th>Tags</th><th></th></tr></thead>
32
+ <tbody>
33
+ <q:loop type="array" var="comp" items="{lista.components}">
34
+ <tr>
35
+ <td><a class="qa-font-mono" href="/admin/component/components/{comp.path}">{comp.path}</a></td>
36
+ <td style="font-variant-numeric: tabular-nums;">{comp.lines}</td>
37
+ <td>{comp.size}</td>
38
+ <td><span class="qa-badge qa-badge-info">{comp.group}</span></td>
39
+ <td><span class="qa-text-sm qa-text-muted">{join(comp.feature_tags, ', ') if comp.feature_tags else '-'}</span></td>
40
+ <td><a href="/admin/source?file=components/{comp.path}" class="qa-text-sm">Source</a></td>
41
+ </tr>
42
+ </q:loop>
43
+ </tbody>
44
+ </table>
45
+ </div>
46
+ </div>
47
+ </q:if>
48
+
49
+ <q:if condition="len(lista.components) == 0">
50
+ <div class="qa-card">
51
+ <div class="qa-empty">
52
+ <div class="qa-empty-title">No Components</div>
53
+ <div class="qa-empty-text">There is no .q file under components/ in the project root.</div>
54
+ </div>
55
+ </div>
56
+ </q:if>
57
+
58
+ </AdminShell>
59
+ </q:component>