zrb 1.0.0a1__py3-none-any.whl → 1.0.0a3__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.
- zrb/__init__.py +48 -39
- zrb/__main__.py +3 -3
- zrb/attr/type.py +2 -1
- zrb/builtin/__init__.py +40 -2
- zrb/builtin/base64.py +32 -0
- zrb/builtin/git.py +156 -0
- zrb/builtin/git_subtree.py +88 -0
- zrb/builtin/group.py +34 -0
- zrb/builtin/llm.py +31 -0
- zrb/builtin/md5.py +34 -0
- zrb/builtin/project/__init__.py +0 -0
- zrb/builtin/project/add/__init__.py +0 -0
- zrb/builtin/project/add/fastapp.py +72 -0
- zrb/builtin/project/add/fastapp_template/.gitignore +4 -0
- zrb/builtin/project/add/fastapp_template/README.md +7 -0
- zrb/builtin/project/add/fastapp_template/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/_zrb/config.py +17 -0
- zrb/builtin/project/add/fastapp_template/_zrb/group.py +16 -0
- zrb/builtin/project/add/fastapp_template/_zrb/helper.py +97 -0
- zrb/builtin/project/add/fastapp_template/_zrb/main.py +132 -0
- zrb/builtin/project/add/fastapp_template/_zrb/venv_task.py +22 -0
- zrb/builtin/project/add/fastapp_template/common/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/common/app.py +18 -0
- zrb/builtin/project/add/fastapp_template/common/db_engine.py +5 -0
- zrb/builtin/project/add/fastapp_template/common/db_repository.py +134 -0
- zrb/builtin/project/add/fastapp_template/common/error.py +8 -0
- zrb/builtin/project/add/fastapp_template/common/schema.py +5 -0
- zrb/builtin/project/add/fastapp_template/common/usecase.py +232 -0
- zrb/builtin/project/add/fastapp_template/config.py +29 -0
- zrb/builtin/project/add/fastapp_template/main.py +7 -0
- zrb/builtin/project/add/fastapp_template/migrate.py +3 -0
- zrb/builtin/project/add/fastapp_template/module/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/module/auth/alembic.ini +117 -0
- zrb/builtin/project/add/fastapp_template/module/auth/client/api_client.py +7 -0
- zrb/builtin/project/add/fastapp_template/module/auth/client/base_client.py +27 -0
- zrb/builtin/project/add/fastapp_template/module/auth/client/direct_client.py +6 -0
- zrb/builtin/project/add/fastapp_template/module/auth/client/factory.py +9 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration/README +1 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration/env.py +108 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration/script.py.mako +26 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration/versions/3093c7336477_add_user_table.py +37 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration_metadata.py +6 -0
- zrb/builtin/project/add/fastapp_template/module/auth/route.py +22 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/db_repository.py +39 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/factory.py +13 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/repository.py +34 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/usecase.py +45 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/alembic.ini +117 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration/README +1 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration/env.py +108 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration/script.py.mako +26 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration/versions/.gitkeep +0 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration_metadata.py +3 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/route.py +27 -0
- zrb/builtin/project/add/fastapp_template/requirements.txt +6 -0
- zrb/builtin/project/add/fastapp_template/schema/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/schema/role.py +31 -0
- zrb/builtin/project/add/fastapp_template/schema/user.py +31 -0
- zrb/builtin/project/add/fastapp_template/template.env +2 -0
- zrb/builtin/project/create/__init__.py +0 -0
- zrb/builtin/project/create/create.py +41 -0
- zrb/builtin/project/create/project-template/README.md +3 -0
- zrb/builtin/project/create/project-template/zrb_init.py +7 -0
- zrb/builtin/python.py +11 -0
- zrb/builtin/shell/__init__.py +0 -5
- zrb/builtin/shell/autocomplete/__init__.py +0 -9
- zrb/builtin/shell/autocomplete/bash.py +5 -6
- zrb/builtin/shell/autocomplete/subcmd.py +7 -8
- zrb/builtin/shell/autocomplete/zsh.py +5 -6
- zrb/builtin/todo.py +186 -0
- zrb/callback/any_callback.py +1 -1
- zrb/callback/callback.py +5 -5
- zrb/cmd/cmd_val.py +2 -2
- zrb/config.py +4 -1
- zrb/content_transformer/any_content_transformer.py +1 -1
- zrb/content_transformer/content_transformer.py +2 -2
- zrb/context/any_context.py +5 -1
- zrb/context/any_shared_context.py +3 -3
- zrb/context/context.py +15 -9
- zrb/context/shared_context.py +9 -8
- zrb/env/__init__.py +0 -3
- zrb/env/any_env.py +2 -2
- zrb/env/env.py +4 -5
- zrb/env/env_file.py +4 -4
- zrb/env/env_map.py +4 -4
- zrb/group/__init__.py +0 -3
- zrb/group/any_group.py +3 -3
- zrb/group/group.py +7 -6
- zrb/input/any_input.py +1 -1
- zrb/input/base_input.py +4 -4
- zrb/input/bool_input.py +5 -5
- zrb/input/float_input.py +3 -3
- zrb/input/int_input.py +3 -3
- zrb/input/option_input.py +51 -0
- zrb/input/password_input.py +2 -2
- zrb/input/str_input.py +1 -1
- zrb/input/text_input.py +12 -10
- zrb/runner/cli.py +79 -44
- zrb/runner/web_app/group_info_ui/controller.py +7 -8
- zrb/runner/web_app/group_info_ui/view.html +2 -2
- zrb/runner/web_app/home_page/controller.py +7 -6
- zrb/runner/web_app/home_page/view.html +2 -2
- zrb/runner/web_app/task_ui/controller.py +13 -13
- zrb/runner/web_app/task_ui/partial/common-util.js +37 -0
- zrb/runner/web_app/task_ui/partial/main.js +9 -2
- zrb/runner/web_app/task_ui/partial/show-existing-session.js +20 -5
- zrb/runner/web_app/task_ui/partial/visualize-history.js +1 -41
- zrb/runner/web_app/task_ui/view.html +4 -2
- zrb/runner/web_server.py +137 -211
- zrb/runner/web_util.py +5 -35
- zrb/session/any_session.py +13 -7
- zrb/session/session.py +80 -41
- zrb/session_state_log/session_state_log.py +7 -5
- zrb/session_state_logger/any_session_state_logger.py +1 -1
- zrb/session_state_logger/default_session_state_logger.py +2 -2
- zrb/session_state_logger/file_session_state_logger.py +19 -27
- zrb/task/any_task.py +8 -3
- zrb/task/base_task.py +47 -33
- zrb/task/base_trigger.py +11 -12
- zrb/task/cmd_task.py +55 -43
- zrb/task/http_check.py +8 -8
- zrb/task/llm_task.py +160 -0
- zrb/task/make_task.py +9 -9
- zrb/task/rsync_task.py +7 -7
- zrb/task/scaffolder.py +14 -11
- zrb/task/scheduler.py +6 -7
- zrb/task/task.py +1 -1
- zrb/task/tcp_check.py +8 -8
- zrb/util/attr.py +19 -3
- zrb/util/cli/style.py +71 -2
- zrb/util/cli/subcommand.py +2 -2
- zrb/util/codemod/__init__.py +0 -0
- zrb/util/codemod/add_code_to_class.py +35 -0
- zrb/util/codemod/add_code_to_function.py +36 -0
- zrb/util/codemod/add_code_to_method.py +55 -0
- zrb/util/codemod/add_key_to_dict.py +51 -0
- zrb/util/codemod/add_param_to_function_call.py +39 -0
- zrb/util/codemod/add_property_to_class.py +55 -0
- zrb/util/git.py +156 -0
- zrb/util/git_subtree.py +94 -0
- zrb/util/group.py +2 -2
- zrb/util/llm/tool.py +63 -0
- zrb/util/string/conversion.py +7 -0
- zrb/util/todo.py +135 -0
- {zrb-1.0.0a1.dist-info → zrb-1.0.0a3.dist-info}/METADATA +11 -7
- zrb-1.0.0a3.dist-info/RECORD +194 -0
- zrb/builtin/shell/_group.py +0 -9
- zrb/builtin/shell/autocomplete/_group.py +0 -6
- zrb/runner/web_app/any_request_handler.py +0 -24
- zrb/runner/web_server.bak.py +0 -208
- zrb-1.0.0a1.dist-info/RECORD +0 -120
- {zrb-1.0.0a1.dist-info → zrb-1.0.0a3.dist-info}/WHEEL +0 -0
- {zrb-1.0.0a1.dist-info → zrb-1.0.0a3.dist-info}/entry_points.txt +0 -0
zrb/input/password_input.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
import getpass
|
2
2
|
from collections.abc import Callable
|
3
3
|
|
4
|
-
from
|
5
|
-
from .base_input import BaseInput
|
4
|
+
from zrb.context.any_shared_context import AnySharedContext
|
5
|
+
from zrb.input.base_input import BaseInput
|
6
6
|
|
7
7
|
|
8
8
|
class PasswordInput(BaseInput):
|
zrb/input/str_input.py
CHANGED
zrb/input/text_input.py
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
import os
|
1
2
|
import subprocess
|
2
3
|
import tempfile
|
3
4
|
from collections.abc import Callable
|
4
5
|
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from .base_input import BaseInput
|
6
|
+
from zrb.config import DEFAULT_EDITOR
|
7
|
+
from zrb.context.any_shared_context import AnySharedContext
|
8
|
+
from zrb.input.base_input import BaseInput
|
8
9
|
|
9
10
|
|
10
11
|
class TextInput(BaseInput):
|
@@ -66,14 +67,15 @@ class TextInput(BaseInput):
|
|
66
67
|
|
67
68
|
def _prompt_cli_str(self, shared_ctx: AnySharedContext) -> str:
|
68
69
|
prompt_message = (
|
69
|
-
f"{self.comment_start}{super().prompt_message}{self.comment_end}
|
70
|
+
f"{self.comment_start}{super().prompt_message}{self.comment_end}"
|
70
71
|
)
|
72
|
+
prompt_message_eol = f"{prompt_message}\n"
|
71
73
|
default_value = self._get_default_str(shared_ctx)
|
72
74
|
with tempfile.NamedTemporaryFile(
|
73
75
|
delete=False, suffix=self._extension
|
74
76
|
) as temp_file:
|
75
77
|
temp_file_name = temp_file.name
|
76
|
-
temp_file.write(
|
78
|
+
temp_file.write(prompt_message_eol.encode())
|
77
79
|
# Pre-fill with default content
|
78
80
|
if default_value:
|
79
81
|
temp_file.write(default_value.encode())
|
@@ -82,8 +84,8 @@ class TextInput(BaseInput):
|
|
82
84
|
subprocess.call([self._editor, temp_file_name])
|
83
85
|
# Read the edited content
|
84
86
|
with open(temp_file_name, "r") as temp_file:
|
85
|
-
edited_content = temp_file.read()
|
86
|
-
parts = edited_content.split(prompt_message)
|
87
|
-
|
88
|
-
|
89
|
-
return edited_content
|
87
|
+
edited_content = temp_file.read()
|
88
|
+
parts = [text.strip() for text in edited_content.split(prompt_message, 1)]
|
89
|
+
edited_content = "\n".join(parts).lstrip()
|
90
|
+
os.remove(temp_file_name)
|
91
|
+
return edited_content
|
zrb/runner/cli.py
CHANGED
@@ -1,16 +1,22 @@
|
|
1
1
|
import sys
|
2
2
|
from typing import Any
|
3
3
|
|
4
|
-
from
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from
|
8
|
-
from
|
9
|
-
from
|
10
|
-
from
|
11
|
-
from
|
12
|
-
from
|
13
|
-
|
4
|
+
from zrb.config import BANNER, WEB_HTTP_PORT
|
5
|
+
from zrb.context.any_context import AnyContext
|
6
|
+
from zrb.context.shared_context import SharedContext
|
7
|
+
from zrb.group.group import Group
|
8
|
+
from zrb.runner.web_server import create_app, run_web_server
|
9
|
+
from zrb.session.session import Session
|
10
|
+
from zrb.task.any_task import AnyTask
|
11
|
+
from zrb.task.make_task import make_task
|
12
|
+
from zrb.util.cli.style import (
|
13
|
+
stylize_bold_yellow,
|
14
|
+
stylize_faint,
|
15
|
+
stylize_section_header,
|
16
|
+
)
|
17
|
+
from zrb.util.group import extract_node_from_args, get_non_empty_subgroups, get_subtasks
|
18
|
+
from zrb.util.load import load_zrb_init
|
19
|
+
from zrb.util.string.conversion import double_quote
|
14
20
|
|
15
21
|
|
16
22
|
class Cli(Group):
|
@@ -25,12 +31,15 @@ class Cli(Group):
|
|
25
31
|
if "h" in kwargs or "help" in kwargs:
|
26
32
|
self._show_task_info(node)
|
27
33
|
return
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
+
run_kwargs = self._get_run_kwargs(node, args, kwargs)
|
35
|
+
try:
|
36
|
+
result = self._run_task(node, args, run_kwargs)
|
37
|
+
if result is not None:
|
38
|
+
print(result)
|
39
|
+
return result
|
40
|
+
finally:
|
41
|
+
run_command = self._get_run_command(node_path, run_kwargs)
|
42
|
+
self._print_run_command(run_command)
|
34
43
|
|
35
44
|
def _print_run_command(self, run_command: str):
|
36
45
|
print(
|
@@ -39,34 +48,51 @@ class Cli(Group):
|
|
39
48
|
file=sys.stderr,
|
40
49
|
)
|
41
50
|
|
42
|
-
def _get_run_command(
|
43
|
-
self, node_path: list[str], kwargs: dict[str, Any], args: list[str]
|
44
|
-
) -> str:
|
51
|
+
def _get_run_command(self, node_path: list[str], run_kwargs: dict[str, str]) -> str:
|
45
52
|
parts = [self.name] + node_path
|
46
|
-
if len(
|
47
|
-
parts += [
|
48
|
-
|
49
|
-
|
53
|
+
if len(run_kwargs) > 0:
|
54
|
+
parts += [
|
55
|
+
self._get_run_command_param(key, val) for key, val in run_kwargs.items()
|
56
|
+
]
|
50
57
|
return " ".join(parts)
|
51
58
|
|
52
|
-
def
|
59
|
+
def _get_run_command_param(self, key: str, val: str) -> str:
|
60
|
+
if '"' in val or "'" in val or " " in val:
|
61
|
+
return f"--{key} {double_quote(val)}"
|
62
|
+
return f"--{key} {val}"
|
63
|
+
|
64
|
+
def _run_task(
|
65
|
+
self, task: AnyTask, args: list[str], run_kwargs: dict[str, str]
|
66
|
+
) -> tuple[Any]:
|
67
|
+
shared_ctx = SharedContext(args=args)
|
68
|
+
for task_input in task.inputs:
|
69
|
+
if task_input.name in run_kwargs:
|
70
|
+
task_input.update_shared_context(
|
71
|
+
shared_ctx, run_kwargs[task_input.name]
|
72
|
+
)
|
73
|
+
continue
|
74
|
+
try:
|
75
|
+
return task.run(Session(shared_ctx=shared_ctx, root_group=self))
|
76
|
+
except KeyboardInterrupt:
|
77
|
+
pass
|
78
|
+
|
79
|
+
def _get_run_kwargs(
|
80
|
+
self, task: AnyTask, args: list[str], kwargs: dict[str, str]
|
81
|
+
) -> tuple[Any]:
|
53
82
|
arg_index = 0
|
54
|
-
str_kwargs = {key: val for key, val in
|
83
|
+
str_kwargs = {key: val for key, val in kwargs.items()}
|
84
|
+
run_kwargs = {**str_kwargs}
|
55
85
|
shared_ctx = SharedContext(args=args)
|
56
86
|
for task_input in task.inputs:
|
57
87
|
if task_input.name in str_kwargs:
|
58
88
|
continue
|
59
89
|
if arg_index < len(args):
|
60
|
-
|
90
|
+
run_kwargs[task_input.name] = args[arg_index]
|
61
91
|
arg_index += 1
|
62
92
|
continue
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
Session(shared_ctx=shared_ctx, root_group=self), str_kwargs=str_kwargs
|
67
|
-
)
|
68
|
-
except KeyboardInterrupt:
|
69
|
-
pass
|
93
|
+
str_value = task_input.prompt_cli_str(shared_ctx)
|
94
|
+
run_kwargs[task_input.name] = str_value
|
95
|
+
return run_kwargs
|
70
96
|
|
71
97
|
def _show_task_info(self, task: AnyTask):
|
72
98
|
description = task.description
|
@@ -77,8 +103,9 @@ class Cli(Group):
|
|
77
103
|
print()
|
78
104
|
if len(inputs) > 0:
|
79
105
|
print(stylize_section_header("INPUTS"))
|
106
|
+
max_input_name_length = max(len(task_input.name) for task_input in inputs)
|
80
107
|
for task_input in inputs:
|
81
|
-
task_input_name = task_input.name.ljust(
|
108
|
+
task_input_name = task_input.name.ljust(max_input_name_length + 1)
|
82
109
|
print(f" --{task_input_name}: {task_input.description}")
|
83
110
|
print()
|
84
111
|
|
@@ -93,15 +120,17 @@ class Cli(Group):
|
|
93
120
|
subgroups = get_non_empty_subgroups(group)
|
94
121
|
if len(subgroups) > 0:
|
95
122
|
print(stylize_section_header("GROUPS"))
|
123
|
+
max_subgroup_alias_length = max(len(s) for s in subgroups)
|
96
124
|
for alias, subgroup in subgroups.items():
|
97
|
-
alias = alias.ljust(
|
125
|
+
alias = alias.ljust(max_subgroup_alias_length + 1)
|
98
126
|
print(f" {alias}: {subgroup.description}")
|
99
127
|
print()
|
100
128
|
subtasks = get_subtasks(group)
|
101
129
|
if len(subtasks) > 0:
|
102
130
|
print(stylize_section_header("TASKS"))
|
131
|
+
max_subtask_alias_length = max(len(s) for s in subtasks)
|
103
132
|
for alias, subtask in subtasks.items():
|
104
|
-
alias = alias.ljust(
|
133
|
+
alias = alias.ljust(max_subtask_alias_length + 1)
|
105
134
|
print(f" {alias}: {subtask.description}")
|
106
135
|
print()
|
107
136
|
|
@@ -139,13 +168,19 @@ class Cli(Group):
|
|
139
168
|
|
140
169
|
|
141
170
|
cli = Cli(name="zrb", description="Your Automation Powerhouse", banner=BANNER)
|
171
|
+
server_group = cli.add_group(
|
172
|
+
Group(name="server", description="🌐 Server related command")
|
173
|
+
)
|
174
|
+
|
142
175
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
)
|
176
|
+
@make_task(
|
177
|
+
name="start-server",
|
178
|
+
description="🚀 Start Zrb Web Server",
|
179
|
+
cli_only=True,
|
180
|
+
retries=0,
|
181
|
+
group=server_group,
|
182
|
+
alias="start",
|
151
183
|
)
|
184
|
+
async def run(_: AnyContext):
|
185
|
+
app = create_app(cli, WEB_HTTP_PORT)
|
186
|
+
await run_web_server(app, WEB_HTTP_PORT)
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import os
|
2
2
|
|
3
|
-
from
|
4
|
-
|
5
|
-
from
|
6
|
-
from
|
3
|
+
from fastapi.responses import HTMLResponse
|
4
|
+
|
5
|
+
from zrb.group.any_group import AnyGroup
|
6
|
+
from zrb.util.group import get_non_empty_subgroups, get_subtasks
|
7
|
+
from zrb.util.string.format import fstring_format
|
7
8
|
|
8
9
|
_DIR = os.path.dirname(__file__)
|
9
10
|
|
@@ -23,9 +24,7 @@ with open(os.path.join(_DIR, "partial", "task_li.html")) as f:
|
|
23
24
|
_TASK_LI_TEMPLATE = f.read()
|
24
25
|
|
25
26
|
|
26
|
-
def handle_group_info_ui(
|
27
|
-
handler: AnyRequestHandler, root_group: AnyGroup, group: AnyGroup, url: str
|
28
|
-
):
|
27
|
+
def handle_group_info_ui(root_group: AnyGroup, group: AnyGroup, url: str):
|
29
28
|
url_parts = url.split("/")
|
30
29
|
parent_url_parts = url_parts[:-2] + [""]
|
31
30
|
parent_url = "/".join(parent_url_parts)
|
@@ -75,7 +74,7 @@ def handle_group_info_ui(
|
|
75
74
|
},
|
76
75
|
)
|
77
76
|
)
|
78
|
-
|
77
|
+
return HTMLResponse(
|
79
78
|
fstring_format(
|
80
79
|
_VIEW_TEMPLATE,
|
81
80
|
{
|
@@ -4,8 +4,8 @@
|
|
4
4
|
<meta charset="utf-8">
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
6
|
<meta name="color-scheme" content="light dark">
|
7
|
-
<link rel="stylesheet" href="/pico.min.css">
|
8
|
-
<link rel="icon" href="/favicon-32x32.png" sizes="32x32" type="image/png">
|
7
|
+
<link rel="stylesheet" href="/static/pico.min.css">
|
8
|
+
<link rel="icon" href="/static/favicon-32x32.png" sizes="32x32" type="image/png">
|
9
9
|
<title>Zrb</title>
|
10
10
|
</head>
|
11
11
|
<body>
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import os
|
2
2
|
|
3
|
-
from
|
4
|
-
|
5
|
-
from
|
6
|
-
from
|
3
|
+
from fastapi.responses import HTMLResponse
|
4
|
+
|
5
|
+
from zrb.group.any_group import AnyGroup
|
6
|
+
from zrb.util.group import get_non_empty_subgroups, get_subtasks
|
7
|
+
from zrb.util.string.format import fstring_format
|
7
8
|
|
8
9
|
_DIR = os.path.dirname(__file__)
|
9
10
|
|
@@ -23,7 +24,7 @@ with open(os.path.join(_DIR, "partial", "task_li.html")) as f:
|
|
23
24
|
_TASK_LI_TEMPLATE = f.read()
|
24
25
|
|
25
26
|
|
26
|
-
def handle_home_page(
|
27
|
+
def handle_home_page(root_group: AnyGroup):
|
27
28
|
subgroups = get_non_empty_subgroups(root_group, web_only=True)
|
28
29
|
group_info = (
|
29
30
|
""
|
@@ -62,7 +63,7 @@ def handle_home_page(handler: AnyRequestHandler, root_group: AnyGroup):
|
|
62
63
|
},
|
63
64
|
)
|
64
65
|
)
|
65
|
-
|
66
|
+
return HTMLResponse(
|
66
67
|
fstring_format(
|
67
68
|
_VIEW_TEMPLATE,
|
68
69
|
{
|
@@ -4,8 +4,8 @@
|
|
4
4
|
<meta charset="utf-8">
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
6
|
<meta name="color-scheme" content="light dark">
|
7
|
-
<link rel="stylesheet" href="/pico.min.css">
|
8
|
-
<link rel="icon" href="/favicon-32x32.png" sizes="32x32" type="image/png">
|
7
|
+
<link rel="stylesheet" href="/static/pico.min.css">
|
8
|
+
<link rel="icon" href="/static/favicon-32x32.png" sizes="32x32" type="image/png">
|
9
9
|
<title>Zrb</title>
|
10
10
|
</head>
|
11
11
|
<body>
|
@@ -1,10 +1,11 @@
|
|
1
1
|
import os
|
2
2
|
|
3
|
-
from
|
4
|
-
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from
|
3
|
+
from fastapi.responses import HTMLResponse
|
4
|
+
|
5
|
+
from zrb.group.any_group import AnyGroup
|
6
|
+
from zrb.session.any_session import AnySession
|
7
|
+
from zrb.task.any_task import AnyTask
|
8
|
+
from zrb.util.string.format import fstring_format
|
8
9
|
|
9
10
|
_DIR = os.path.dirname(__file__)
|
10
11
|
|
@@ -23,17 +24,15 @@ with open(os.path.join(_DIR, "partial", "show-existing-session.js")) as f:
|
|
23
24
|
with open(os.path.join(_DIR, "partial", "visualize-history.js")) as f:
|
24
25
|
_VISUALIZE_HISTORY_SCRIPT = f.read()
|
25
26
|
|
27
|
+
with open(os.path.join(_DIR, "partial", "common-util.js")) as f:
|
28
|
+
_COMMON_UTIL_SCRIPT = f.read()
|
29
|
+
|
26
30
|
|
27
31
|
def handle_task_ui(
|
28
|
-
|
29
|
-
root_group: AnyGroup,
|
30
|
-
task: AnyTask,
|
31
|
-
session: AnySession,
|
32
|
-
url: str,
|
33
|
-
args: list[str],
|
32
|
+
root_group: AnyGroup, task: AnyTask, session: AnySession, url: str, args: list[str]
|
34
33
|
):
|
35
34
|
session.register_task(task)
|
36
|
-
ctx =
|
35
|
+
ctx = task.get_ctx(session)
|
37
36
|
url_parts = url.split("/")
|
38
37
|
# Assemble parent url
|
39
38
|
parent_url_parts = url_parts[:-2] + [""]
|
@@ -53,7 +52,7 @@ def handle_task_ui(
|
|
53
52
|
]
|
54
53
|
)
|
55
54
|
session_name = args[0] if len(args) > 0 else ""
|
56
|
-
|
55
|
+
return HTMLResponse(
|
57
56
|
fstring_format(
|
58
57
|
_VIEW_TEMPLATE,
|
59
58
|
{
|
@@ -69,6 +68,7 @@ def handle_task_ui(
|
|
69
68
|
"main_script": _MAIN_SCRIPT,
|
70
69
|
"show_existing_session_script": _SHOW_EXISTING_SESSION_SCRIPT,
|
71
70
|
"visualize_history_script": _VISUALIZE_HISTORY_SCRIPT,
|
71
|
+
"common_util_script": _COMMON_UTIL_SCRIPT,
|
72
72
|
"session_name": session_name,
|
73
73
|
},
|
74
74
|
)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
function getFinalColor(finalStatus) {
|
2
|
+
switch(finalStatus) {
|
3
|
+
case "started":
|
4
|
+
return "#3498db";
|
5
|
+
case "ready":
|
6
|
+
return "#f39c12";
|
7
|
+
case "completed":
|
8
|
+
return "#2ecc71";
|
9
|
+
case "skipped":
|
10
|
+
return "#95a5a6";
|
11
|
+
case "failed":
|
12
|
+
return "#e74c3c";
|
13
|
+
case "permanently-failed":
|
14
|
+
return "#c0392b";
|
15
|
+
case "terminated":
|
16
|
+
return "#ffffff";
|
17
|
+
default:
|
18
|
+
return "#ffffff";
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
function getFinalTaskStatus(taskStatus) {
|
23
|
+
if (taskStatus.is_completed) {
|
24
|
+
return "completed";
|
25
|
+
}
|
26
|
+
if (taskStatus.is_terminated) {
|
27
|
+
return "terminated"
|
28
|
+
}
|
29
|
+
if (taskStatus.is_permanently_failed) {
|
30
|
+
return "permanently-failed"
|
31
|
+
}
|
32
|
+
const histories = taskStatus.history;
|
33
|
+
if (histories.length > 0) {
|
34
|
+
return histories[histories.length - 1].status;
|
35
|
+
}
|
36
|
+
return "";
|
37
|
+
}
|
@@ -17,11 +17,18 @@ window.addEventListener("load", async function () {
|
|
17
17
|
const minStartAtInput = document.getElementById("min-start-at-input");
|
18
18
|
minStartAtInput.value = formattedToday;
|
19
19
|
// Update session
|
20
|
-
|
20
|
+
pollExistingSessions(PAGE);
|
21
21
|
});
|
22
22
|
|
23
|
+
async function pollExistingSessions() {
|
24
|
+
while (true) {
|
25
|
+
await getExistingSessions(PAGE);
|
26
|
+
await delay(5000);
|
27
|
+
}
|
28
|
+
}
|
23
29
|
|
24
30
|
async function getExistingSessions(page) {
|
31
|
+
PAGE=page
|
25
32
|
const minStartAtInput = document.getElementById("min-start-at-input");
|
26
33
|
const minStartAt = formatDate(minStartAtInput.value);
|
27
34
|
const maxStartAtInput = document.getElementById("max-start-at-input");
|
@@ -41,7 +48,7 @@ async function getExistingSessions(page) {
|
|
41
48
|
},
|
42
49
|
});
|
43
50
|
const {total, data} = await response.json();
|
44
|
-
showExistingSession(total, data);
|
51
|
+
showExistingSession(page, total, data);
|
45
52
|
console.log("Success:", data);
|
46
53
|
} catch (error) {
|
47
54
|
console.error("Error:", error);
|
@@ -1,16 +1,31 @@
|
|
1
|
-
function showExistingSession(total, data) {
|
1
|
+
function showExistingSession(page, total, data) {
|
2
2
|
const ul = document.getElementById("session-history-ul");
|
3
3
|
ul.innerHTML = ''; // Clear existing content
|
4
4
|
data.forEach(item => {
|
5
|
-
const
|
6
|
-
const
|
7
|
-
const
|
5
|
+
const taskStatus = item.task_status[item.main_task_name];
|
6
|
+
const finalStatus = getFinalTaskStatus(taskStatus);
|
7
|
+
const finalColor = getFinalColor(finalStatus);
|
8
|
+
const taskHistories = taskStatus.history;
|
9
|
+
const taskStartTime = taskHistories.length > 0 ? taskHistories[0].time : ""
|
8
10
|
const li = document.createElement('li');
|
9
11
|
const a = document.createElement('a');
|
10
|
-
|
12
|
+
const dateSpan = document.createElement('span');
|
13
|
+
const statusSpan = document.createElement('span');
|
14
|
+
a.textContent = item.name;
|
11
15
|
a.target = '_blank';
|
12
16
|
a.href = `${UI_URL}${item.name}`;
|
13
17
|
li.appendChild(a);
|
18
|
+
statusSpan.style.marginLeft = "10px";
|
19
|
+
statusSpan.style.display = 'inline-block';
|
20
|
+
statusSpan.style.width = '15px';
|
21
|
+
statusSpan.style.height = '15px';
|
22
|
+
statusSpan.style.borderRadius = '50%';
|
23
|
+
statusSpan.style.border = '2px solid black';
|
24
|
+
statusSpan.style.backgroundColor = finalColor;
|
25
|
+
li.appendChild(statusSpan);
|
26
|
+
dateSpan.style.marginLeft = "10px";
|
27
|
+
dateSpan.textContent = taskStartTime;
|
28
|
+
li.appendChild(dateSpan);
|
14
29
|
ul.appendChild(li);
|
15
30
|
});
|
16
31
|
const paginationUl = document.getElementById("session-history-pagination-ul");
|
@@ -101,44 +101,4 @@ function getTaskEndDateTime(taskStatus, now) {
|
|
101
101
|
}
|
102
102
|
}
|
103
103
|
return now;
|
104
|
-
}
|
105
|
-
|
106
|
-
|
107
|
-
function getFinalColor(finalStatus) {
|
108
|
-
switch(finalStatus) {
|
109
|
-
case "started":
|
110
|
-
return "#3498db";
|
111
|
-
case "ready":
|
112
|
-
return "#f39c12";
|
113
|
-
case "completed":
|
114
|
-
return "#2ecc71";
|
115
|
-
case "skipped":
|
116
|
-
return "#95a5a6";
|
117
|
-
case "failed":
|
118
|
-
return "#e74c3c";
|
119
|
-
case "permanently-failed":
|
120
|
-
return "#c0392b";
|
121
|
-
case "terminated":
|
122
|
-
return "#ffffff";
|
123
|
-
default:
|
124
|
-
return "#ffffff";
|
125
|
-
}
|
126
|
-
}
|
127
|
-
|
128
|
-
|
129
|
-
function getFinalTaskStatus(taskStatus) {
|
130
|
-
if (taskStatus.is_completed) {
|
131
|
-
return "completed";
|
132
|
-
}
|
133
|
-
if (taskStatus.is_terminated) {
|
134
|
-
return "terminated"
|
135
|
-
}
|
136
|
-
if (taskStatus.is_permanently_failed) {
|
137
|
-
return "permanently-failed"
|
138
|
-
}
|
139
|
-
const histories = taskStatus.history;
|
140
|
-
if (histories.length > 0) {
|
141
|
-
return histories[histories.length - 1].status;
|
142
|
-
}
|
143
|
-
return "";
|
144
|
-
}
|
104
|
+
}
|
@@ -4,8 +4,8 @@
|
|
4
4
|
<meta charset="utf-8">
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
6
|
<meta name="color-scheme" content="light dark">
|
7
|
-
<link rel="stylesheet" href="/pico.min.css">
|
8
|
-
<link rel="icon" href="/favicon-32x32.png" sizes="32x32" type="image/png">
|
7
|
+
<link rel="stylesheet" href="/static/pico.min.css">
|
8
|
+
<link rel="icon" href="/static/favicon-32x32.png" sizes="32x32" type="image/png">
|
9
9
|
<title>Zrb</title>
|
10
10
|
</head>
|
11
11
|
<body>
|
@@ -78,7 +78,9 @@
|
|
78
78
|
const API_URL = '{api_url}';
|
79
79
|
const UI_URL = `{ui_url}`;
|
80
80
|
let SESSION_NAME = '{session_name}';
|
81
|
+
let PAGE = 0;
|
81
82
|
{main_script}
|
83
|
+
{common_util_script}
|
82
84
|
{show_existing_session_script}
|
83
85
|
{visualize_history_script}
|
84
86
|
</script>
|