py-data-engine 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data_engine/__init__.py +37 -0
- data_engine/application/__init__.py +39 -0
- data_engine/application/actions.py +42 -0
- data_engine/application/catalog.py +151 -0
- data_engine/application/control.py +213 -0
- data_engine/application/details.py +73 -0
- data_engine/application/runtime.py +449 -0
- data_engine/application/workspace.py +62 -0
- data_engine/authoring/__init__.py +14 -0
- data_engine/authoring/builder.py +31 -0
- data_engine/authoring/execution/__init__.py +6 -0
- data_engine/authoring/execution/app.py +6 -0
- data_engine/authoring/execution/context.py +82 -0
- data_engine/authoring/execution/continuous.py +176 -0
- data_engine/authoring/execution/grouped.py +106 -0
- data_engine/authoring/execution/logging.py +83 -0
- data_engine/authoring/execution/polling.py +135 -0
- data_engine/authoring/execution/runner.py +210 -0
- data_engine/authoring/execution/single.py +171 -0
- data_engine/authoring/flow.py +361 -0
- data_engine/authoring/helpers.py +160 -0
- data_engine/authoring/model.py +59 -0
- data_engine/authoring/primitives.py +430 -0
- data_engine/authoring/services.py +42 -0
- data_engine/devtools/__init__.py +3 -0
- data_engine/devtools/project_ast_map.py +503 -0
- data_engine/docs/__init__.py +1 -0
- data_engine/docs/sphinx_source/_static/custom.css +13 -0
- data_engine/docs/sphinx_source/api.rst +42 -0
- data_engine/docs/sphinx_source/conf.py +37 -0
- data_engine/docs/sphinx_source/guides/app-runtime-and-workspaces.md +397 -0
- data_engine/docs/sphinx_source/guides/authoring-flow-modules.md +215 -0
- data_engine/docs/sphinx_source/guides/configuring-flows.md +185 -0
- data_engine/docs/sphinx_source/guides/core-concepts.md +208 -0
- data_engine/docs/sphinx_source/guides/database-methods.md +107 -0
- data_engine/docs/sphinx_source/guides/duckdb-helpers.md +462 -0
- data_engine/docs/sphinx_source/guides/flow-context.md +538 -0
- data_engine/docs/sphinx_source/guides/flow-methods.md +206 -0
- data_engine/docs/sphinx_source/guides/getting-started.md +271 -0
- data_engine/docs/sphinx_source/guides/project-inventory.md +5683 -0
- data_engine/docs/sphinx_source/guides/project-map.md +118 -0
- data_engine/docs/sphinx_source/guides/recipes.md +268 -0
- data_engine/docs/sphinx_source/index.rst +22 -0
- data_engine/domain/__init__.py +92 -0
- data_engine/domain/actions.py +69 -0
- data_engine/domain/catalog.py +128 -0
- data_engine/domain/details.py +214 -0
- data_engine/domain/diagnostics.py +56 -0
- data_engine/domain/errors.py +104 -0
- data_engine/domain/inspection.py +99 -0
- data_engine/domain/logs.py +118 -0
- data_engine/domain/operations.py +172 -0
- data_engine/domain/operator.py +72 -0
- data_engine/domain/runs.py +155 -0
- data_engine/domain/runtime.py +279 -0
- data_engine/domain/source_state.py +17 -0
- data_engine/domain/support.py +54 -0
- data_engine/domain/time.py +23 -0
- data_engine/domain/workspace.py +159 -0
- data_engine/flow_modules/__init__.py +1 -0
- data_engine/flow_modules/flow_module_compiler.py +179 -0
- data_engine/flow_modules/flow_module_loader.py +201 -0
- data_engine/helpers/__init__.py +25 -0
- data_engine/helpers/duckdb.py +705 -0
- data_engine/hosts/__init__.py +1 -0
- data_engine/hosts/daemon/__init__.py +23 -0
- data_engine/hosts/daemon/app.py +221 -0
- data_engine/hosts/daemon/bootstrap.py +69 -0
- data_engine/hosts/daemon/client.py +465 -0
- data_engine/hosts/daemon/commands.py +64 -0
- data_engine/hosts/daemon/composition.py +310 -0
- data_engine/hosts/daemon/constants.py +15 -0
- data_engine/hosts/daemon/entrypoints.py +97 -0
- data_engine/hosts/daemon/lifecycle.py +191 -0
- data_engine/hosts/daemon/manager.py +272 -0
- data_engine/hosts/daemon/ownership.py +126 -0
- data_engine/hosts/daemon/runtime_commands.py +188 -0
- data_engine/hosts/daemon/runtime_control.py +31 -0
- data_engine/hosts/daemon/server.py +84 -0
- data_engine/hosts/daemon/shared_state.py +147 -0
- data_engine/hosts/daemon/state_sync.py +101 -0
- data_engine/platform/__init__.py +1 -0
- data_engine/platform/identity.py +35 -0
- data_engine/platform/local_settings.py +146 -0
- data_engine/platform/theme.py +259 -0
- data_engine/platform/workspace_models.py +190 -0
- data_engine/platform/workspace_policy.py +333 -0
- data_engine/runtime/__init__.py +1 -0
- data_engine/runtime/file_watch.py +185 -0
- data_engine/runtime/ledger_models.py +116 -0
- data_engine/runtime/runtime_db.py +938 -0
- data_engine/runtime/shared_state.py +523 -0
- data_engine/services/__init__.py +49 -0
- data_engine/services/daemon.py +64 -0
- data_engine/services/daemon_state.py +40 -0
- data_engine/services/flow_catalog.py +102 -0
- data_engine/services/flow_execution.py +48 -0
- data_engine/services/ledger.py +85 -0
- data_engine/services/logs.py +65 -0
- data_engine/services/runtime_binding.py +105 -0
- data_engine/services/runtime_execution.py +126 -0
- data_engine/services/runtime_history.py +62 -0
- data_engine/services/settings.py +58 -0
- data_engine/services/shared_state.py +28 -0
- data_engine/services/theme.py +59 -0
- data_engine/services/workspace_provisioning.py +224 -0
- data_engine/services/workspaces.py +74 -0
- data_engine/ui/__init__.py +3 -0
- data_engine/ui/cli/__init__.py +19 -0
- data_engine/ui/cli/app.py +161 -0
- data_engine/ui/cli/commands_doctor.py +178 -0
- data_engine/ui/cli/commands_run.py +80 -0
- data_engine/ui/cli/commands_start.py +100 -0
- data_engine/ui/cli/commands_workspace.py +97 -0
- data_engine/ui/cli/dependencies.py +44 -0
- data_engine/ui/cli/parser.py +56 -0
- data_engine/ui/gui/__init__.py +25 -0
- data_engine/ui/gui/app.py +116 -0
- data_engine/ui/gui/bootstrap.py +487 -0
- data_engine/ui/gui/bootstrapper.py +140 -0
- data_engine/ui/gui/cache_models.py +23 -0
- data_engine/ui/gui/control_support.py +185 -0
- data_engine/ui/gui/controllers/__init__.py +6 -0
- data_engine/ui/gui/controllers/flows.py +439 -0
- data_engine/ui/gui/controllers/runtime.py +245 -0
- data_engine/ui/gui/dialogs/__init__.py +12 -0
- data_engine/ui/gui/dialogs/messages.py +88 -0
- data_engine/ui/gui/dialogs/previews.py +222 -0
- data_engine/ui/gui/helpers/__init__.py +62 -0
- data_engine/ui/gui/helpers/inspection.py +81 -0
- data_engine/ui/gui/helpers/lifecycle.py +112 -0
- data_engine/ui/gui/helpers/scroll.py +28 -0
- data_engine/ui/gui/helpers/theming.py +87 -0
- data_engine/ui/gui/icons/dark_light.svg +12 -0
- data_engine/ui/gui/icons/documentation.svg +1 -0
- data_engine/ui/gui/icons/failed.svg +3 -0
- data_engine/ui/gui/icons/group.svg +4 -0
- data_engine/ui/gui/icons/home.svg +2 -0
- data_engine/ui/gui/icons/manual.svg +2 -0
- data_engine/ui/gui/icons/poll.svg +2 -0
- data_engine/ui/gui/icons/schedule.svg +4 -0
- data_engine/ui/gui/icons/settings.svg +2 -0
- data_engine/ui/gui/icons/started.svg +3 -0
- data_engine/ui/gui/icons/success.svg +3 -0
- data_engine/ui/gui/icons/view-log.svg +3 -0
- data_engine/ui/gui/icons.py +50 -0
- data_engine/ui/gui/launcher.py +48 -0
- data_engine/ui/gui/presenters/__init__.py +72 -0
- data_engine/ui/gui/presenters/docs.py +140 -0
- data_engine/ui/gui/presenters/logs.py +58 -0
- data_engine/ui/gui/presenters/runtime_projection.py +29 -0
- data_engine/ui/gui/presenters/sidebar.py +88 -0
- data_engine/ui/gui/presenters/steps.py +148 -0
- data_engine/ui/gui/presenters/workspace.py +39 -0
- data_engine/ui/gui/presenters/workspace_binding.py +75 -0
- data_engine/ui/gui/presenters/workspace_settings.py +182 -0
- data_engine/ui/gui/preview_models.py +37 -0
- data_engine/ui/gui/render_support.py +241 -0
- data_engine/ui/gui/rendering/__init__.py +12 -0
- data_engine/ui/gui/rendering/artifacts.py +95 -0
- data_engine/ui/gui/rendering/icons.py +50 -0
- data_engine/ui/gui/runtime.py +47 -0
- data_engine/ui/gui/state_support.py +193 -0
- data_engine/ui/gui/support.py +214 -0
- data_engine/ui/gui/surface.py +209 -0
- data_engine/ui/gui/theme.py +720 -0
- data_engine/ui/gui/widgets/__init__.py +34 -0
- data_engine/ui/gui/widgets/config.py +41 -0
- data_engine/ui/gui/widgets/logs.py +62 -0
- data_engine/ui/gui/widgets/panels.py +507 -0
- data_engine/ui/gui/widgets/sidebar.py +130 -0
- data_engine/ui/gui/widgets/steps.py +84 -0
- data_engine/ui/tui/__init__.py +5 -0
- data_engine/ui/tui/app.py +222 -0
- data_engine/ui/tui/bootstrap.py +475 -0
- data_engine/ui/tui/bootstrapper.py +117 -0
- data_engine/ui/tui/controllers/__init__.py +6 -0
- data_engine/ui/tui/controllers/flows.py +349 -0
- data_engine/ui/tui/controllers/runtime.py +167 -0
- data_engine/ui/tui/runtime.py +34 -0
- data_engine/ui/tui/state_support.py +141 -0
- data_engine/ui/tui/support.py +63 -0
- data_engine/ui/tui/theme.py +204 -0
- data_engine/ui/tui/widgets.py +123 -0
- data_engine/views/__init__.py +109 -0
- data_engine/views/actions.py +80 -0
- data_engine/views/artifacts.py +58 -0
- data_engine/views/flow_display.py +69 -0
- data_engine/views/logs.py +54 -0
- data_engine/views/models.py +96 -0
- data_engine/views/presentation.py +133 -0
- data_engine/views/runs.py +62 -0
- data_engine/views/state.py +39 -0
- data_engine/views/status.py +13 -0
- data_engine/views/text.py +109 -0
- py_data_engine-0.1.0.dist-info/METADATA +330 -0
- py_data_engine-0.1.0.dist-info/RECORD +200 -0
- py_data_engine-0.1.0.dist-info/WHEEL +5 -0
- py_data_engine-0.1.0.dist-info/entry_points.txt +2 -0
- py_data_engine-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Rendering and widget-presentation helpers for the GUI application shell."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from PySide6.QtCore import Qt
|
|
9
|
+
from PySide6.QtGui import QColor, QIcon, QPixmap
|
|
10
|
+
from PySide6.QtWidgets import QFrame, QHBoxLayout, QLabel, QPushButton, QStyle, QWidget
|
|
11
|
+
|
|
12
|
+
from data_engine.domain import FlowLogEntry, RuntimeStepEvent
|
|
13
|
+
from data_engine.ui.gui.helpers import (
|
|
14
|
+
action_bar_icon as helper_action_bar_icon,
|
|
15
|
+
apply_theme as helper_apply_theme,
|
|
16
|
+
artifact_key_for_operation as helper_artifact_key_for_operation,
|
|
17
|
+
capture_step_outputs as helper_capture_step_outputs,
|
|
18
|
+
group_icon as helper_group_icon,
|
|
19
|
+
group_icon_color as helper_group_icon_color,
|
|
20
|
+
inspect_step_output as helper_inspect_step_output,
|
|
21
|
+
is_inspectable_operation as helper_is_inspectable_operation,
|
|
22
|
+
log_icon as helper_log_icon,
|
|
23
|
+
refresh_operation_buttons as helper_refresh_operation_buttons,
|
|
24
|
+
rehydrate_step_outputs_from_ledger as helper_rehydrate_step_outputs_from_ledger,
|
|
25
|
+
render_group_icon_pixmap as helper_render_group_icon_pixmap,
|
|
26
|
+
render_svg_icon_pixmap as helper_render_svg_icon_pixmap,
|
|
27
|
+
show_config_preview as helper_show_config_preview,
|
|
28
|
+
show_output_preview as helper_show_output_preview,
|
|
29
|
+
sync_theme_to_system as helper_sync_theme_to_system,
|
|
30
|
+
toggle_theme as helper_toggle_theme,
|
|
31
|
+
update_operation_scroll_cues as helper_update_operation_scroll_cues,
|
|
32
|
+
update_sidebar_scroll_cues as helper_update_sidebar_scroll_cues,
|
|
33
|
+
view_rail_icon as helper_view_rail_icon,
|
|
34
|
+
)
|
|
35
|
+
from data_engine.ui.gui.presenters import refresh_sidebar_selection, refresh_sidebar_state_views, repolish_widget_tree, set_hovered
|
|
36
|
+
from data_engine.ui.gui.presenters import (
|
|
37
|
+
apply_runtime_event as present_runtime_event,
|
|
38
|
+
duration_text as present_duration_text,
|
|
39
|
+
format_raw_log_message as present_format_raw_log_message,
|
|
40
|
+
format_seconds as present_format_seconds,
|
|
41
|
+
normalize_completed_operation_rows as present_normalize_completed_operation_rows,
|
|
42
|
+
refresh_live_operation_durations as present_refresh_live_operation_durations,
|
|
43
|
+
render_operation_durations as present_render_operation_durations,
|
|
44
|
+
reset_operation_state as present_reset_operation_state,
|
|
45
|
+
)
|
|
46
|
+
from data_engine.ui.gui.widgets import (
|
|
47
|
+
build_flow_row_widget,
|
|
48
|
+
build_group_row_widget,
|
|
49
|
+
format_operation_title as view_format_operation_title,
|
|
50
|
+
set_operation_cards as view_set_operation_cards,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if TYPE_CHECKING:
|
|
54
|
+
from data_engine.ui.gui.app import DataEngineWindow
|
|
55
|
+
from data_engine.views.models import QtFlowCard
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class GuiRenderingMixin:
|
|
59
|
+
"""Widget rendering and visual-state helpers for the GUI shell."""
|
|
60
|
+
|
|
61
|
+
def _format_raw_log_message(self: "DataEngineWindow", entry: FlowLogEntry) -> str:
|
|
62
|
+
return present_format_raw_log_message(entry)
|
|
63
|
+
|
|
64
|
+
def _set_operation_cards(self: "DataEngineWindow", operation_items: tuple[str, ...]) -> None:
|
|
65
|
+
view_set_operation_cards(self, operation_items)
|
|
66
|
+
|
|
67
|
+
def _update_operation_scroll_cues(self: "DataEngineWindow", *args) -> None:
|
|
68
|
+
helper_update_operation_scroll_cues(self, *args)
|
|
69
|
+
|
|
70
|
+
def _update_sidebar_scroll_cues(self: "DataEngineWindow", *args) -> None:
|
|
71
|
+
helper_update_sidebar_scroll_cues(self, *args)
|
|
72
|
+
|
|
73
|
+
def _format_operation_title(self: "DataEngineWindow", operation_name: str) -> str:
|
|
74
|
+
return view_format_operation_title(operation_name)
|
|
75
|
+
|
|
76
|
+
def _reset_operation_state(self: "DataEngineWindow", flow_name: str) -> None:
|
|
77
|
+
present_reset_operation_state(self, flow_name)
|
|
78
|
+
|
|
79
|
+
def _apply_runtime_event(self: "DataEngineWindow", event: RuntimeStepEvent) -> None:
|
|
80
|
+
present_runtime_event(self, event)
|
|
81
|
+
|
|
82
|
+
def _render_operation_durations(self: "DataEngineWindow", flow_name: str) -> None:
|
|
83
|
+
present_render_operation_durations(self, flow_name)
|
|
84
|
+
|
|
85
|
+
def _duration_text(self: "DataEngineWindow", flow_name: str, operation_name: str) -> str:
|
|
86
|
+
return present_duration_text(self, flow_name, operation_name)
|
|
87
|
+
|
|
88
|
+
def _refresh_live_operation_durations(self: "DataEngineWindow") -> None:
|
|
89
|
+
present_refresh_live_operation_durations(self)
|
|
90
|
+
|
|
91
|
+
def _apply_operation_row_state(self: "DataEngineWindow", row_card: QFrame, row_state) -> None:
|
|
92
|
+
status = row_state.status if row_state is not None else "idle"
|
|
93
|
+
if row_card.property("stepState") == status:
|
|
94
|
+
return
|
|
95
|
+
row_card.setProperty("stepState", status)
|
|
96
|
+
style = row_card.style()
|
|
97
|
+
style.unpolish(row_card)
|
|
98
|
+
style.polish(row_card)
|
|
99
|
+
row_card.update()
|
|
100
|
+
|
|
101
|
+
def _flash_operation_row(self: "DataEngineWindow", index: int) -> None:
|
|
102
|
+
from data_engine.ui.gui.presenters.steps import flash_operation_row
|
|
103
|
+
|
|
104
|
+
flash_operation_row(self, index)
|
|
105
|
+
|
|
106
|
+
def _normalize_completed_operation_rows(self: "DataEngineWindow", flow_name: str) -> None:
|
|
107
|
+
present_normalize_completed_operation_rows(self, flow_name)
|
|
108
|
+
|
|
109
|
+
def _format_seconds(self: "DataEngineWindow", seconds: float) -> str:
|
|
110
|
+
return present_format_seconds(seconds)
|
|
111
|
+
|
|
112
|
+
def _group_icon(self: "DataEngineWindow", group_name: str) -> QIcon:
|
|
113
|
+
return helper_group_icon(self, group_name)
|
|
114
|
+
|
|
115
|
+
def _group_icon_color(self: "DataEngineWindow") -> QColor:
|
|
116
|
+
return helper_group_icon_color(self)
|
|
117
|
+
|
|
118
|
+
def _render_svg_icon_pixmap(
|
|
119
|
+
self: "DataEngineWindow", icon_name: str, size: int, *, fill_color: str | None = None
|
|
120
|
+
) -> QPixmap:
|
|
121
|
+
return helper_render_svg_icon_pixmap(self, icon_name, size, fill_color=fill_color)
|
|
122
|
+
|
|
123
|
+
def _view_rail_icon(self: "DataEngineWindow", view_name: str) -> QIcon:
|
|
124
|
+
return helper_view_rail_icon(self, view_name)
|
|
125
|
+
|
|
126
|
+
def _action_bar_icon(self: "DataEngineWindow", action_name: str) -> QIcon:
|
|
127
|
+
return helper_action_bar_icon(self, action_name)
|
|
128
|
+
|
|
129
|
+
def _log_icon(self: "DataEngineWindow", icon_name: str, size: int = 16) -> QIcon:
|
|
130
|
+
return helper_log_icon(self, icon_name, size)
|
|
131
|
+
|
|
132
|
+
def _render_group_icon_pixmap(self: "DataEngineWindow", group_name: str, size: int) -> QPixmap:
|
|
133
|
+
return helper_render_group_icon_pixmap(self, group_name, size)
|
|
134
|
+
|
|
135
|
+
def _build_group_row_widget(self: "DataEngineWindow", group_name: str, entries: list["QtFlowCard"]) -> QFrame:
|
|
136
|
+
return build_group_row_widget(self, group_name, entries)
|
|
137
|
+
|
|
138
|
+
def _build_flow_row_widget(self: "DataEngineWindow", card: "QtFlowCard") -> QFrame:
|
|
139
|
+
return build_flow_row_widget(self, card)
|
|
140
|
+
|
|
141
|
+
def _build_log_run_widget(self: "DataEngineWindow", run_group) -> QFrame:
|
|
142
|
+
frame = QFrame()
|
|
143
|
+
frame.setObjectName("logRunRow")
|
|
144
|
+
layout = QHBoxLayout(frame)
|
|
145
|
+
layout.setContentsMargins(8, 6, 8, 6)
|
|
146
|
+
layout.setSpacing(10)
|
|
147
|
+
|
|
148
|
+
title_row = QHBoxLayout()
|
|
149
|
+
title_row.setContentsMargins(0, 0, 0, 0)
|
|
150
|
+
title_row.setSpacing(8)
|
|
151
|
+
title = QLabel(run_group.display_label)
|
|
152
|
+
title.setObjectName("logPrimary")
|
|
153
|
+
title_row.addWidget(title, 0, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
|
|
154
|
+
if run_group.elapsed_seconds is not None:
|
|
155
|
+
duration = QLabel(self._format_seconds(run_group.elapsed_seconds))
|
|
156
|
+
duration.setObjectName("logDuration")
|
|
157
|
+
title_row.addWidget(duration, 0, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
|
|
158
|
+
title_row.addStretch(1)
|
|
159
|
+
layout.addLayout(title_row, 1)
|
|
160
|
+
|
|
161
|
+
status_name = "failed" if run_group.status in {"failed", "stopped"} else "started" if run_group.status == "started" else "finished"
|
|
162
|
+
status_icon = QLabel()
|
|
163
|
+
status_icon.setObjectName("logStatusIcon")
|
|
164
|
+
status_icon.setPixmap(self._render_svg_icon_pixmap(self._LOG_ICON_NAMES[status_name], 16, fill_color=self._LOG_ICON_COLORS[status_name]))
|
|
165
|
+
status_icon.setToolTip(run_group.status.title())
|
|
166
|
+
layout.addWidget(status_icon, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
167
|
+
|
|
168
|
+
view_button = QPushButton()
|
|
169
|
+
view_button.setObjectName("logIconButton")
|
|
170
|
+
view_button.setIcon(self._log_icon("view_log"))
|
|
171
|
+
view_button.setIconSize(QPixmap(16, 16).size())
|
|
172
|
+
view_button.setToolTip("View Log")
|
|
173
|
+
view_button.clicked.connect(lambda _checked=False, group=run_group: self._show_run_log_preview(group))
|
|
174
|
+
layout.addWidget(view_button, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
175
|
+
|
|
176
|
+
return frame
|
|
177
|
+
|
|
178
|
+
def _refresh_sidebar_selection(self: "DataEngineWindow") -> None:
|
|
179
|
+
refresh_sidebar_selection(self)
|
|
180
|
+
|
|
181
|
+
def _refresh_sidebar_state_views(self: "DataEngineWindow", changed_flow_names: set[str]) -> None:
|
|
182
|
+
"""Refresh sidebar labels/colors in place for state-only changes."""
|
|
183
|
+
if refresh_sidebar_state_views(self, changed_flow_names):
|
|
184
|
+
self._populate_flow_tree()
|
|
185
|
+
|
|
186
|
+
def _set_hovered(self: "DataEngineWindow", widget: QFrame, hovered: bool) -> None:
|
|
187
|
+
"""Update one sidebar row hover property and repolish it."""
|
|
188
|
+
set_hovered(widget, hovered)
|
|
189
|
+
|
|
190
|
+
def _repolish_widget_tree(self: "DataEngineWindow", widget: QWidget) -> None:
|
|
191
|
+
"""Reapply stylesheet state to one widget and its child widgets."""
|
|
192
|
+
repolish_widget_tree(widget)
|
|
193
|
+
|
|
194
|
+
def _flow_icon(self: "DataEngineWindow", card: "QtFlowCard") -> QIcon:
|
|
195
|
+
"""Return a left-side icon for one flow row."""
|
|
196
|
+
style = self.style()
|
|
197
|
+
state = self.flow_states.get(card.name, card.state)
|
|
198
|
+
if state == "failed":
|
|
199
|
+
return style.standardIcon(QStyle.StandardPixmap.SP_MessageBoxCritical)
|
|
200
|
+
if state in {"running", "polling", "scheduled"}:
|
|
201
|
+
return style.standardIcon(QStyle.StandardPixmap.SP_DialogApplyButton)
|
|
202
|
+
if state in {"stopping flow", "stopping runtime"}:
|
|
203
|
+
return style.standardIcon(QStyle.StandardPixmap.SP_BrowserStop)
|
|
204
|
+
if card.mode == "schedule":
|
|
205
|
+
return style.standardIcon(QStyle.StandardPixmap.SP_FileDialogDetailedView)
|
|
206
|
+
if card.mode == "poll":
|
|
207
|
+
return style.standardIcon(QStyle.StandardPixmap.SP_BrowserReload)
|
|
208
|
+
return style.standardIcon(QStyle.StandardPixmap.SP_FileIcon)
|
|
209
|
+
|
|
210
|
+
def _toggle_theme(self: "DataEngineWindow") -> None:
|
|
211
|
+
helper_toggle_theme(self)
|
|
212
|
+
|
|
213
|
+
def _sync_theme_to_system(self: "DataEngineWindow", *args) -> None:
|
|
214
|
+
helper_sync_theme_to_system(self, *args)
|
|
215
|
+
|
|
216
|
+
def _apply_theme(self: "DataEngineWindow") -> None:
|
|
217
|
+
helper_apply_theme(self)
|
|
218
|
+
|
|
219
|
+
def _is_inspectable_operation(self: "DataEngineWindow", operation_name: str) -> bool:
|
|
220
|
+
return helper_is_inspectable_operation(operation_name)
|
|
221
|
+
|
|
222
|
+
def _artifact_key_for_operation(self: "DataEngineWindow", operation_name: str) -> str | None:
|
|
223
|
+
return helper_artifact_key_for_operation(operation_name)
|
|
224
|
+
|
|
225
|
+
def _capture_step_outputs(self: "DataEngineWindow", flow_name: str, results: object) -> None:
|
|
226
|
+
helper_capture_step_outputs(self, flow_name, results)
|
|
227
|
+
|
|
228
|
+
def _rehydrate_step_outputs_from_ledger(self: "DataEngineWindow") -> None:
|
|
229
|
+
helper_rehydrate_step_outputs_from_ledger(self)
|
|
230
|
+
|
|
231
|
+
def _refresh_operation_buttons(self: "DataEngineWindow", flow_name: str) -> None:
|
|
232
|
+
helper_refresh_operation_buttons(self, flow_name)
|
|
233
|
+
|
|
234
|
+
def _inspect_step_output(self: "DataEngineWindow", operation_name: str) -> None:
|
|
235
|
+
helper_inspect_step_output(self, operation_name)
|
|
236
|
+
|
|
237
|
+
def _show_output_preview(self: "DataEngineWindow", operation_name: str, output_path: Path) -> None:
|
|
238
|
+
helper_show_output_preview(self, operation_name, output_path)
|
|
239
|
+
|
|
240
|
+
def _show_config_preview(self: "DataEngineWindow") -> None:
|
|
241
|
+
helper_show_config_preview(self)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Rendering helpers for the desktop UI."""
|
|
2
|
+
|
|
3
|
+
from data_engine.ui.gui.rendering.artifacts import ArtifactPreviewSpec, classify_artifact_preview, populate_output_preview
|
|
4
|
+
from data_engine.ui.gui.rendering.icons import render_svg_icon_pixmap, theme_svg_paths
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"ArtifactPreviewSpec",
|
|
8
|
+
"classify_artifact_preview",
|
|
9
|
+
"populate_output_preview",
|
|
10
|
+
"render_svg_icon_pixmap",
|
|
11
|
+
"theme_svg_paths",
|
|
12
|
+
]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Artifact classification and preview rendering helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import polars as pl
|
|
8
|
+
from PySide6.QtWidgets import (
|
|
9
|
+
QAbstractItemView,
|
|
10
|
+
QHeaderView,
|
|
11
|
+
QLabel,
|
|
12
|
+
QTableWidget,
|
|
13
|
+
QTableWidgetItem,
|
|
14
|
+
QTextEdit,
|
|
15
|
+
QVBoxLayout,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from data_engine.views import ArtifactPreviewSpec, classify_artifact_preview
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def populate_output_preview(layout: QVBoxLayout, output_path: Path, preview_spec: ArtifactPreviewSpec | None = None) -> None:
|
|
22
|
+
"""Populate one dialog layout with the appropriate artifact preview widgets."""
|
|
23
|
+
preview_spec = preview_spec or classify_artifact_preview(output_path)
|
|
24
|
+
if preview_spec.kind == "parquet":
|
|
25
|
+
_add_tabular_preview(layout, pl.read_parquet(output_path), preview_spec.label)
|
|
26
|
+
return
|
|
27
|
+
if preview_spec.kind == "excel":
|
|
28
|
+
_add_tabular_preview(layout, pl.read_excel(output_path, sheet_id=1, engine="calamine"), preview_spec.label)
|
|
29
|
+
return
|
|
30
|
+
if preview_spec.kind == "text":
|
|
31
|
+
_add_text_preview(layout, output_path, preview_spec.label)
|
|
32
|
+
return
|
|
33
|
+
if preview_spec.kind == "pdf":
|
|
34
|
+
_add_placeholder_preview(
|
|
35
|
+
layout,
|
|
36
|
+
heading=preview_spec.label,
|
|
37
|
+
message=preview_spec.placeholder_message or "PDF artifacts are recognized, but in-app PDF text inspection is not available yet.",
|
|
38
|
+
output_path=output_path,
|
|
39
|
+
)
|
|
40
|
+
return
|
|
41
|
+
_add_placeholder_preview(
|
|
42
|
+
layout,
|
|
43
|
+
heading=preview_spec.label,
|
|
44
|
+
message=preview_spec.placeholder_message or "This artifact type is not previewable in the UI yet.",
|
|
45
|
+
output_path=output_path,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _add_tabular_preview(layout: QVBoxLayout, frame: pl.DataFrame, heading: str) -> None:
|
|
50
|
+
meta_label = QLabel(f"{heading} {frame.height} row(s) x {len(frame.columns)} column(s) Previewing up to 200 rows")
|
|
51
|
+
meta_label.setObjectName("sectionMeta")
|
|
52
|
+
layout.addWidget(meta_label)
|
|
53
|
+
|
|
54
|
+
table = QTableWidget()
|
|
55
|
+
table.setObjectName("outputPreviewTable")
|
|
56
|
+
table.setColumnCount(len(frame.columns))
|
|
57
|
+
table.setHorizontalHeaderLabels(frame.columns)
|
|
58
|
+
preview = frame.head(200)
|
|
59
|
+
table.setRowCount(preview.height)
|
|
60
|
+
table.setAlternatingRowColors(True)
|
|
61
|
+
table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
|
62
|
+
table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
|
63
|
+
table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
|
64
|
+
table.setShowGrid(False)
|
|
65
|
+
table.verticalHeader().setVisible(False)
|
|
66
|
+
table.horizontalHeader().setStretchLastSection(True)
|
|
67
|
+
table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
|
|
68
|
+
for row_index in range(preview.height):
|
|
69
|
+
for column_index, column_name in enumerate(preview.columns):
|
|
70
|
+
table.setItem(row_index, column_index, QTableWidgetItem(str(preview[row_index, column_name])))
|
|
71
|
+
layout.addWidget(table, 1)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _add_text_preview(layout: QVBoxLayout, output_path: Path, heading: str) -> None:
|
|
75
|
+
meta_label = QLabel(heading)
|
|
76
|
+
meta_label.setObjectName("sectionMeta")
|
|
77
|
+
layout.addWidget(meta_label)
|
|
78
|
+
body = QTextEdit()
|
|
79
|
+
body.setObjectName("outputPreviewText")
|
|
80
|
+
body.setReadOnly(True)
|
|
81
|
+
body.setPlainText(output_path.read_text(encoding="utf-8"))
|
|
82
|
+
layout.addWidget(body, 1)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _add_placeholder_preview(layout: QVBoxLayout, *, heading: str, message: str, output_path: Path) -> None:
|
|
86
|
+
size_bytes = output_path.stat().st_size if output_path.exists() else 0
|
|
87
|
+
meta_label = QLabel(f"{heading} {size_bytes:,} bytes")
|
|
88
|
+
meta_label.setObjectName("sectionMeta")
|
|
89
|
+
layout.addWidget(meta_label)
|
|
90
|
+
body = QTextEdit()
|
|
91
|
+
body.setObjectName("outputPreviewText")
|
|
92
|
+
body.setReadOnly(True)
|
|
93
|
+
body.setPlainText(message)
|
|
94
|
+
layout.addWidget(body, 1)
|
|
95
|
+
__all__ = ["ArtifactPreviewSpec", "classify_artifact_preview", "populate_output_preview"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Theme-aware SVG icon rendering helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from PySide6.QtCore import QRectF, Qt
|
|
8
|
+
from PySide6.QtGui import QColor, QPainter, QPixmap
|
|
9
|
+
from PySide6.QtSvg import QSvgRenderer
|
|
10
|
+
|
|
11
|
+
from data_engine.ui.gui.icons import load_svg_icon_text
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def theme_svg_paths(svg_text: str, fill: str) -> str:
|
|
15
|
+
"""Apply one fill color to every SVG path element in one icon."""
|
|
16
|
+
|
|
17
|
+
def _replace(match: re.Match[str]) -> str:
|
|
18
|
+
attributes = re.sub(r'\sfill="[^"]*"', "", match.group(1))
|
|
19
|
+
return f'<path fill="{fill}"{attributes}>'
|
|
20
|
+
|
|
21
|
+
return re.sub(r"<path\b([^>]*)>", _replace, svg_text)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def render_svg_icon_pixmap(
|
|
25
|
+
*,
|
|
26
|
+
icon_name: str,
|
|
27
|
+
size: int,
|
|
28
|
+
device_pixel_ratio: float,
|
|
29
|
+
fill_color: str | None = None,
|
|
30
|
+
default_fill_color: QColor | str,
|
|
31
|
+
) -> QPixmap:
|
|
32
|
+
"""Render one registered SVG icon to one theme-aware pixmap."""
|
|
33
|
+
svg_text = load_svg_icon_text(icon_name)
|
|
34
|
+
if isinstance(default_fill_color, QColor):
|
|
35
|
+
default_fill = default_fill_color.name()
|
|
36
|
+
else:
|
|
37
|
+
default_fill = str(default_fill_color)
|
|
38
|
+
themed_svg = theme_svg_paths(svg_text, fill_color or default_fill)
|
|
39
|
+
renderer = QSvgRenderer(themed_svg.encode("utf-8"))
|
|
40
|
+
dpr = max(1.0, float(device_pixel_ratio))
|
|
41
|
+
pixmap = QPixmap(int(size * dpr), int(size * dpr))
|
|
42
|
+
pixmap.setDevicePixelRatio(dpr)
|
|
43
|
+
pixmap.fill(Qt.GlobalColor.transparent)
|
|
44
|
+
painter = QPainter(pixmap)
|
|
45
|
+
renderer.render(painter, QRectF(0, 0, size, size))
|
|
46
|
+
painter.end()
|
|
47
|
+
return pixmap
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
__all__ = ["render_svg_icon_pixmap", "theme_svg_paths"]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Runtime wiring helpers for the Data Engine desktop UI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from queue import Queue
|
|
7
|
+
|
|
8
|
+
from PySide6.QtCore import QObject, Signal
|
|
9
|
+
|
|
10
|
+
from data_engine.domain import FlowLogEntry, format_log_line, parse_runtime_event
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class QueueLogHandler(logging.Handler):
|
|
14
|
+
"""Logging handler that forwards formatted runtime lines into a queue."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, queue: Queue[FlowLogEntry]) -> None:
|
|
17
|
+
"""Initialize the handler with the queue consumed by the UI thread."""
|
|
18
|
+
super().__init__(level=logging.INFO)
|
|
19
|
+
self.queue = queue
|
|
20
|
+
|
|
21
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
22
|
+
"""Convert one log record into a UI entry and enqueue it."""
|
|
23
|
+
try:
|
|
24
|
+
event = parse_runtime_event(record)
|
|
25
|
+
kind = "flow" if event is not None and event.flow_name is not None else "system"
|
|
26
|
+
self.queue.put_nowait(
|
|
27
|
+
FlowLogEntry(
|
|
28
|
+
line=format_log_line(record),
|
|
29
|
+
kind=kind,
|
|
30
|
+
event=event,
|
|
31
|
+
flow_name=event.flow_name if event is not None else None,
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
except Exception:
|
|
35
|
+
self.handleError(record)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class UiSignals(QObject):
|
|
39
|
+
"""Cross-thread Qt signals used by background runtime workers."""
|
|
40
|
+
|
|
41
|
+
run_finished = Signal(object, object, object)
|
|
42
|
+
runtime_finished = Signal(object, object, object)
|
|
43
|
+
docs_build_finished = Signal(bool, str)
|
|
44
|
+
daemon_startup_finished = Signal(bool, str)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
__all__ = ["FlowLogEntry", "QueueLogHandler", "UiSignals"]
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""Operator-session and log plumbing helpers for the GUI shell."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from data_engine.domain import (
|
|
9
|
+
DaemonStatusState,
|
|
10
|
+
FlowLogEntry,
|
|
11
|
+
FlowCatalogState,
|
|
12
|
+
OperationSessionState,
|
|
13
|
+
OperatorSessionState,
|
|
14
|
+
RuntimeSessionState,
|
|
15
|
+
WorkspaceControlState,
|
|
16
|
+
WorkspaceSessionState,
|
|
17
|
+
)
|
|
18
|
+
from data_engine.ui.gui.surface import (
|
|
19
|
+
append_log_entry as surface_append_log_entry,
|
|
20
|
+
append_log_line as surface_append_log_line,
|
|
21
|
+
flush_deferred_ui_updates as surface_flush_deferred_ui_updates,
|
|
22
|
+
log_matches_selection as surface_log_matches_selection,
|
|
23
|
+
schedule_ui_refresh as surface_schedule_ui_refresh,
|
|
24
|
+
)
|
|
25
|
+
from data_engine.views.models import QtFlowCard, flow_catalog_entry_from_qt_card, qt_flow_cards_from_entries
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from data_engine.ui.gui.app import DataEngineWindow
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class GuiStateMixin:
|
|
32
|
+
"""Session-state and log-queue helpers separated from the main GUI shell."""
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def runtime_ledger(self: "DataEngineWindow"):
|
|
36
|
+
"""Compatibility facade over the current runtime binding ledger."""
|
|
37
|
+
return self.runtime_binding.runtime_ledger
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def log_store(self: "DataEngineWindow"):
|
|
41
|
+
"""Compatibility facade over the current runtime binding log store."""
|
|
42
|
+
return self.runtime_binding.log_store
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def _daemon_manager(self: "DataEngineWindow"):
|
|
46
|
+
"""Compatibility facade over the current runtime binding daemon manager."""
|
|
47
|
+
return self.runtime_binding.daemon_manager
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def runtime_session(self: "DataEngineWindow") -> RuntimeSessionState:
|
|
51
|
+
"""Return the current operator runtime/control session state."""
|
|
52
|
+
return self._operator_session_state.runtime
|
|
53
|
+
|
|
54
|
+
@runtime_session.setter
|
|
55
|
+
def runtime_session(self: "DataEngineWindow", value: RuntimeSessionState) -> None:
|
|
56
|
+
self._operator_session_state = self._operator_session_state.with_runtime(value)
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def flow_catalog_state(self: "DataEngineWindow") -> FlowCatalogState:
|
|
60
|
+
"""Return the current discovered flow catalog state."""
|
|
61
|
+
return self._operator_session_state.catalog
|
|
62
|
+
|
|
63
|
+
@flow_catalog_state.setter
|
|
64
|
+
def flow_catalog_state(self: "DataEngineWindow", value: FlowCatalogState) -> None:
|
|
65
|
+
self._operator_session_state = self._operator_session_state.with_catalog(value)
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def flow_cards(self: "DataEngineWindow") -> dict[str, QtFlowCard]:
|
|
69
|
+
return {card.name: card for card in qt_flow_cards_from_entries(self.flow_catalog_state.entries)}
|
|
70
|
+
|
|
71
|
+
@flow_cards.setter
|
|
72
|
+
def flow_cards(self: "DataEngineWindow", value: dict[str, QtFlowCard] | tuple[QtFlowCard, ...]) -> None:
|
|
73
|
+
cards = tuple(value.values()) if isinstance(value, dict) else tuple(value)
|
|
74
|
+
self.flow_catalog_state = self.flow_catalog_state.with_entries(
|
|
75
|
+
tuple(flow_catalog_entry_from_qt_card(card) for card in cards)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def flow_states(self: "DataEngineWindow") -> dict[str, str]:
|
|
80
|
+
return self.flow_catalog_state.flow_states or {}
|
|
81
|
+
|
|
82
|
+
@flow_states.setter
|
|
83
|
+
def flow_states(self: "DataEngineWindow", value: dict[str, str]) -> None:
|
|
84
|
+
self.flow_catalog_state = self.flow_catalog_state.with_flow_states(value)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def selected_flow_name(self: "DataEngineWindow") -> str | None:
|
|
88
|
+
return self.flow_catalog_state.selected_flow_name
|
|
89
|
+
|
|
90
|
+
@selected_flow_name.setter
|
|
91
|
+
def selected_flow_name(self: "DataEngineWindow", value: str | None) -> None:
|
|
92
|
+
self.flow_catalog_state = self.flow_catalog_state.with_selected_flow_name(value)
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def empty_flow_message(self: "DataEngineWindow") -> str:
|
|
96
|
+
return self.flow_catalog_state.empty_message
|
|
97
|
+
|
|
98
|
+
@empty_flow_message.setter
|
|
99
|
+
def empty_flow_message(self: "DataEngineWindow", value: str) -> None:
|
|
100
|
+
self.flow_catalog_state = self.flow_catalog_state.with_empty_message(value)
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def daemon_status(self: "DataEngineWindow") -> DaemonStatusState:
|
|
104
|
+
"""Return the current daemon status domain model."""
|
|
105
|
+
return self._daemon_status
|
|
106
|
+
|
|
107
|
+
@daemon_status.setter
|
|
108
|
+
def daemon_status(self: "DataEngineWindow", value: DaemonStatusState) -> None:
|
|
109
|
+
self._daemon_status = value
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def workspace_control_state(self: "DataEngineWindow") -> WorkspaceControlState:
|
|
113
|
+
"""Return the current structured workspace control state."""
|
|
114
|
+
return self._operator_session_state.workspace_control
|
|
115
|
+
|
|
116
|
+
@workspace_control_state.setter
|
|
117
|
+
def workspace_control_state(self: "DataEngineWindow", value: WorkspaceControlState) -> None:
|
|
118
|
+
self._operator_session_state = self._operator_session_state.with_workspace_control(value)
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def workspace_session_state(self: "DataEngineWindow") -> WorkspaceSessionState:
|
|
122
|
+
"""Return the current workspace selection/root session state."""
|
|
123
|
+
return self._operator_session_state.workspace
|
|
124
|
+
|
|
125
|
+
@workspace_session_state.setter
|
|
126
|
+
def workspace_session_state(self: "DataEngineWindow", value: WorkspaceSessionState) -> None:
|
|
127
|
+
self._operator_session_state = self._operator_session_state.with_workspace(value)
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def operator_session_state(self: "DataEngineWindow") -> OperatorSessionState:
|
|
131
|
+
"""Return the top-level operator session state for this surface."""
|
|
132
|
+
return self._operator_session_state
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def operation_tracker(self: "DataEngineWindow") -> OperationSessionState:
|
|
136
|
+
"""Return the current operation/step session state."""
|
|
137
|
+
return self._operator_session_state.operations
|
|
138
|
+
|
|
139
|
+
@operation_tracker.setter
|
|
140
|
+
def operation_tracker(self: "DataEngineWindow", value: OperationSessionState) -> None:
|
|
141
|
+
self._operator_session_state = self._operator_session_state.with_operations(value)
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def docs_build_running(self: "DataEngineWindow") -> bool:
|
|
145
|
+
"""Return whether the documentation build is currently active for this GUI window."""
|
|
146
|
+
return self._docs_build_running
|
|
147
|
+
|
|
148
|
+
@docs_build_running.setter
|
|
149
|
+
def docs_build_running(self: "DataEngineWindow", value: bool) -> None:
|
|
150
|
+
self._docs_build_running = bool(value)
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def docs_root_dir(self: "DataEngineWindow") -> Path | None:
|
|
154
|
+
"""Return the current built-docs root directory for this GUI window, if available."""
|
|
155
|
+
return self._docs_root_dir
|
|
156
|
+
|
|
157
|
+
@docs_root_dir.setter
|
|
158
|
+
def docs_root_dir(self: "DataEngineWindow", value: Path | None) -> None:
|
|
159
|
+
self._docs_root_dir = value
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def workspace_collection_root_override(self: "DataEngineWindow") -> Path | None:
|
|
163
|
+
return self.workspace_session_state.workspace_collection_root_override
|
|
164
|
+
|
|
165
|
+
@workspace_collection_root_override.setter
|
|
166
|
+
def workspace_collection_root_override(self: "DataEngineWindow", value: Path | None) -> None:
|
|
167
|
+
self.workspace_session_state = self.workspace_session_state.with_override_root(value)
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def discovered_workspace_ids(self: "DataEngineWindow") -> tuple[str, ...]:
|
|
171
|
+
return self.workspace_session_state.discovered_workspace_ids
|
|
172
|
+
|
|
173
|
+
@discovered_workspace_ids.setter
|
|
174
|
+
def discovered_workspace_ids(self: "DataEngineWindow", value: tuple[str, ...]) -> None:
|
|
175
|
+
self.workspace_session_state = self.workspace_session_state.with_discovered_workspace_ids(value)
|
|
176
|
+
|
|
177
|
+
def _log_matches_selection(self: "DataEngineWindow", entry: FlowLogEntry) -> bool:
|
|
178
|
+
return surface_log_matches_selection(self, entry)
|
|
179
|
+
|
|
180
|
+
def _append_log_entry(self: "DataEngineWindow", entry: FlowLogEntry) -> None:
|
|
181
|
+
surface_append_log_entry(self, entry)
|
|
182
|
+
|
|
183
|
+
def _schedule_ui_refresh(self: "DataEngineWindow", *, log_view: bool = False, action_buttons: bool = False) -> None:
|
|
184
|
+
surface_schedule_ui_refresh(self, log_view=log_view, action_buttons=action_buttons)
|
|
185
|
+
|
|
186
|
+
def _flush_deferred_ui_updates(self: "DataEngineWindow") -> None:
|
|
187
|
+
surface_flush_deferred_ui_updates(self)
|
|
188
|
+
|
|
189
|
+
def _append_log_line(self: "DataEngineWindow", line: str, *, flow_name: str | None = None) -> None:
|
|
190
|
+
surface_append_log_line(self, line, flow_name=flow_name)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
__all__ = ["GuiStateMixin"]
|