uipath 2.1.30__py3-none-any.whl → 2.1.32__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.
- uipath/_cli/_dev/_terminal/__init__.py +55 -9
- uipath/_cli/_dev/_terminal/_components/_details.py +45 -56
- uipath/_cli/_dev/_terminal/_components/_history.py +18 -6
- uipath/_cli/_dev/_terminal/_components/_new.py +26 -27
- uipath/_cli/_dev/_terminal/_components/_resume.py +31 -0
- uipath/_cli/_dev/_terminal/_models/_execution.py +30 -8
- uipath/_cli/_dev/_terminal/_styles/terminal.tcss +3 -149
- uipath/_cli/_runtime/_runtime.py +1 -1
- {uipath-2.1.30.dist-info → uipath-2.1.32.dist-info}/METADATA +1 -1
- {uipath-2.1.30.dist-info → uipath-2.1.32.dist-info}/RECORD +13 -12
- {uipath-2.1.30.dist-info → uipath-2.1.32.dist-info}/WHEEL +0 -0
- {uipath-2.1.30.dist-info → uipath-2.1.32.dist-info}/entry_points.txt +0 -0
- {uipath-2.1.30.dist-info → uipath-2.1.32.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,6 @@
|
|
1
1
|
import asyncio
|
2
2
|
import json
|
3
|
+
import traceback
|
3
4
|
from datetime import datetime
|
4
5
|
from os import environ as env
|
5
6
|
from pathlib import Path
|
@@ -9,15 +10,19 @@ from uuid import uuid4
|
|
9
10
|
from textual.app import App, ComposeResult
|
10
11
|
from textual.binding import Binding
|
11
12
|
from textual.containers import Container, Horizontal
|
12
|
-
from textual.widgets import Button, ListView
|
13
|
+
from textual.widgets import Button, Footer, ListView
|
13
14
|
|
14
15
|
from ..._runtime._contracts import (
|
16
|
+
UiPathErrorContract,
|
15
17
|
UiPathRuntimeContext,
|
18
|
+
UiPathRuntimeError,
|
16
19
|
UiPathRuntimeFactory,
|
20
|
+
UiPathRuntimeStatus,
|
17
21
|
)
|
18
22
|
from ._components._details import RunDetailsPanel
|
19
23
|
from ._components._history import RunHistoryPanel
|
20
24
|
from ._components._new import NewRunPanel
|
25
|
+
from ._components._resume import ResumePanel
|
21
26
|
from ._models._execution import ExecutionRun
|
22
27
|
from ._models._messages import LogMessage, TraceMessage
|
23
28
|
from ._traces._exporter import RunContextExporter
|
@@ -31,8 +36,8 @@ class UiPathDevTerminal(App[Any]):
|
|
31
36
|
|
32
37
|
BINDINGS = [
|
33
38
|
Binding("q", "quit", "Quit"),
|
34
|
-
Binding("n", "new_run", "New
|
35
|
-
Binding("r", "execute_run", "
|
39
|
+
Binding("n", "new_run", "New"),
|
40
|
+
Binding("r", "execute_run", "Run"),
|
36
41
|
Binding("c", "clear_history", "Clear History"),
|
37
42
|
Binding("escape", "cancel", "Cancel"),
|
38
43
|
]
|
@@ -73,6 +78,8 @@ class UiPathDevTerminal(App[Any]):
|
|
73
78
|
# Run details panel (initially hidden)
|
74
79
|
yield RunDetailsPanel(id="details-panel", classes="hidden")
|
75
80
|
|
81
|
+
yield Footer()
|
82
|
+
|
76
83
|
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
77
84
|
"""Handle button press events."""
|
78
85
|
if event.button.id == "new-run-btn":
|
@@ -81,6 +88,8 @@ class UiPathDevTerminal(App[Any]):
|
|
81
88
|
await self.action_execute_run()
|
82
89
|
elif event.button.id == "cancel-btn":
|
83
90
|
await self.action_cancel()
|
91
|
+
elif event.button.id == "resume-btn":
|
92
|
+
await self.action_resume()
|
84
93
|
|
85
94
|
async def on_list_view_selected(self, event: ListView.Selected) -> None:
|
86
95
|
"""Handle run selection from history."""
|
@@ -104,6 +113,19 @@ class UiPathDevTerminal(App[Any]):
|
|
104
113
|
"""Cancel and return to new run view."""
|
105
114
|
await self.action_new_run()
|
106
115
|
|
116
|
+
async def action_resume(self) -> None:
|
117
|
+
"""Resume the suspended run."""
|
118
|
+
details_panel = self.query_one("#details-panel", RunDetailsPanel)
|
119
|
+
if details_panel and details_panel.current_run:
|
120
|
+
input: Dict[str, Any] = {}
|
121
|
+
input_data = self.query_one("#resume-panel", ResumePanel).get_input_values()
|
122
|
+
try:
|
123
|
+
input = json.loads(input_data)
|
124
|
+
except json.JSONDecodeError:
|
125
|
+
return
|
126
|
+
details_panel.current_run.input_data = input
|
127
|
+
asyncio.create_task(self._execute_runtime(details_panel.current_run))
|
128
|
+
|
107
129
|
async def action_execute_run(self) -> None:
|
108
130
|
"""Execute a new run with UiPath runtime."""
|
109
131
|
new_run_panel = self.query_one("#new-run-panel", NewRunPanel)
|
@@ -112,12 +134,14 @@ class UiPathDevTerminal(App[Any]):
|
|
112
134
|
if not entrypoint:
|
113
135
|
return
|
114
136
|
|
137
|
+
input: Dict[str, Any] = {}
|
115
138
|
try:
|
116
|
-
json.loads(input_data)
|
139
|
+
input = json.loads(input_data)
|
117
140
|
except json.JSONDecodeError:
|
118
141
|
return
|
119
142
|
|
120
|
-
run = ExecutionRun(entrypoint,
|
143
|
+
run = ExecutionRun(entrypoint, input)
|
144
|
+
|
121
145
|
self.runs[run.id] = run
|
122
146
|
|
123
147
|
self._add_run_in_history(run)
|
@@ -137,7 +161,7 @@ class UiPathDevTerminal(App[Any]):
|
|
137
161
|
try:
|
138
162
|
context: UiPathRuntimeContext = self.runtime_factory.new_context(
|
139
163
|
entrypoint=run.entrypoint,
|
140
|
-
|
164
|
+
input_json=run.input_data,
|
141
165
|
trace_id=str(uuid4()),
|
142
166
|
execution_id=run.id,
|
143
167
|
logs_min_level=env.get("LOG_LEVEL", "INFO"),
|
@@ -146,24 +170,46 @@ class UiPathDevTerminal(App[Any]):
|
|
146
170
|
),
|
147
171
|
)
|
148
172
|
|
149
|
-
|
173
|
+
if run.status == "suspended":
|
174
|
+
context.resume = True
|
175
|
+
self._add_info_log(run, f"Resuming execution: {run.entrypoint}")
|
176
|
+
else:
|
177
|
+
self._add_info_log(run, f"Starting execution: {run.entrypoint}")
|
178
|
+
|
179
|
+
run.status = "running"
|
180
|
+
run.start_time = datetime.now()
|
150
181
|
|
151
182
|
result = await self.runtime_factory.execute_in_root_span(context)
|
152
183
|
|
153
184
|
if result is not None:
|
154
|
-
|
185
|
+
if result.status == UiPathRuntimeStatus.SUSPENDED.value:
|
186
|
+
run.status = "suspended"
|
187
|
+
else:
|
188
|
+
run.output_data = result.output
|
189
|
+
run.status = "completed"
|
155
190
|
if run.output_data:
|
156
191
|
self._add_info_log(run, f"Execution result: {run.output_data}")
|
157
192
|
|
158
193
|
self._add_info_log(run, "✅ Execution completed successfully")
|
159
|
-
run.status = "completed"
|
160
194
|
run.end_time = datetime.now()
|
161
195
|
|
196
|
+
except UiPathRuntimeError as e:
|
197
|
+
error_msg = (
|
198
|
+
f"{e.error_info.code}: {e.error_info.title}\n{e.error_info.detail}"
|
199
|
+
)
|
200
|
+
self._add_error_log(run, error_msg)
|
201
|
+
run.status = "failed"
|
202
|
+
run.end_time = datetime.now()
|
203
|
+
run.error = e.error_info
|
204
|
+
|
162
205
|
except Exception as e:
|
163
206
|
error_msg = f"Execution failed: {str(e)}"
|
164
207
|
self._add_error_log(run, error_msg)
|
165
208
|
run.status = "failed"
|
166
209
|
run.end_time = datetime.now()
|
210
|
+
run.error = UiPathErrorContract(
|
211
|
+
code="Unknown", title=str(e), detail=traceback.format_exc()
|
212
|
+
)
|
167
213
|
|
168
214
|
self._update_run_in_history(run)
|
169
215
|
self._update_run_details(run)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import json
|
1
2
|
from typing import Dict, List, Optional
|
2
3
|
|
3
4
|
from textual.app import ComposeResult
|
@@ -8,6 +9,7 @@ from textual.widgets.tree import TreeNode
|
|
8
9
|
|
9
10
|
from .._models._execution import ExecutionRun
|
10
11
|
from .._models._messages import LogMessage, TraceMessage
|
12
|
+
from ._resume import ResumePanel
|
11
13
|
|
12
14
|
|
13
15
|
class SpanDetailsDisplay(Container):
|
@@ -112,6 +114,9 @@ class RunDetailsPanel(Container):
|
|
112
114
|
classes="detail-log",
|
113
115
|
)
|
114
116
|
|
117
|
+
with TabPane("Resume", id="resume-tab"):
|
118
|
+
yield ResumePanel(id="resume-panel")
|
119
|
+
|
115
120
|
def watch_current_run(
|
116
121
|
self, old_value: Optional[ExecutionRun], new_value: Optional[ExecutionRun]
|
117
122
|
):
|
@@ -139,8 +144,14 @@ class RunDetailsPanel(Container):
|
|
139
144
|
# Clear and rebuild traces tree using TraceMessage objects
|
140
145
|
self._rebuild_spans_tree()
|
141
146
|
|
147
|
+
def _update_resume_tab(self, run: ExecutionRun) -> None:
|
148
|
+
resume_panel = self.query_one("#resume-panel", ResumePanel)
|
149
|
+
resume_panel.display = run.status == "suspended"
|
150
|
+
|
142
151
|
def _show_run_details(self, run: ExecutionRun):
|
143
152
|
"""Display detailed information about the run in the Details tab."""
|
153
|
+
self._update_resume_tab(run)
|
154
|
+
|
144
155
|
run_details_log = self.query_one("#run-details-log", RichLog)
|
145
156
|
run_details_log.clear()
|
146
157
|
|
@@ -200,8 +211,6 @@ class RunDetailsPanel(Container):
|
|
200
211
|
if isinstance(run.input_data, str):
|
201
212
|
run_details_log.write(run.input_data)
|
202
213
|
elif isinstance(run.input_data, dict):
|
203
|
-
import json
|
204
|
-
|
205
214
|
run_details_log.write(json.dumps(run.input_data, indent=2))
|
206
215
|
else:
|
207
216
|
run_details_log.write(str(run.input_data))
|
@@ -217,8 +226,6 @@ class RunDetailsPanel(Container):
|
|
217
226
|
if isinstance(run.output_data, str):
|
218
227
|
run_details_log.write(run.output_data)
|
219
228
|
elif isinstance(run.output_data, dict):
|
220
|
-
import json
|
221
|
-
|
222
229
|
run_details_log.write(json.dumps(run.output_data, indent=2))
|
223
230
|
else:
|
224
231
|
run_details_log.write(str(run.output_data))
|
@@ -229,28 +236,12 @@ class RunDetailsPanel(Container):
|
|
229
236
|
if hasattr(run, "error") and run.error:
|
230
237
|
run_details_log.write("[bold red]ERROR:[/bold red]")
|
231
238
|
run_details_log.write("[dim]" + "=" * 50 + "[/dim]")
|
232
|
-
|
239
|
+
if run.error.code:
|
240
|
+
run_details_log.write(f"[red]Code: {run.error.code}[/red]")
|
241
|
+
run_details_log.write(f"[red]Title: {run.error.title}[/red]")
|
242
|
+
run_details_log.write(f"[red]\n{run.error.detail}[/red]")
|
233
243
|
run_details_log.write("")
|
234
244
|
|
235
|
-
# Additional metadata
|
236
|
-
run_details_log.write("[bold]METADATA:[/bold]")
|
237
|
-
run_details_log.write("[dim]" + "=" * 50 + "[/dim]")
|
238
|
-
|
239
|
-
# Show available attributes
|
240
|
-
for attr in ["id", "status", "start_time", "end_time", "duration_ms"]:
|
241
|
-
if hasattr(run, attr):
|
242
|
-
value = getattr(run, attr)
|
243
|
-
if value is not None:
|
244
|
-
run_details_log.write(f" {attr}: {value}")
|
245
|
-
|
246
|
-
# Show traces count
|
247
|
-
traces_count = len(run.traces) if run.traces else 0
|
248
|
-
run_details_log.write(f" traces_count: {traces_count}")
|
249
|
-
|
250
|
-
# Show logs count
|
251
|
-
logs_count = len(run.logs) if run.logs else 0
|
252
|
-
run_details_log.write(f" logs_count: {logs_count}")
|
253
|
-
|
254
245
|
def _rebuild_spans_tree(self):
|
255
246
|
"""Rebuild the spans tree from current run's traces."""
|
256
247
|
spans_tree = self.query_one("#spans-tree", Tree)
|
@@ -272,34 +263,38 @@ class RunDetailsPanel(Container):
|
|
272
263
|
spans_tree = self.query_one("#spans-tree", Tree)
|
273
264
|
root = spans_tree.root
|
274
265
|
|
275
|
-
#
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
for trace_msg in trace_messages:
|
280
|
-
if not trace_msg.parent_span_id:
|
281
|
-
root_spans.append(trace_msg)
|
282
|
-
else:
|
283
|
-
if trace_msg.parent_span_id not in child_spans:
|
284
|
-
child_spans[trace_msg.parent_span_id] = []
|
285
|
-
child_spans[trace_msg.parent_span_id].append(trace_msg)
|
266
|
+
# Filter out spans without parents (artificial root spans)
|
267
|
+
spans_by_id = {
|
268
|
+
msg.span_id: msg for msg in trace_messages if msg.parent_span_id is not None
|
269
|
+
}
|
286
270
|
|
287
|
-
# Build
|
271
|
+
# Build parent-to-children mapping once upfront
|
272
|
+
children_by_parent: Dict[str, List[TraceMessage]] = {}
|
273
|
+
for msg in spans_by_id.values():
|
274
|
+
if msg.parent_span_id:
|
275
|
+
if msg.parent_span_id not in children_by_parent:
|
276
|
+
children_by_parent[msg.parent_span_id] = []
|
277
|
+
children_by_parent[msg.parent_span_id].append(msg)
|
278
|
+
|
279
|
+
# Find root spans (parent doesn't exist in our filtered data)
|
280
|
+
root_spans = [
|
281
|
+
msg
|
282
|
+
for msg in trace_messages
|
283
|
+
if msg.parent_span_id and msg.parent_span_id not in spans_by_id
|
284
|
+
]
|
285
|
+
|
286
|
+
# Build tree recursively for each root span
|
288
287
|
for root_span in sorted(root_spans, key=lambda x: x.timestamp):
|
289
|
-
|
290
|
-
for child in sorted(
|
291
|
-
child_spans[root_span.span_id], key=lambda x: x.timestamp
|
292
|
-
):
|
293
|
-
self._add_span_node(root, child, child_spans)
|
288
|
+
self._add_span_with_children(root, root_span, children_by_parent)
|
294
289
|
|
295
|
-
def
|
290
|
+
def _add_span_with_children(
|
296
291
|
self,
|
297
292
|
parent_node: TreeNode[str],
|
298
293
|
trace_msg: TraceMessage,
|
299
|
-
|
294
|
+
children_by_parent: Dict[str, List[TraceMessage]],
|
300
295
|
):
|
301
|
-
"""Recursively add span
|
302
|
-
# Create
|
296
|
+
"""Recursively add a span and all its children."""
|
297
|
+
# Create the node for this span
|
303
298
|
color_map = {
|
304
299
|
"started": "🔵",
|
305
300
|
"running": "🟡",
|
@@ -308,26 +303,20 @@ class RunDetailsPanel(Container):
|
|
308
303
|
"error": "🔴",
|
309
304
|
}
|
310
305
|
status_icon = color_map.get(trace_msg.status.lower(), "⚪")
|
311
|
-
|
312
306
|
duration_str = (
|
313
307
|
f" ({trace_msg.duration_ms:.1f}ms)" if trace_msg.duration_ms else ""
|
314
308
|
)
|
315
309
|
label = f"{status_icon} {trace_msg.span_name}{duration_str}"
|
316
310
|
|
317
|
-
# Add node to tree
|
318
311
|
node = parent_node.add(label)
|
319
|
-
node.data = trace_msg.span_id
|
312
|
+
node.data = trace_msg.span_id
|
320
313
|
self.span_tree_nodes[trace_msg.span_id] = node
|
321
|
-
|
322
314
|
node.expand()
|
323
315
|
|
324
|
-
#
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
)
|
329
|
-
for child_span in sorted_children:
|
330
|
-
self._add_span_node(node, child_span, child_spans)
|
316
|
+
# Get children from prebuilt mapping - O(1) lookup
|
317
|
+
children = children_by_parent.get(trace_msg.span_id, [])
|
318
|
+
for child in sorted(children, key=lambda x: x.timestamp):
|
319
|
+
self._add_span_with_children(node, child, children_by_parent)
|
331
320
|
|
332
321
|
def on_tree_node_selected(self, event: Tree.NodeSelected[str]) -> None:
|
333
322
|
"""Handle span selection in the tree."""
|
@@ -2,7 +2,14 @@ from typing import List, Optional
|
|
2
2
|
|
3
3
|
from textual.app import ComposeResult
|
4
4
|
from textual.containers import Container, Vertical
|
5
|
-
from textual.widgets import
|
5
|
+
from textual.widgets import (
|
6
|
+
Button,
|
7
|
+
ListItem,
|
8
|
+
ListView,
|
9
|
+
Static,
|
10
|
+
TabbedContent,
|
11
|
+
TabPane,
|
12
|
+
)
|
6
13
|
|
7
14
|
from .._models._execution import ExecutionRun
|
8
15
|
|
@@ -16,11 +23,16 @@ class RunHistoryPanel(Container):
|
|
16
23
|
self.selected_run: Optional[ExecutionRun] = None
|
17
24
|
|
18
25
|
def compose(self) -> ComposeResult:
|
19
|
-
with
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
26
|
+
with TabbedContent():
|
27
|
+
with TabPane("History", id="history-tab"):
|
28
|
+
with Vertical():
|
29
|
+
yield ListView(id="run-list", classes="run-list")
|
30
|
+
yield Button(
|
31
|
+
"+ New",
|
32
|
+
id="new-run-btn",
|
33
|
+
variant="primary",
|
34
|
+
classes="new-run-btn",
|
35
|
+
)
|
24
36
|
|
25
37
|
def add_run(self, run: ExecutionRun):
|
26
38
|
"""Add a new run to history."""
|
@@ -5,7 +5,7 @@ from typing import Any, Dict, Tuple, cast
|
|
5
5
|
from textual.app import ComposeResult
|
6
6
|
from textual.containers import Container, Horizontal, Vertical
|
7
7
|
from textual.reactive import reactive
|
8
|
-
from textual.widgets import Button, Select, TextArea
|
8
|
+
from textual.widgets import Button, Select, TabbedContent, TabPane, TextArea
|
9
9
|
|
10
10
|
|
11
11
|
def mock_json_from_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
|
@@ -63,32 +63,31 @@ class NewRunPanel(Container):
|
|
63
63
|
)
|
64
64
|
|
65
65
|
def compose(self) -> ComposeResult:
|
66
|
-
with
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
)
|
66
|
+
with TabbedContent():
|
67
|
+
with TabPane("New run", id="new-tab"):
|
68
|
+
with Vertical():
|
69
|
+
options = [(path, path) for path in self.entrypoint_paths]
|
70
|
+
yield Select(
|
71
|
+
options,
|
72
|
+
id="entrypoint-select",
|
73
|
+
value=self.selected_entrypoint,
|
74
|
+
allow_blank=False,
|
75
|
+
)
|
76
|
+
|
77
|
+
yield TextArea(
|
78
|
+
text=self.initial_input,
|
79
|
+
language="json",
|
80
|
+
id="json-input",
|
81
|
+
classes="input-field json-input",
|
82
|
+
)
|
83
|
+
|
84
|
+
with Horizontal(classes="run-actions"):
|
85
|
+
yield Button(
|
86
|
+
"▶ Run",
|
87
|
+
id="execute-btn",
|
88
|
+
variant="primary",
|
89
|
+
classes="action-btn",
|
90
|
+
)
|
92
91
|
|
93
92
|
async def on_select_changed(self, event: Select.Changed) -> None:
|
94
93
|
"""Update JSON input when user selects an entrypoint."""
|
@@ -0,0 +1,31 @@
|
|
1
|
+
from textual.app import ComposeResult
|
2
|
+
from textual.containers import Container, Horizontal, Vertical
|
3
|
+
from textual.widgets import Button, TextArea
|
4
|
+
|
5
|
+
|
6
|
+
class ResumePanel(Container):
|
7
|
+
"""Panel for resuming a suspended run."""
|
8
|
+
|
9
|
+
def __init__(self, **kwargs):
|
10
|
+
super().__init__(**kwargs)
|
11
|
+
|
12
|
+
def compose(self) -> ComposeResult:
|
13
|
+
with Vertical():
|
14
|
+
yield TextArea(
|
15
|
+
text="{}",
|
16
|
+
language="json",
|
17
|
+
id="resume-json-input",
|
18
|
+
classes="input-field json-input",
|
19
|
+
)
|
20
|
+
with Horizontal(classes="run-actions"):
|
21
|
+
yield Button(
|
22
|
+
"▶ Resume",
|
23
|
+
id="resume-btn",
|
24
|
+
variant="primary",
|
25
|
+
classes="action-btn",
|
26
|
+
)
|
27
|
+
|
28
|
+
def get_input_values(self) -> str:
|
29
|
+
"""Return the JSON text to resume with."""
|
30
|
+
json_input = self.query_one("#resume-json-input", TextArea)
|
31
|
+
return json_input.text.strip()
|
@@ -1,24 +1,28 @@
|
|
1
1
|
import os
|
2
2
|
from datetime import datetime
|
3
|
-
from typing import List, Optional
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from uuid import uuid4
|
5
5
|
|
6
|
+
from rich.text import Text
|
7
|
+
|
8
|
+
from ...._runtime._contracts import UiPathErrorContract
|
6
9
|
from ._messages import LogMessage, TraceMessage
|
7
10
|
|
8
11
|
|
9
12
|
class ExecutionRun:
|
10
13
|
"""Represents a single execution run."""
|
11
14
|
|
12
|
-
def __init__(self, entrypoint: str, input_data: str):
|
15
|
+
def __init__(self, entrypoint: str, input_data: Dict[str, Any]):
|
13
16
|
self.id = str(uuid4())[:8]
|
14
17
|
self.entrypoint = entrypoint
|
15
18
|
self.input_data = input_data
|
16
|
-
self.output_data: Optional[str] = None
|
19
|
+
self.output_data: Optional[Dict[str, Any]] = None
|
17
20
|
self.start_time = datetime.now()
|
18
21
|
self.end_time: Optional[datetime] = None
|
19
22
|
self.status = "running" # running, completed, failed
|
20
23
|
self.traces: List[TraceMessage] = []
|
21
24
|
self.logs: List[LogMessage] = []
|
25
|
+
self.error: Optional[UiPathErrorContract] = None
|
22
26
|
|
23
27
|
@property
|
24
28
|
def duration(self) -> str:
|
@@ -30,14 +34,32 @@ class ExecutionRun:
|
|
30
34
|
return f"{delta.total_seconds():.1f}s"
|
31
35
|
|
32
36
|
@property
|
33
|
-
def display_name(self) ->
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
+
def display_name(self) -> Text:
|
38
|
+
status_colors = {
|
39
|
+
"running": "yellow",
|
40
|
+
"suspended": "cyan",
|
41
|
+
"completed": "green",
|
42
|
+
"failed": "red",
|
43
|
+
}
|
44
|
+
|
45
|
+
status_icon = {
|
46
|
+
"running": "▶",
|
47
|
+
"suspended": "⏸",
|
48
|
+
"completed": "✔",
|
49
|
+
"failed": "✖",
|
50
|
+
}.get(self.status, "?")
|
37
51
|
|
38
52
|
script_name = (
|
39
53
|
os.path.basename(self.entrypoint) if self.entrypoint else "untitled"
|
40
54
|
)
|
55
|
+
truncated_script = script_name[:10]
|
41
56
|
time_str = self.start_time.strftime("%H:%M:%S")
|
57
|
+
duration_str = self.duration[:6]
|
58
|
+
|
59
|
+
text = Text()
|
60
|
+
text.append(f"{status_icon:<2} ", style=status_colors.get(self.status, "white"))
|
61
|
+
text.append(f"{truncated_script:<10} ")
|
62
|
+
text.append(f"({time_str:<8}) ")
|
63
|
+
text.append(f"[{duration_str:<6}]")
|
42
64
|
|
43
|
-
return
|
65
|
+
return text
|
@@ -1,11 +1,7 @@
|
|
1
|
-
/* Global layout - dark terminal theme */
|
2
1
|
Screen {
|
3
|
-
background: #1a1a1a;
|
4
|
-
color: #e0e0e0;
|
5
2
|
layout: horizontal;
|
6
3
|
}
|
7
4
|
|
8
|
-
/* Left sidebar - run history with embedded title */
|
9
5
|
.run-history {
|
10
6
|
width: 30%;
|
11
7
|
min-width: 25;
|
@@ -15,18 +11,10 @@ Screen {
|
|
15
11
|
.run-list {
|
16
12
|
height: 1fr;
|
17
13
|
margin-bottom: 1;
|
18
|
-
border: solid #404040;
|
19
|
-
background: #252525;
|
20
14
|
}
|
21
15
|
|
22
16
|
.run-item {
|
23
17
|
padding: 0 1;
|
24
|
-
background: transparent;
|
25
|
-
color: #e0e0e0;
|
26
|
-
}
|
27
|
-
|
28
|
-
.run-item:hover {
|
29
|
-
background: #333333;
|
30
18
|
}
|
31
19
|
|
32
20
|
.run-running {
|
@@ -47,43 +35,27 @@ Screen {
|
|
47
35
|
.new-run-btn {
|
48
36
|
width: 100%;
|
49
37
|
margin-bottom: 1;
|
50
|
-
background: #00d4ff;
|
51
|
-
color: #000000;
|
52
38
|
border: none;
|
53
39
|
text-style: bold;
|
54
40
|
}
|
55
|
-
|
56
|
-
.new-run-btn:hover {
|
57
|
-
background: #00a0cc;
|
58
|
-
}
|
59
|
-
|
60
|
-
/* Main content area */
|
61
41
|
.main-content {
|
62
42
|
width: 70%;
|
63
43
|
padding-left: 1;
|
64
44
|
}
|
65
45
|
|
66
|
-
/* New run panel with embedded titles */
|
67
46
|
.new-run-title {
|
68
|
-
color: #00d4ff;
|
69
47
|
text-style: bold;
|
70
|
-
background: #252525;
|
71
48
|
padding: 0 1;
|
72
49
|
height: 1;
|
73
|
-
border: solid #404040;
|
74
50
|
margin-bottom: 0;
|
75
51
|
}
|
76
52
|
|
77
53
|
.new-run-panel {
|
78
54
|
height: 100%;
|
79
|
-
background: #252525;
|
80
|
-
border: solid #404040;
|
81
55
|
}
|
82
56
|
|
83
57
|
.field-label {
|
84
|
-
color: #00d4ff;
|
85
58
|
text-style: bold;
|
86
|
-
background: #252525;
|
87
59
|
}
|
88
60
|
|
89
61
|
.run-actions {
|
@@ -94,26 +66,10 @@ Screen {
|
|
94
66
|
.action-btn {
|
95
67
|
margin-right: 2;
|
96
68
|
min-width: 8;
|
97
|
-
background: #00ff88;
|
98
|
-
color: #000000;
|
99
69
|
border: none;
|
100
70
|
text-style: bold;
|
101
71
|
}
|
102
72
|
|
103
|
-
.action-btn:hover {
|
104
|
-
background: #00cc66;
|
105
|
-
}
|
106
|
-
|
107
|
-
.cancel-btn {
|
108
|
-
background: #404040;
|
109
|
-
color: #e0e0e0;
|
110
|
-
}
|
111
|
-
|
112
|
-
.cancel-btn:hover {
|
113
|
-
background: #555555;
|
114
|
-
}
|
115
|
-
|
116
|
-
/* Run details panel with embedded titles */
|
117
73
|
.details-content {
|
118
74
|
height: 1fr;
|
119
75
|
}
|
@@ -134,12 +90,10 @@ Screen {
|
|
134
90
|
|
135
91
|
.detail-log {
|
136
92
|
height: 1fr;
|
137
|
-
background: #252525;
|
138
93
|
padding: 1;
|
139
94
|
padding-top: 0;
|
140
95
|
}
|
141
96
|
|
142
|
-
/* Status indicators for buttons */
|
143
97
|
.status-running {
|
144
98
|
background: #ffaa00;
|
145
99
|
color: #000000;
|
@@ -158,53 +112,16 @@ Screen {
|
|
158
112
|
border: solid #ff4444;
|
159
113
|
}
|
160
114
|
|
161
|
-
/* ListView styling */
|
162
|
-
ListView {
|
163
|
-
background: transparent;
|
164
|
-
}
|
165
|
-
|
166
|
-
ListView>ListItem {
|
167
|
-
background: transparent;
|
168
|
-
}
|
169
|
-
|
170
|
-
ListView>ListItem:hover {
|
171
|
-
background: #333333;
|
172
|
-
}
|
173
|
-
|
174
|
-
ListView>ListItem.--highlight {
|
175
|
-
background: #00d4ff;
|
176
|
-
color: #000000;
|
177
|
-
}
|
178
|
-
|
179
|
-
/* TextArea and RichLog improvements */
|
180
|
-
TextArea {
|
181
|
-
background: #1a1a1a;
|
182
|
-
color: #e0e0e0;
|
183
|
-
}
|
184
|
-
|
185
|
-
RichLog {
|
186
|
-
background: #252525;
|
187
|
-
color: #e0e0e0;
|
188
|
-
}
|
189
|
-
|
190
|
-
/* Initially hide details panel */
|
191
115
|
.hidden {
|
192
116
|
display: none;
|
193
117
|
}
|
194
118
|
|
195
|
-
/* Header and Footer */
|
196
|
-
Header {
|
197
|
-
background: #000000;
|
198
|
-
color: #00d4ff;
|
199
|
-
}
|
200
|
-
|
201
119
|
Footer {
|
202
|
-
|
203
|
-
|
204
|
-
|
120
|
+
margin-top:1;
|
121
|
+
height: auto;
|
122
|
+
dock: bottom;
|
205
123
|
}
|
206
124
|
|
207
|
-
/* Tabbed content styling */
|
208
125
|
TabbedContent {
|
209
126
|
height: 100%;
|
210
127
|
}
|
@@ -214,7 +131,6 @@ TabPane {
|
|
214
131
|
padding: 0;
|
215
132
|
}
|
216
133
|
|
217
|
-
/* Traces tab layout */
|
218
134
|
.traces-content {
|
219
135
|
height: 100%;
|
220
136
|
}
|
@@ -231,60 +147,24 @@ TabPane {
|
|
231
147
|
padding-left: 1;
|
232
148
|
}
|
233
149
|
|
234
|
-
/* Tree styling */
|
235
150
|
.spans-tree {
|
236
151
|
height: 100%;
|
237
|
-
background: #252525;
|
238
152
|
padding: 1;
|
239
153
|
padding-top: 0;
|
240
154
|
}
|
241
155
|
|
242
|
-
Tree {
|
243
|
-
background: #252525;
|
244
|
-
color: #e0e0e0;
|
245
|
-
}
|
246
|
-
|
247
|
-
Tree>TreeNode {
|
248
|
-
background: transparent;
|
249
|
-
}
|
250
|
-
|
251
|
-
Tree>TreeNode:hover {
|
252
|
-
background: #333333;
|
253
|
-
}
|
254
|
-
|
255
|
-
Tree>TreeNode.--highlight {
|
256
|
-
background: #00d4ff;
|
257
|
-
color: #000000;
|
258
|
-
}
|
259
|
-
|
260
|
-
/* Tab styling */
|
261
|
-
Tabs {
|
262
|
-
background: #252525;
|
263
|
-
color: #e0e0e0;
|
264
|
-
}
|
265
|
-
|
266
|
-
Tab {
|
267
|
-
background: transparent;
|
268
|
-
color: #888888;
|
269
|
-
border: none;
|
270
|
-
}
|
271
|
-
|
272
156
|
Label {
|
273
157
|
margin: 1 1;
|
274
158
|
width: 100%;
|
275
159
|
height: 100%;
|
276
|
-
background: $panel;
|
277
160
|
border: tall $primary;
|
278
161
|
content-align: center middle;
|
279
162
|
}
|
280
163
|
|
281
|
-
/* Content areas */
|
282
164
|
ContentSwitcher {
|
283
165
|
height: 1fr;
|
284
|
-
background: transparent;
|
285
166
|
}
|
286
167
|
|
287
|
-
/* Span details styling */
|
288
168
|
SpanDetailsDisplay {
|
289
169
|
height: 100%;
|
290
170
|
}
|
@@ -297,35 +177,22 @@ SpanDetailsDisplay {
|
|
297
177
|
height: 100%;
|
298
178
|
}
|
299
179
|
|
300
|
-
/* Panels */
|
301
180
|
.new-run-panel {
|
302
181
|
height: 100%;
|
303
|
-
background: #252525;
|
304
|
-
padding: 1;
|
305
182
|
}
|
306
183
|
|
307
|
-
/* Section Titles */
|
308
184
|
.new-run-title {
|
309
|
-
color: #00d4ff;
|
310
185
|
text-style: bold;
|
311
|
-
background: #1f1f1f;
|
312
186
|
padding: 0 1;
|
313
187
|
height: 2;
|
314
188
|
content-align: left middle;
|
315
189
|
}
|
316
190
|
|
317
|
-
/* Labels */
|
318
191
|
.field-label {
|
319
|
-
color: #00d4ff;
|
320
192
|
text-style: bold;
|
321
193
|
margin: 1 0;
|
322
194
|
}
|
323
195
|
|
324
|
-
.input-field {
|
325
|
-
background: #1a1a1a;
|
326
|
-
color: #e0e0e0;
|
327
|
-
}
|
328
|
-
|
329
196
|
.script-input {
|
330
197
|
height: 3;
|
331
198
|
}
|
@@ -346,16 +213,3 @@ SpanDetailsDisplay {
|
|
346
213
|
text-style: bold;
|
347
214
|
border: none;
|
348
215
|
}
|
349
|
-
|
350
|
-
.action-btn:hover {
|
351
|
-
background: #00cc66;
|
352
|
-
}
|
353
|
-
|
354
|
-
.cancel-btn {
|
355
|
-
background: #404040;
|
356
|
-
color: #e0e0e0;
|
357
|
-
}
|
358
|
-
|
359
|
-
.cancel-btn:hover {
|
360
|
-
background: #555555;
|
361
|
-
}
|
uipath/_cli/_runtime/_runtime.py
CHANGED
@@ -86,7 +86,7 @@ class UiPathRuntime(UiPathBaseRuntime):
|
|
86
86
|
try:
|
87
87
|
if self.context.input:
|
88
88
|
self.context.input_json = json.loads(self.context.input)
|
89
|
-
|
89
|
+
if self.context.input_json is None:
|
90
90
|
self.context.input_json = {}
|
91
91
|
except json.JSONDecodeError as e:
|
92
92
|
raise UiPathRuntimeError(
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: uipath
|
3
|
-
Version: 2.1.
|
3
|
+
Version: 2.1.32
|
4
4
|
Summary: Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools.
|
5
5
|
Project-URL: Homepage, https://uipath.com
|
6
6
|
Project-URL: Repository, https://github.com/UiPath/uipath-python
|
@@ -31,13 +31,14 @@ uipath/_cli/_auth/auth_config.json,sha256=UnAhdum8phjuZaZKE5KLp0IcPCbIltDEU1M_G8
|
|
31
31
|
uipath/_cli/_auth/index.html,sha256=uGK0CDTP8Rys_p4O_Pbd2x4tz0frKNVcumjrXnal5Nc,22814
|
32
32
|
uipath/_cli/_auth/localhost.crt,sha256=oGl9oLLOiouHubAt39B4zEfylFvKEtbtr_43SIliXJc,1226
|
33
33
|
uipath/_cli/_auth/localhost.key,sha256=X31VYXD8scZtmGA837dGX5l6G-LXHLo5ItWJhZXaz3c,1679
|
34
|
-
uipath/_cli/_dev/_terminal/__init__.py,sha256=
|
35
|
-
uipath/_cli/_dev/_terminal/_components/_details.py,sha256=
|
36
|
-
uipath/_cli/_dev/_terminal/_components/_history.py,sha256
|
37
|
-
uipath/_cli/_dev/_terminal/_components/_new.py,sha256=
|
38
|
-
uipath/_cli/_dev/_terminal/
|
34
|
+
uipath/_cli/_dev/_terminal/__init__.py,sha256=Fyqb5cQeP7B-zt5PEccusXxcOAlgCOsh792AUTBrdxc,10025
|
35
|
+
uipath/_cli/_dev/_terminal/_components/_details.py,sha256=DK1e6ZxuKws54G-4XfgGWNcEWZSTW5iQ2djHfvd365E,15055
|
36
|
+
uipath/_cli/_dev/_terminal/_components/_history.py,sha256=-0lystNcVUCUbHgEUVQ-CdxAfV3_X5uhjxWevxs19Z0,2054
|
37
|
+
uipath/_cli/_dev/_terminal/_components/_new.py,sha256=Lpt703Y_FTZ9tCrudcnDK7Dfta_7h6AEWqHJ9lR62sU,4577
|
38
|
+
uipath/_cli/_dev/_terminal/_components/_resume.py,sha256=_9nhlZOT7eaarzydugn8Z4ESHXuP-92U6XZyMSmXUwE,1002
|
39
|
+
uipath/_cli/_dev/_terminal/_models/_execution.py,sha256=4rMq-WWvhqLZfFB66_aCuGSkSYR4B1kUyegzWb2vm48,2052
|
39
40
|
uipath/_cli/_dev/_terminal/_models/_messages.py,sha256=TR7D1yLL0PNYGUMts_cGLgF8zj67urNwuX-5xSGqWgM,1762
|
40
|
-
uipath/_cli/_dev/_terminal/_styles/terminal.tcss,sha256=
|
41
|
+
uipath/_cli/_dev/_terminal/_styles/terminal.tcss,sha256=C4XMJJtEzKSqanh9GU-fgGye3uexYvnjNG4jdKnRslI,2591
|
41
42
|
uipath/_cli/_dev/_terminal/_traces/_exporter.py,sha256=oI6D_eMwrh_2aqDYUh4GrJg8VLGrLYhDahR-_o0uJns,4144
|
42
43
|
uipath/_cli/_dev/_terminal/_traces/_logger.py,sha256=Dmfba3X9GmAZtXpzu_KDsleRCrpVo8_y-W6jizwFYq0,880
|
43
44
|
uipath/_cli/_evals/evaluation_service.py,sha256=zqYRB-tZpTTFqMctjIpEli3joIlmrz3dCVZsxekxIps,22053
|
@@ -58,7 +59,7 @@ uipath/_cli/_runtime/_contracts.py,sha256=ays9ki4PQjdiy_z_kuR_Z0mHYVy_MZ6DvBG6g_
|
|
58
59
|
uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
|
59
60
|
uipath/_cli/_runtime/_hitl.py,sha256=aexwe0dIXvh6SlVS1jVnO_aGZc6e3gLsmGkCyha5AHo,11300
|
60
61
|
uipath/_cli/_runtime/_logging.py,sha256=MGklGKPjYKjs7J5Jy9eplA9zCDsdtEbkZdCbTwgut_4,8311
|
61
|
-
uipath/_cli/_runtime/_runtime.py,sha256=
|
62
|
+
uipath/_cli/_runtime/_runtime.py,sha256=TXtXzscRPLdYJURH0Y-7sXsigC-2k_LttBOz7EUfWUQ,11449
|
62
63
|
uipath/_cli/_templates/.psmdcp.template,sha256=C7pBJPt98ovEljcBvGtEUGoWjjQhu9jls1bpYjeLOKA,611
|
63
64
|
uipath/_cli/_templates/.rels.template,sha256=-fTcw7OA1AcymHr0LzBqbMAAtzZTRXLTNa_ljq087Jk,406
|
64
65
|
uipath/_cli/_templates/[Content_Types].xml.template,sha256=bYsKDz31PkIF9QksjgAY_bqm57YC8U_owsZeNZAiBxQ,584
|
@@ -126,8 +127,8 @@ uipath/tracing/_traced.py,sha256=qeVDrds2OUnpdUIA0RhtF0kg2dlAZhyC1RRkI-qivTM,185
|
|
126
127
|
uipath/tracing/_utils.py,sha256=wJRELaPu69iY0AhV432Dk5QYf_N_ViRU4kAUG1BI1ew,10384
|
127
128
|
uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
|
128
129
|
uipath/utils/_endpoints_manager.py,sha256=iRTl5Q0XAm_YgcnMcJOXtj-8052sr6jpWuPNz6CgT0Q,8408
|
129
|
-
uipath-2.1.
|
130
|
-
uipath-2.1.
|
131
|
-
uipath-2.1.
|
132
|
-
uipath-2.1.
|
133
|
-
uipath-2.1.
|
130
|
+
uipath-2.1.32.dist-info/METADATA,sha256=ouBZDro2TME5ykTsNMJoN3_qiI1wDHt_Ys7nCZF8z8A,6450
|
131
|
+
uipath-2.1.32.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
132
|
+
uipath-2.1.32.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
|
133
|
+
uipath-2.1.32.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
|
134
|
+
uipath-2.1.32.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|