zrb 1.0.0a16__py3-none-any.whl → 1.0.0a20__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 (196) hide show
  1. zrb/__init__.py +5 -0
  2. zrb/__main__.py +3 -0
  3. zrb/builtin/__init__.py +2 -2
  4. zrb/builtin/git.py +10 -2
  5. zrb/builtin/git_subtree.py +4 -0
  6. zrb/builtin/llm/tool/rag.py +2 -2
  7. zrb/builtin/project/add/fastapp/fastapp_input.py +16 -0
  8. zrb/builtin/project/add/fastapp/fastapp_task.py +78 -0
  9. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.flake8 +3 -0
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/create_column_task.py +14 -0
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +128 -0
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +213 -0
  13. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +27 -0
  14. zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/my_entity_usecase.py +9 -10
  15. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/factory.py +13 -0
  16. zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/repository/my_entity_db_repository.py +14 -9
  17. zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/repository/my_entity_repository.py +6 -7
  18. zrb/builtin/project/add/{fastapp_template/_zrb/entity/schema.template.py → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py} +8 -0
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +17 -0
  20. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/input.py +1 -4
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +85 -0
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +154 -0
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/any_client.py +7 -0
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +6 -0
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +6 -0
  26. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +9 -0
  27. zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/env.py +2 -4
  28. zrb/builtin/project/add/{fastapp_template/module/auth → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/script.py.mako +1 -0
  29. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +33 -0
  30. zrb/builtin/project/add/{fastapp_template/_zrb/main.py → fastapp/fastapp_template/my_app_name/_zrb/task.py} +12 -14
  31. zrb/builtin/project/add/{fastapp_template/_zrb/helper.py → fastapp/fastapp_template/my_app_name/_zrb/util.py} +1 -1
  32. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/venv_task.py +1 -1
  33. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/app.py +2 -2
  34. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/base_db_repository.py +1 -1
  35. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/base_usecase.py +19 -6
  36. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/db_engine.py +1 -1
  37. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/config.py +1 -0
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +7 -0
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/migrate.py +3 -0
  40. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/client/any_client.py +10 -4
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +7 -0
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +6 -0
  43. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +9 -0
  44. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration/env.py +2 -4
  45. zrb/builtin/project/add/{fastapp_template/module/gateway → fastapp/fastapp_template/my_app_name/module/auth}/migration/script.py.mako +1 -0
  46. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration_metadata.py +1 -1
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +37 -0
  48. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/repository/user_db_repository.py +13 -7
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +42 -0
  50. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +13 -0
  51. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/user_usecase.py +13 -12
  52. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +6 -0
  53. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration/env.py +2 -4
  54. zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/module/gateway}/migration/script.py.mako +1 -0
  55. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +37 -0
  56. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +44 -0
  57. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/requirements.txt +1 -1
  58. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/permission.py +8 -0
  59. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/role.py +8 -0
  60. zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/user.py +8 -0
  61. zrb/builtin/project/add/fastapp/fastapp_util.py +46 -0
  62. zrb/builtin/project/create/{create.py → project_task.py} +1 -1
  63. zrb/builtin/python.py +4 -1
  64. zrb/builtin/setup/asdf/asdf_helper.py +4 -8
  65. zrb/builtin/setup/tmux/tmux.py +7 -12
  66. zrb/builtin/todo.py +42 -26
  67. zrb/callback/callback.py +0 -1
  68. zrb/cmd/cmd_val.py +2 -2
  69. zrb/config.py +18 -0
  70. zrb/content_transformer/content_transformer.py +8 -7
  71. zrb/context/any_context.py +6 -6
  72. zrb/group/group.py +0 -1
  73. zrb/input/any_input.py +4 -0
  74. zrb/input/base_input.py +17 -5
  75. zrb/input/bool_input.py +1 -1
  76. zrb/input/float_input.py +2 -2
  77. zrb/input/int_input.py +1 -1
  78. zrb/input/option_input.py +2 -2
  79. zrb/input/password_input.py +2 -2
  80. zrb/input/text_input.py +6 -6
  81. zrb/runner/cli.py +9 -35
  82. zrb/runner/common_util.py +31 -0
  83. zrb/runner/web_app.py +169 -46
  84. zrb/runner/web_config.py +288 -0
  85. zrb/runner/web_controller/error_page/controller.py +27 -0
  86. zrb/runner/web_controller/error_page/view.html +33 -0
  87. zrb/runner/web_controller/group_info_page/controller.py +40 -0
  88. zrb/runner/web_controller/group_info_page/view.html +36 -0
  89. zrb/runner/web_controller/home_page/controller.py +14 -57
  90. zrb/runner/web_controller/home_page/view.html +29 -20
  91. zrb/runner/web_controller/login_page/controller.py +25 -0
  92. zrb/runner/web_controller/login_page/view.html +50 -0
  93. zrb/runner/web_controller/logout_page/controller.py +26 -0
  94. zrb/runner/web_controller/logout_page/view.html +40 -0
  95. zrb/runner/web_controller/{task_ui → session_page}/controller.py +36 -34
  96. zrb/runner/web_controller/{task_ui → session_page}/partial/input.html +1 -1
  97. zrb/runner/web_controller/session_page/view.html +91 -0
  98. zrb/runner/web_controller/static/common.css +11 -0
  99. zrb/runner/web_controller/static/login/event.js +33 -0
  100. zrb/runner/web_controller/static/logout/event.js +20 -0
  101. zrb/runner/web_controller/static/pico.min.css +1 -1
  102. zrb/runner/web_controller/static/session/common-util.js +63 -0
  103. zrb/runner/web_controller/static/session/current-session.js +164 -0
  104. zrb/runner/web_controller/static/session/event.js +120 -0
  105. zrb/runner/web_controller/static/session/past-session.js +138 -0
  106. zrb/runner/web_util.py +53 -0
  107. zrb/session_state_logger/any_session_state_logger.py +0 -1
  108. zrb/session_state_logger/file_session_state_logger.py +4 -8
  109. zrb/task/base_trigger.py +0 -1
  110. zrb/task/cmd_task.py +1 -1
  111. zrb/task/llm_task.py +3 -6
  112. zrb/task/make_task.py +0 -1
  113. zrb/task/scaffolder.py +18 -4
  114. zrb/task/scheduler.py +0 -1
  115. zrb/util/cmd/command.py +0 -1
  116. zrb/util/codemod/{add_code_to_class.py → append_code_to_class.py} +4 -4
  117. zrb/util/codemod/{add_code_to_function.py → append_code_to_function.py} +5 -3
  118. zrb/util/codemod/{add_code_to_method.py → append_code_to_method.py} +3 -3
  119. zrb/util/codemod/{add_key_to_dict.py → append_key_to_dict.py} +1 -1
  120. zrb/util/codemod/{add_param_to_function_call.py → append_param_to_function_call.py} +1 -1
  121. zrb/util/codemod/{add_code_to_module.py → prepend_code_to_module.py} +2 -2
  122. zrb/util/codemod/{add_parent_to_class.py → prepend_parent_to_class.py} +1 -1
  123. zrb/util/codemod/{add_property_to_class.py → prepend_property_to_class.py} +1 -1
  124. zrb/util/file.py +18 -0
  125. zrb/util/git_subtree.py +3 -4
  126. zrb/util/todo.py +105 -24
  127. zrb/xcom/xcom.py +0 -1
  128. {zrb-1.0.0a16.dist-info → zrb-1.0.0a20.dist-info}/METADATA +3 -2
  129. zrb-1.0.0a20.dist-info/RECORD +243 -0
  130. zrb/builtin/project/add/fastapp.py +0 -87
  131. zrb/builtin/project/add/fastapp_template/_zrb/column/create_column_task.py +0 -11
  132. zrb/builtin/project/add/fastapp_template/_zrb/entity/create_entity_task.py +0 -196
  133. zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/factory.py +0 -13
  134. zrb/builtin/project/add/fastapp_template/_zrb/module/create_module_task.py +0 -136
  135. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/any_client.py +0 -27
  136. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/api_client.py +0 -6
  137. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/direct_client.py +0 -6
  138. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/factory.py +0 -9
  139. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/route.py +0 -19
  140. zrb/builtin/project/add/fastapp_template/main.py +0 -7
  141. zrb/builtin/project/add/fastapp_template/migrate.py +0 -3
  142. zrb/builtin/project/add/fastapp_template/module/auth/client/api_client.py +0 -7
  143. zrb/builtin/project/add/fastapp_template/module/auth/client/direct_client.py +0 -6
  144. zrb/builtin/project/add/fastapp_template/module/auth/client/factory.py +0 -9
  145. zrb/builtin/project/add/fastapp_template/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
  146. zrb/builtin/project/add/fastapp_template/module/auth/route.py +0 -22
  147. zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/factory.py +0 -13
  148. zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/user_repository.py +0 -34
  149. zrb/builtin/project/add/fastapp_template/module/gateway/route.py +0 -27
  150. zrb/runner/web_controller/group_info_ui/controller.py +0 -91
  151. zrb/runner/web_controller/group_info_ui/partial/group_info.html +0 -2
  152. zrb/runner/web_controller/group_info_ui/partial/group_li.html +0 -1
  153. zrb/runner/web_controller/group_info_ui/partial/task_info.html +0 -2
  154. zrb/runner/web_controller/group_info_ui/partial/task_li.html +0 -1
  155. zrb/runner/web_controller/group_info_ui/view.html +0 -31
  156. zrb/runner/web_controller/home_page/partial/group_info.html +0 -2
  157. zrb/runner/web_controller/home_page/partial/group_li.html +0 -1
  158. zrb/runner/web_controller/home_page/partial/task_info.html +0 -2
  159. zrb/runner/web_controller/home_page/partial/task_li.html +0 -1
  160. zrb/runner/web_controller/task_ui/partial/common-util.js +0 -37
  161. zrb/runner/web_controller/task_ui/partial/main.js +0 -195
  162. zrb/runner/web_controller/task_ui/partial/show-existing-session.js +0 -97
  163. zrb/runner/web_controller/task_ui/partial/visualize-history.js +0 -104
  164. zrb/runner/web_controller/task_ui/view.html +0 -87
  165. zrb-1.0.0a16.dist-info/RECORD +0 -231
  166. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/.gitignore +0 -0
  167. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/README.md +0 -0
  168. /zrb/builtin/project/add/{__init__.py → fastapp/fastapp_template/my_app_name/__init__.py} +0 -0
  169. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/config.py +0 -0
  170. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/group.py +0 -0
  171. /zrb/builtin/project/add/{fastapp_template/__init__.py → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py} +0 -0
  172. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/alembic.ini +0 -0
  173. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/README +0 -0
  174. /zrb/builtin/project/add/{fastapp_template/module/gateway → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/versions/.gitkeep +0 -0
  175. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration_metadata.py +0 -0
  176. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/service/__init__.py +0 -0
  177. /zrb/builtin/project/add/{fastapp_template/_zrb/module/run_module.template.py → fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py} +0 -0
  178. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/__init__.py +0 -0
  179. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/error.py +0 -0
  180. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/schema.py +0 -0
  181. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/__init__.py +0 -0
  182. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/alembic.ini +0 -0
  183. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration/README +0 -0
  184. /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/module/auth}/migration/versions/3093c7336477_add_user_table.py +0 -0
  185. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/__init__.py +0 -0
  186. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/__init__.py +0 -0
  187. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/alembic.ini +0 -0
  188. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration/README +0 -0
  189. /zrb/builtin/project/add/{fastapp_template/module/auth/service/user/repository/__init__.py → fastapp/fastapp_template/my_app_name/module/gateway/migration/versions/.gitkeep} +0 -0
  190. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration_metadata.py +0 -0
  191. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/__init__.py +0 -0
  192. /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/template.env +0 -0
  193. /zrb/runner/web_controller/{group_info_ui → group_info_page}/__init__.py +0 -0
  194. /zrb/runner/web_controller/{task_ui → session_page}/__init__.py +0 -0
  195. {zrb-1.0.0a16.dist-info → zrb-1.0.0a20.dist-info}/WHEEL +0 -0
  196. {zrb-1.0.0a16.dist-info → zrb-1.0.0a20.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,120 @@
1
+ window.addEventListener("load", async function () {
2
+ // Get current session
3
+ if (cfg.SESSION_NAME != "") {
4
+ CURRENT_SESSION.pollCurrentSession();
5
+ }
6
+ // set maxStartDate to today
7
+ const tomorrow = new Date();
8
+ tomorrow.setDate(tomorrow.getDate() + 1); // Move to the next day
9
+ tomorrow.setHours(0, 0, 0, 0);
10
+ const formattedTomorrow = UTIL.toLocalDateInputValue(tomorrow);
11
+ const maxStartAtInput = document.getElementById("max-start-at-input");
12
+ maxStartAtInput.value = formattedTomorrow;
13
+ // set minStartDate to yesterday
14
+ const today = new Date();
15
+ today.setHours(0, 0, 0, 0); // Set time to 00:00:00
16
+ const formattedToday = UTIL.toLocalDateInputValue(today);
17
+ const minStartAtInput = document.getElementById("min-start-at-input");
18
+ minStartAtInput.value = formattedToday;
19
+ // Update session
20
+ PAST_SESSION.pollPastSession();
21
+ });
22
+
23
+
24
+ const submitTaskForm = document.getElementById("submit-task-form");
25
+ submitTaskForm.addEventListener("input", async function(event) {
26
+ const currentInput = event.target;
27
+ const inputs = Array.from(submitTaskForm.querySelectorAll("input[name]"));
28
+ const inputMap = {};
29
+ const fixedInputNames = [];
30
+ for (const input of inputs) {
31
+ fixedInputNames.push(input.name);
32
+ if (input === currentInput) {
33
+ inputMap[input.name] = currentInput.value;
34
+ break;
35
+ } else {
36
+ inputMap[input.name] = input.value;
37
+ }
38
+ }
39
+ const queryString = new URLSearchParams(
40
+ {query: JSON.stringify(inputMap)}
41
+ ).toString();
42
+ try {
43
+ // Send the AJAX request
44
+ const response = await fetch(`${cfg.INPUT_API_URL}?${queryString}`, {
45
+ method: "GET",
46
+ headers: {
47
+ "Content-Type": "application/json"
48
+ },
49
+ });
50
+ if (response.ok) {
51
+ const data = await response.json();
52
+ // Update the values of all subsequent inputs based on the response
53
+ Object.entries(data).forEach(([key, value]) => {
54
+ if (fixedInputNames.includes(key)) {
55
+ return;
56
+ }
57
+ const input = submitTaskForm.querySelector(`[name="${key}"]`);
58
+ input.value = value;
59
+ });
60
+ } else {
61
+ console.error("Failed to fetch updated values:", response.statusText);
62
+ }
63
+ } catch (error) {
64
+ console.error("Error during fetch:", error);
65
+ }
66
+ })
67
+
68
+
69
+ function openPastSessionDialog(event) {
70
+ event.preventDefault();
71
+ const dialog = document.getElementById("past-session-dialog")
72
+ dialog.showModal();
73
+ }
74
+
75
+
76
+ function closePastSessionDialog(event) {
77
+ event.preventDefault();
78
+ const dialog = document.getElementById("past-session-dialog")
79
+ dialog.close();
80
+ }
81
+
82
+
83
+ async function submitNewSessionForm(event) {
84
+ // Prevent the form from submitting the traditional way
85
+ event.preventDefault();
86
+ // Select the form
87
+ const form = document.getElementById("submit-task-form");
88
+ // Initialize an empty object to hold form data
89
+ const formData = {};
90
+ // Iterate through each input in the form
91
+ Array.from(form.elements).forEach(element => {
92
+ // Only include inputs with a name attribute and ignore buttons
93
+ if (element.name && (element.type !== "button" && element.type !== "submit")) {
94
+ formData[element.name] = element.value;
95
+ }
96
+ });
97
+ // Convert formData to JSON
98
+ const jsonData = JSON.stringify(formData);
99
+ try {
100
+ // Send the AJAX request
101
+ const response = await fetch(cfg.SESSION_API_URL, {
102
+ method: "POST",
103
+ headers: {
104
+ "Content-Type": "application/json"
105
+ },
106
+ body: jsonData
107
+ });
108
+ if (response.ok) {
109
+ const data = await response.json();
110
+ cfg.SESSION_NAME = data.session_name;
111
+ history.pushState(null, "", `${cfg.CURRENT_URL}${cfg.SESSION_NAME}`);
112
+ await PAST_SESSION.getAndRenderPastSession(0);
113
+ await CURRENT_SESSION.pollCurrentSession();
114
+ } else {
115
+ console.error("Error:", response);
116
+ }
117
+ } catch (error) {
118
+ console.error("Error:", error);
119
+ }
120
+ }
@@ -0,0 +1,138 @@
1
+ const PAST_SESSION = {
2
+
3
+ async pollPastSession() {
4
+ while (true) {
5
+ await this.getAndRenderPastSession(cfg.PAGE);
6
+ await UTIL.delay(5000);
7
+ }
8
+ },
9
+
10
+ async getAndRenderPastSession(page) {
11
+ cfg.PAGE=page
12
+ const minStartAtInput = document.getElementById("min-start-at-input");
13
+ const minStartAt = UTIL.formatDate(minStartAtInput.value);
14
+ const maxStartAtInput = document.getElementById("max-start-at-input");
15
+ const maxStartAt = UTIL.formatDate(maxStartAtInput.value);
16
+ const queryString = new URLSearchParams({
17
+ page: page,
18
+ from: minStartAt,
19
+ to: maxStartAt,
20
+ }).toString();
21
+ try {
22
+ // Send the AJAX request
23
+ const response = await fetch(`${cfg.SESSION_API_URL}list?${queryString}`, {
24
+ method: "GET",
25
+ headers: {
26
+ "Content-Type": "application/json"
27
+ },
28
+ });
29
+ if (response.ok) {
30
+ const {total, data} = await response.json();
31
+ this.showPastSession(page, total, data);
32
+ } else {
33
+ console.error("Error:", response);
34
+ }
35
+ } catch (error) {
36
+ console.error("Error:", error);
37
+ }
38
+ },
39
+
40
+ showPastSession(page, total, data) {
41
+ const ul = document.getElementById("past-session-ul");
42
+ ul.innerHTML = ''; // Clear existing content
43
+ data.forEach(item => {
44
+ const taskStatus = item.task_status[item.main_task_name];
45
+ const finalStatus = UTIL.getFinalTaskStatus(taskStatus);
46
+ const finalColor = UTIL.getFinalColor(finalStatus);
47
+ const taskHistories = taskStatus.history;
48
+ const taskStartTime = taskHistories.length > 0 ? taskHistories[0].time : ""
49
+ const li = document.createElement('li');
50
+ const a = document.createElement('a');
51
+ const dateSpan = document.createElement('span');
52
+ const statusSpan = document.createElement('span');
53
+ a.textContent = item.name;
54
+ a.target = '_blank';
55
+ a.href = `${cfg.UI_URL}${item.name}`;
56
+ li.appendChild(a);
57
+ statusSpan.style.marginLeft = "10px";
58
+ statusSpan.style.display = 'inline-block';
59
+ statusSpan.style.width = '15px';
60
+ statusSpan.style.height = '15px';
61
+ statusSpan.style.borderRadius = '50%';
62
+ statusSpan.style.border = '2px solid black';
63
+ statusSpan.style.backgroundColor = finalColor;
64
+ li.appendChild(statusSpan);
65
+ dateSpan.style.marginLeft = "10px";
66
+ dateSpan.textContent = taskStartTime;
67
+ li.appendChild(dateSpan);
68
+ ul.appendChild(li);
69
+ });
70
+ const paginationUl = document.getElementById("past-session-pagination-ul");
71
+ paginationUl.innerHTML = ''; // Clear previous pagination
72
+
73
+ const totalPages = Math.ceil(total / 10); // Calculate total pages based on page size
74
+ const maxPagesToShow = 5; // Number of pages to display around the current page
75
+ const halfMaxPages = Math.floor(maxPagesToShow / 2);
76
+
77
+ // Add first page and previous controls
78
+ if (page > 0) {
79
+ paginationUl.appendChild(this.createPageLink("⟪", 0)); // Go to first page
80
+ paginationUl.appendChild(this.createPageLink("⟨", page - 1)); // Go to previous page
81
+ }
82
+
83
+ let startPage = Math.max(0, page - halfMaxPages);
84
+ let endPage = Math.min(totalPages - 1, page + halfMaxPages);
85
+
86
+ if (page <= halfMaxPages) {
87
+ endPage = Math.min(totalPages - 1, maxPagesToShow - 1);
88
+ } else if (page + halfMaxPages >= totalPages) {
89
+ startPage = Math.max(0, totalPages - maxPagesToShow);
90
+ }
91
+
92
+ if (startPage > 1) {
93
+ paginationUl.appendChild(this.createEllipsis());
94
+ }
95
+
96
+ // Add page links within the calculated range
97
+ for (let i = startPage; i <= endPage; i++) {
98
+ if (i === page) {
99
+ const pageLi = document.createElement('li');
100
+ pageLi.textContent = i + 1;
101
+ paginationUl.append(pageLi)
102
+ } else {
103
+ paginationUl.appendChild(this.createPageLink(i + 1, i))
104
+ }
105
+ }
106
+
107
+ // Add ellipsis after the end page if needed
108
+ if (endPage < totalPages - 2) {
109
+ paginationUl.appendChild(this.createEllipsis());
110
+ }
111
+
112
+ // Add next and last page controls
113
+ if (page < totalPages - 1) {
114
+ paginationUl.appendChild(this.createPageLink("⟩", page + 1)); // Go to next page
115
+ paginationUl.appendChild(this.createPageLink("⟫", totalPages - 1)); // Go to last page
116
+ }
117
+ },
118
+
119
+ createPageLink(text, page) {
120
+ const li = document.createElement('li');
121
+ const link = document.createElement('a');
122
+ link.textContent = text;
123
+ link.href = '#';
124
+ link.onclick = (e) => {
125
+ e.preventDefault();
126
+ this.getAndRenderPastSession(page);
127
+ };
128
+ li.appendChild(link);
129
+ return li;
130
+ },
131
+
132
+ createEllipsis() {
133
+ const li = document.createElement('li');
134
+ li.textContent = '...';
135
+ return li;
136
+ },
137
+
138
+ }
zrb/runner/web_util.py CHANGED
@@ -1,5 +1,10 @@
1
1
  from pydantic import BaseModel
2
2
 
3
+ from zrb.group.any_group import AnyGroup
4
+ from zrb.runner.web_config import User
5
+ from zrb.task.any_task import AnyTask
6
+ from zrb.util.group import get_non_empty_subgroups, get_subtasks
7
+
3
8
 
4
9
  class NewSessionResponse(BaseModel):
5
10
  session_name: str
@@ -14,3 +19,51 @@ def node_path_to_url(args: list[str]) -> str:
14
19
  pruned_args = [part for part in args if part.strip() != ""]
15
20
  stripped_url = "/".join(pruned_args)
16
21
  return f"/{stripped_url}/"
22
+
23
+
24
+ def get_html_auth_link(user: User) -> str:
25
+ if user.is_guest and user.is_super_admin:
26
+ return f"Hi, {user.username}"
27
+ if user.is_guest:
28
+ return f'Hi, {user.username} <a href="/login">Login 🔑</a>'
29
+ return f'Hi, {user.username} <a href="/logout">Logout 🚪</a>'
30
+
31
+
32
+ def get_html_subtask_info(user: User, parent_url: str, parent_group: AnyGroup) -> str:
33
+ subtasks = get_subtasks(parent_group, web_only=True)
34
+ task_li = "\n".join(
35
+ [
36
+ get_html_task_li(parent_url, alias, subtask)
37
+ for alias, subtask in subtasks.items()
38
+ if user.can_access_task(subtask)
39
+ ]
40
+ )
41
+ if task_li.strip() == "":
42
+ return ""
43
+ return f"<h5>Tasks</h5><ul>{task_li}</ul>"
44
+
45
+
46
+ def get_html_task_li(parent_url: str, alias: str, task: AnyTask) -> str:
47
+ if not parent_url.endswith("/"):
48
+ parent_url += "/"
49
+ return f'<li><a href="{parent_url}{alias}">{alias}</a> {task.description}</li>'
50
+
51
+
52
+ def get_html_subgroup_info(user: User, parent_url: str, parent_group: AnyGroup) -> str:
53
+ subgroups = get_non_empty_subgroups(parent_group, web_only=True)
54
+ group_li = "\n".join(
55
+ [
56
+ get_html_group_li(parent_url, alias, subgroup)
57
+ for alias, subgroup in subgroups.items()
58
+ if user.can_access_group(subgroup)
59
+ ]
60
+ )
61
+ if group_li.strip() == "":
62
+ return ""
63
+ return f"<h5>Groups</h5><ul>{group_li}</ul>"
64
+
65
+
66
+ def get_html_group_li(parent_url: str, alias: str, group: AnyGroup) -> str:
67
+ if not parent_url.endswith("/"):
68
+ parent_url += "/"
69
+ return f'<li><a href="{parent_url}{alias}">{alias}</a> {group.description}</li>'
@@ -5,7 +5,6 @@ from zrb.session_state_log.session_state_log import SessionStateLog, SessionStat
5
5
 
6
6
 
7
7
  class AnySessionStateLogger(ABC):
8
-
9
8
  @abstractmethod
10
9
  def write(self, session_log: SessionStateLog):
11
10
  pass
@@ -3,10 +3,10 @@ import os
3
3
 
4
4
  from zrb.session_state_log.session_state_log import SessionStateLog, SessionStateLogList
5
5
  from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
6
+ from zrb.util.file import read_file, write_file
6
7
 
7
8
 
8
9
  class FileSessionStateLogger(AnySessionStateLogger):
9
-
10
10
  def __init__(self, session_log_dir: str):
11
11
  self._session_log_dir = session_log_dir
12
12
 
@@ -15,20 +15,16 @@ class FileSessionStateLogger(AnySessionStateLogger):
15
15
  session_dir_path = os.path.dirname(session_file_path)
16
16
  if not os.path.isdir(session_dir_path):
17
17
  os.makedirs(session_dir_path, exist_ok=True)
18
- with open(session_file_path, "w") as f:
19
- f.write(session_log.model_dump_json())
18
+ write_file(session_file_path, session_log.model_dump_json())
20
19
  start_time = session_log.start_time
21
20
  if start_time == "":
22
21
  return
23
22
  timeline_dir_path = self._get_timeline_dir_path(session_log)
24
- os.makedirs(timeline_dir_path, exist_ok=True)
25
- with open(os.path.join(timeline_dir_path, session_log.name), "w"):
26
- pass
23
+ write_file(os.path.join(timeline_dir_path, session_log.name), "")
27
24
 
28
25
  def read(self, session_name: str) -> SessionStateLog:
29
26
  session_file_path = self._get_session_file_path(session_name)
30
- with open(session_file_path, "r") as f:
31
- return SessionStateLog.model_validate_json(f.read())
27
+ return SessionStateLog.model_validate_json(read_file(session_file_path))
32
28
 
33
29
  def list(
34
30
  self,
zrb/task/base_trigger.py CHANGED
@@ -19,7 +19,6 @@ from zrb.xcom.xcom import Xcom
19
19
 
20
20
 
21
21
  class BaseTrigger(BaseTask):
22
-
23
22
  def __init__(
24
23
  self,
25
24
  name: str,
zrb/task/cmd_task.py CHANGED
@@ -132,7 +132,7 @@ class CmdTask(BaseTask):
132
132
  if return_code != 0:
133
133
  ctx.log_error(f"Exit status: {return_code}")
134
134
  raise Exception(
135
- f"Process {self._name} exited ({return_code}): {cmd_result.stderr}"
135
+ f"Process {self._name} exited ({return_code}): {cmd_result.error}"
136
136
  )
137
137
  ctx.log_info(f"Exit status: {return_code}")
138
138
  return cmd_result
zrb/task/llm_task.py CHANGED
@@ -15,6 +15,7 @@ from zrb.task.any_task import AnyTask
15
15
  from zrb.task.base_task import BaseTask
16
16
  from zrb.util.attr import get_str_attr
17
17
  from zrb.util.cli.style import stylize_faint
18
+ from zrb.util.file import read_file, write_file
18
19
  from zrb.util.llm.tool import callable_to_tool_schema
19
20
 
20
21
  ListOfDict = list[dict[str, Any]]
@@ -32,7 +33,6 @@ def scratchpad(thought: str) -> str:
32
33
 
33
34
 
34
35
  class LLMTask(BaseTask):
35
-
36
36
  def __init__(
37
37
  self,
38
38
  name: str,
@@ -171,9 +171,7 @@ class LLMTask(BaseTask):
171
171
  messages.append(tool_call_message)
172
172
  continue
173
173
  if history_file != "":
174
- os.makedirs(os.path.dirname(history_file), exist_ok=True)
175
- with open(history_file, "w") as f:
176
- f.write(json.dumps(messages, indent=2))
174
+ write_file(history_file, json.dumps(messages, indent=2))
177
175
  return response_message.content
178
176
 
179
177
  def _get_model(self, ctx: AnyContext) -> str:
@@ -211,8 +209,7 @@ class LLMTask(BaseTask):
211
209
  and history_file != ""
212
210
  and os.path.isfile(history_file)
213
211
  ):
214
- with open(history_file, "r") as f:
215
- return json.loads(f.read())
212
+ return json.loads(read_file(history_file))
216
213
  return self._history
217
214
 
218
215
  def _get_history_file(self, ctx: AnyContext) -> str:
zrb/task/make_task.py CHANGED
@@ -32,7 +32,6 @@ def make_task(
32
32
  group: AnyGroup | None = None,
33
33
  alias: str | None = None,
34
34
  ) -> Callable[[Callable[[AnyContext], Any]], AnyTask]:
35
-
36
35
  def _make_task(fn: Callable[[AnyContext], Any]) -> BaseTask:
37
36
  task = BaseTask(
38
37
  name=name,
zrb/task/scaffolder.py CHANGED
@@ -30,9 +30,11 @@ class Scaffolder(BaseTask):
30
30
  destination_path: StrAttr | None = None,
31
31
  render_destination_path: bool = True,
32
32
  transform_path: TransformConfig = {},
33
+ render_transform_path: bool = True,
33
34
  transform_content: (
34
35
  list[AnyContentTransformer] | AnyContentTransformer | TransformConfig
35
36
  ) = [],
37
+ render_transform_content: bool = True,
36
38
  execute_condition: BoolAttr = True,
37
39
  retries: int = 2,
38
40
  retry_period: float = 0,
@@ -70,7 +72,9 @@ class Scaffolder(BaseTask):
70
72
  self._destination_path = destination_path
71
73
  self._render_destination_path = render_destination_path
72
74
  self._content_transformers = transform_content
75
+ self._render_content_transformers = render_transform_content
73
76
  self._path_transformer = transform_path
77
+ self._render_path_transformer = render_transform_path
74
78
 
75
79
  def _get_source_path(self, ctx: AnyContext) -> str:
76
80
  return get_str_attr(ctx, self._source_path, "", auto_render=True)
@@ -80,9 +84,17 @@ class Scaffolder(BaseTask):
80
84
 
81
85
  def _get_content_transformers(self) -> list[AnyContentTransformer]:
82
86
  if callable(self._content_transformers):
83
- return [ContentTransformer(match="*", transform=self._content_transformers)]
87
+ return [
88
+ ContentTransformer(match=".*", transform=self._content_transformers)
89
+ ]
84
90
  if isinstance(self._content_transformers, dict):
85
- return [ContentTransformer(match="*", transform=self._content_transformers)]
91
+ return [
92
+ ContentTransformer(
93
+ match=".*",
94
+ transform=self._content_transformers,
95
+ auto_render=self._render_content_transformers,
96
+ )
97
+ ]
86
98
  if isinstance(self._content_transformers, AnyContentTransformer):
87
99
  return [self._content_transformers]
88
100
  return self._content_transformers
@@ -117,17 +129,19 @@ class Scaffolder(BaseTask):
117
129
  dest_file = os.path.join(
118
130
  dest_dir, self._transform_path(ctx, file_name)
119
131
  )
132
+ ctx.log_info(f"Copying {src_file} to {dest_file}")
120
133
  shutil.copy2(src_file, dest_file)
121
- ctx.log_info(f"Copied {src_file} to {dest_file}")
122
134
  else:
135
+ ctx.log_info(f"Copying {source_path} to {destination_path}")
123
136
  shutil.copy2(source_path, destination_path)
124
- ctx.log_info(f"Copied {source_path} to {destination_path}")
125
137
 
126
138
  def _transform_path(self, ctx: AnyContext, file_path: str):
127
139
  if callable(self._path_transformer):
128
140
  return self._path_transformer(ctx, file_path)
129
141
  new_file_path = file_path
130
142
  for keyword, replacement in self._path_transformer.items():
143
+ if self._render_path_transformer:
144
+ replacement = ctx.render(replacement)
131
145
  new_file_path = new_file_path.replace(keyword, replacement)
132
146
  return new_file_path
133
147
 
zrb/task/scheduler.py CHANGED
@@ -16,7 +16,6 @@ from zrb.xcom.xcom import Xcom
16
16
 
17
17
 
18
18
  class Scheduler(BaseTrigger):
19
-
20
19
  def __init__(
21
20
  self,
22
21
  name: str,
zrb/util/cmd/command.py CHANGED
@@ -47,7 +47,6 @@ async def run_command(
47
47
  max_output_line: int = 1000,
48
48
  max_error_line: int = 1000,
49
49
  ) -> tuple[CmdResult, int]:
50
-
51
50
  async def __read_stream(
52
51
  stream, log_method: Callable[..., None], max_lines: int
53
52
  ) -> str:
@@ -4,7 +4,7 @@ import libcst as cst
4
4
  class ClassCodeAdder(cst.CSTTransformer):
5
5
  def __init__(self, class_name: str, new_code: str):
6
6
  self.class_name = class_name
7
- self.new_code = cst.parse_statement(new_code)
7
+ self.new_code = cst.parse_module(new_code).body
8
8
  self.class_found = False
9
9
 
10
10
  def leave_ClassDef(
@@ -15,17 +15,17 @@ class ClassCodeAdder(cst.CSTTransformer):
15
15
  self.class_found = True
16
16
  # Add the method to the class body
17
17
  new_body = updated_node.body.with_changes(
18
- body=updated_node.body.body + (self.new_code,)
18
+ body=updated_node.body.body + tuple(self.new_code)
19
19
  )
20
20
  return updated_node.with_changes(body=new_body)
21
21
  return updated_node
22
22
 
23
23
 
24
- def add_code_to_class(original_code: str, class_name: str, method_code: str) -> str:
24
+ def append_code_to_class(original_code: str, class_name: str, new_code: str) -> str:
25
25
  # Parse the original code into a module
26
26
  module = cst.parse_module(original_code)
27
27
  # Initialize transformer with the class name and method code
28
- transformer = ClassCodeAdder(class_name, method_code)
28
+ transformer = ClassCodeAdder(class_name, new_code)
29
29
  # Apply the transformation
30
30
  modified_module = module.visit(transformer)
31
31
  # Check if the class was found
@@ -5,7 +5,7 @@ class FunctionCodeAdder(cst.CSTTransformer):
5
5
  def __init__(self, function_name: str, new_code: str):
6
6
  self.function_name = function_name
7
7
  # Use parse_module to handle multiple statements
8
- self.new_code = cst.parse_statement(new_code)
8
+ self.new_code = cst.parse_module(new_code).body
9
9
  self.function_found = False
10
10
 
11
11
  def leave_FunctionDef(
@@ -16,13 +16,15 @@ class FunctionCodeAdder(cst.CSTTransformer):
16
16
  self.function_found = True
17
17
  # Add the method to the class body
18
18
  new_body = updated_node.body.with_changes(
19
- body=updated_node.body.body + (self.new_code,)
19
+ body=updated_node.body.body + tuple(self.new_code)
20
20
  )
21
21
  return updated_node.with_changes(body=new_body)
22
22
  return updated_node
23
23
 
24
24
 
25
- def add_code_to_function(original_code: str, function_name: str, new_code: str) -> str:
25
+ def append_code_to_function(
26
+ original_code: str, function_name: str, new_code: str
27
+ ) -> str:
26
28
  # Parse the original code into a module
27
29
  module = cst.parse_module(original_code)
28
30
  # Initialize the transformer with the necessary information
@@ -6,7 +6,7 @@ class MethodCodeAdder(cst.CSTTransformer):
6
6
  self.class_name = class_name
7
7
  self.method_name = method_name
8
8
  # Use parse_module to handle multiple statements
9
- self.new_code = cst.parse_statement(new_code)
9
+ self.new_code = cst.parse_module(new_code).body
10
10
  self.class_found = False
11
11
  self.method_found = False
12
12
 
@@ -27,7 +27,7 @@ class MethodCodeAdder(cst.CSTTransformer):
27
27
  ):
28
28
  # Modify the target function by adding the new code
29
29
  body_with_new_code = item.body.with_changes(
30
- body=item.body.body + (self.new_code,) # Add the new code
30
+ body=item.body.body + tuple(self.new_code) # Add the new code
31
31
  )
32
32
  new_body.append(item.with_changes(body=body_with_new_code))
33
33
  self.method_found = True
@@ -37,7 +37,7 @@ class MethodCodeAdder(cst.CSTTransformer):
37
37
  return updated_node
38
38
 
39
39
 
40
- def add_code_to_method(
40
+ def append_code_to_method(
41
41
  original_code: str, class_name: str, function_name: str, new_code: str
42
42
  ) -> str:
43
43
  # Parse the original code into a module
@@ -33,7 +33,7 @@ class DictionaryModifier(cst.CSTTransformer):
33
33
  return updated_node
34
34
 
35
35
 
36
- def add_key_to_dict(
36
+ def append_key_to_dict(
37
37
  original_code: str, dictionary_name: str, new_key: str, new_value: str
38
38
  ) -> str:
39
39
  # Parse the original code into a module
@@ -21,7 +21,7 @@ class FunctionCallParamAdder(cst.CSTTransformer):
21
21
  return updated_node
22
22
 
23
23
 
24
- def add_param_to_function_call(
24
+ def append_param_to_function_call(
25
25
  original_code: str, func_name: str, new_param: str
26
26
  ) -> str:
27
27
  # Parse the original code into a module
@@ -1,5 +1,5 @@
1
- def add_code_to_module(source_code: str, new_code: str) -> str:
2
- lines = source_code.splitlines()
1
+ def prepend_code_to_module(original_code: str, new_code: str) -> str:
2
+ lines = original_code.splitlines()
3
3
  last_import_index = -1
4
4
  for i, line in enumerate(lines):
5
5
  stripped_line = line.strip()
@@ -22,7 +22,7 @@ class ParentClassAdder(cst.CSTTransformer):
22
22
  return updated_node
23
23
 
24
24
 
25
- def add_parent_to_class(
25
+ def prepend_parent_class(
26
26
  original_code: str, class_name: str, parent_class_name: str
27
27
  ) -> str:
28
28
  # Parse the original code into a module
@@ -33,7 +33,7 @@ class ClassPropertyAdder(cst.CSTTransformer):
33
33
  return updated_node
34
34
 
35
35
 
36
- def add_property_to_class(
36
+ def prepend_property_to_class(
37
37
  original_code: str,
38
38
  class_name: str,
39
39
  property_name: str,
zrb/util/file.py ADDED
@@ -0,0 +1,18 @@
1
+ import os
2
+
3
+
4
+ def read_file(file_path: str, replace_map: dict[str, str] = {}) -> str:
5
+ with open(file_path, "r", encoding="utf-8") as f:
6
+ content = f.read()
7
+ for key, val in replace_map.items():
8
+ content = content.replace(key, val)
9
+ return content
10
+
11
+
12
+ def write_file(file_path: str, content: str | list[str]):
13
+ if isinstance(content, list):
14
+ content = "\n".join([line for line in content if line is not None])
15
+ dir_path = os.path.dirname(file_path)
16
+ os.makedirs(dir_path, exist_ok=True)
17
+ with open(file_path, "w") as f:
18
+ f.write(content.strip())