uipath 2.1.31__py3-none-any.whl → 2.1.33__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.
@@ -10,17 +10,19 @@ from uuid import uuid4
10
10
  from textual.app import App, ComposeResult
11
11
  from textual.binding import Binding
12
12
  from textual.containers import Container, Horizontal
13
- from textual.widgets import Button, ListView
13
+ from textual.widgets import Button, Footer, ListView
14
14
 
15
15
  from ..._runtime._contracts import (
16
16
  UiPathErrorContract,
17
17
  UiPathRuntimeContext,
18
18
  UiPathRuntimeError,
19
19
  UiPathRuntimeFactory,
20
+ UiPathRuntimeStatus,
20
21
  )
21
22
  from ._components._details import RunDetailsPanel
22
23
  from ._components._history import RunHistoryPanel
23
24
  from ._components._new import NewRunPanel
25
+ from ._components._resume import ResumePanel
24
26
  from ._models._execution import ExecutionRun
25
27
  from ._models._messages import LogMessage, TraceMessage
26
28
  from ._traces._exporter import RunContextExporter
@@ -34,8 +36,8 @@ class UiPathDevTerminal(App[Any]):
34
36
 
35
37
  BINDINGS = [
36
38
  Binding("q", "quit", "Quit"),
37
- Binding("n", "new_run", "New Run"),
38
- Binding("r", "execute_run", "Execute"),
39
+ Binding("n", "new_run", "New"),
40
+ Binding("r", "execute_run", "Run"),
39
41
  Binding("c", "clear_history", "Clear History"),
40
42
  Binding("escape", "cancel", "Cancel"),
41
43
  ]
@@ -76,6 +78,8 @@ class UiPathDevTerminal(App[Any]):
76
78
  # Run details panel (initially hidden)
77
79
  yield RunDetailsPanel(id="details-panel", classes="hidden")
78
80
 
81
+ yield Footer()
82
+
79
83
  async def on_button_pressed(self, event: Button.Pressed) -> None:
80
84
  """Handle button press events."""
81
85
  if event.button.id == "new-run-btn":
@@ -84,6 +88,8 @@ class UiPathDevTerminal(App[Any]):
84
88
  await self.action_execute_run()
85
89
  elif event.button.id == "cancel-btn":
86
90
  await self.action_cancel()
91
+ elif event.button.id == "resume-btn":
92
+ await self.action_resume()
87
93
 
88
94
  async def on_list_view_selected(self, event: ListView.Selected) -> None:
89
95
  """Handle run selection from history."""
@@ -107,6 +113,20 @@ class UiPathDevTerminal(App[Any]):
107
113
  """Cancel and return to new run view."""
108
114
  await self.action_new_run()
109
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.resume_data = input
127
+ asyncio.create_task(self._execute_runtime(details_panel.current_run))
128
+ details_panel.switch_tab("run-tab")
129
+
110
130
  async def action_execute_run(self) -> None:
111
131
  """Execute a new run with UiPath runtime."""
112
132
  new_run_panel = self.query_one("#new-run-panel", NewRunPanel)
@@ -115,12 +135,14 @@ class UiPathDevTerminal(App[Any]):
115
135
  if not entrypoint:
116
136
  return
117
137
 
138
+ input: Dict[str, Any] = {}
118
139
  try:
119
- json.loads(input_data)
140
+ input = json.loads(input_data)
120
141
  except json.JSONDecodeError:
121
142
  return
122
143
 
123
- run = ExecutionRun(entrypoint, input_data)
144
+ run = ExecutionRun(entrypoint, input)
145
+
124
146
  self.runs[run.id] = run
125
147
 
126
148
  self._add_run_in_history(run)
@@ -140,7 +162,6 @@ class UiPathDevTerminal(App[Any]):
140
162
  try:
141
163
  context: UiPathRuntimeContext = self.runtime_factory.new_context(
142
164
  entrypoint=run.entrypoint,
143
- input=run.input_data,
144
165
  trace_id=str(uuid4()),
145
166
  execution_id=run.id,
146
167
  logs_min_level=env.get("LOG_LEVEL", "INFO"),
@@ -149,17 +170,29 @@ class UiPathDevTerminal(App[Any]):
149
170
  ),
150
171
  )
151
172
 
152
- self._add_info_log(run, f"Starting execution: {run.entrypoint}")
173
+ if run.status == "suspended":
174
+ context.resume = True
175
+ context.input_json = run.resume_data
176
+ self._add_info_log(run, f"Resuming execution: {run.entrypoint}")
177
+ else:
178
+ context.input_json = run.input_data
179
+ self._add_info_log(run, f"Starting execution: {run.entrypoint}")
180
+
181
+ run.status = "running"
182
+ run.start_time = datetime.now()
153
183
 
154
184
  result = await self.runtime_factory.execute_in_root_span(context)
155
185
 
156
186
  if result is not None:
157
- run.output_data = json.dumps(result.output)
187
+ if result.status == UiPathRuntimeStatus.SUSPENDED.value:
188
+ run.status = "suspended"
189
+ else:
190
+ run.output_data = result.output
191
+ run.status = "completed"
158
192
  if run.output_data:
159
193
  self._add_info_log(run, f"Execution result: {run.output_data}")
160
194
 
161
195
  self._add_info_log(run, "✅ Execution completed successfully")
162
- run.status = "completed"
163
196
  run.end_time = datetime.now()
164
197
 
165
198
  except UiPathRuntimeError as e:
@@ -8,6 +8,7 @@ from textual.widgets.tree import TreeNode
8
8
 
9
9
  from .._models._execution import ExecutionRun
10
10
  from .._models._messages import LogMessage, TraceMessage
11
+ from ._resume import ResumePanel
11
12
 
12
13
 
13
14
  class SpanDetailsDisplay(Container):
@@ -27,14 +28,7 @@ class SpanDetailsDisplay(Container):
27
28
  details_log = self.query_one("#span-details", RichLog)
28
29
  details_log.clear()
29
30
 
30
- # Format span details
31
31
  details_log.write(f"[bold cyan]Span: {trace_msg.span_name}[/bold cyan]")
32
- details_log.write(f"[dim]Trace ID: {trace_msg.trace_id}[/dim]")
33
- details_log.write(f"[dim]Span ID: {trace_msg.span_id}[/dim]")
34
- details_log.write(f"[dim]Run ID: {trace_msg.run_id}[/dim]")
35
-
36
- if trace_msg.parent_span_id:
37
- details_log.write(f"[dim]Parent Span: {trace_msg.parent_span_id}[/dim]")
38
32
 
39
33
  details_log.write("") # Empty line
40
34
 
@@ -66,6 +60,16 @@ class SpanDetailsDisplay(Container):
66
60
  for key, value in trace_msg.attributes.items():
67
61
  details_log.write(f" {key}: {value}")
68
62
 
63
+ details_log.write("") # Empty line
64
+
65
+ # Format span details
66
+ details_log.write(f"[dim]Trace ID: {trace_msg.trace_id}[/dim]")
67
+ details_log.write(f"[dim]Span ID: {trace_msg.span_id}[/dim]")
68
+ details_log.write(f"[dim]Run ID: {trace_msg.run_id}[/dim]")
69
+
70
+ if trace_msg.parent_span_id:
71
+ details_log.write(f"[dim]Parent Span: {trace_msg.parent_span_id}[/dim]")
72
+
69
73
 
70
74
  class RunDetailsPanel(Container):
71
75
  """Panel showing traces and logs for selected run with tabbed interface."""
@@ -112,6 +116,9 @@ class RunDetailsPanel(Container):
112
116
  classes="detail-log",
113
117
  )
114
118
 
119
+ with TabPane("Resume", id="resume-tab"):
120
+ yield ResumePanel(id="resume-panel")
121
+
115
122
  def watch_current_run(
116
123
  self, old_value: Optional[ExecutionRun], new_value: Optional[ExecutionRun]
117
124
  ):
@@ -139,8 +146,69 @@ class RunDetailsPanel(Container):
139
146
  # Clear and rebuild traces tree using TraceMessage objects
140
147
  self._rebuild_spans_tree()
141
148
 
149
+ def switch_tab(self, tab_id: str) -> None:
150
+ """Switch to a specific tab by id (e.g. 'run-tab', 'traces-tab')."""
151
+ tabbed = self.query_one(TabbedContent)
152
+ tabbed.active = tab_id
153
+
154
+ def _update_resume_tab(self, run: ExecutionRun) -> None:
155
+ resume_panel = self.query_one("#resume-panel", ResumePanel)
156
+ resume_panel.display = run.status == "suspended"
157
+
158
+ def _flatten_values(self, value: object, prefix: str = "") -> list[str]:
159
+ """Flatten nested dict/list structures into dot-notation paths."""
160
+ lines: list[str] = []
161
+
162
+ if value is None:
163
+ lines.append(f"{prefix}: [dim]—[/dim]" if prefix else "[dim]—[/dim]")
164
+
165
+ elif isinstance(value, dict):
166
+ if not value:
167
+ lines.append(f"{prefix}: {{}}" if prefix else "{}")
168
+ else:
169
+ for k, v in value.items():
170
+ new_prefix = f"{prefix}.{k}" if prefix else k
171
+ lines.extend(self._flatten_values(v, new_prefix))
172
+
173
+ elif isinstance(value, list):
174
+ if not value:
175
+ lines.append(f"{prefix}: []" if prefix else "[]")
176
+ else:
177
+ for i, item in enumerate(value):
178
+ new_prefix = f"{prefix}[{i}]"
179
+ lines.extend(self._flatten_values(item, new_prefix))
180
+
181
+ elif isinstance(value, str):
182
+ if prefix:
183
+ for line in value.splitlines():
184
+ lines.append(f"{prefix}: {line}")
185
+ else:
186
+ lines.extend(value.splitlines())
187
+
188
+ else:
189
+ if prefix:
190
+ lines.append(f"{prefix}: {value}")
191
+ else:
192
+ lines.append(str(value))
193
+
194
+ return lines
195
+
196
+ def _write_block(
197
+ self, log: RichLog, title: str, data: object, style: str = "white"
198
+ ) -> None:
199
+ """Pretty-print a block with flattened dot-notation paths."""
200
+ log.write(f"[bold {style}]{title.upper()}:[/bold {style}]")
201
+ log.write("[dim]" + "=" * 50 + "[/dim]")
202
+
203
+ for line in self._flatten_values(data):
204
+ log.write(line)
205
+
206
+ log.write("")
207
+
142
208
  def _show_run_details(self, run: ExecutionRun):
143
209
  """Display detailed information about the run in the Details tab."""
210
+ self._update_resume_tab(run)
211
+
144
212
  run_details_log = self.query_one("#run-details-log", RichLog)
145
213
  run_details_log.clear()
146
214
 
@@ -191,39 +259,16 @@ class RunDetailsPanel(Container):
191
259
 
192
260
  run_details_log.write("")
193
261
 
194
- # Input section
195
- if hasattr(run, "input_data") and run.input_data is not None:
196
- run_details_log.write("[bold green]INPUT:[/bold green]")
197
- run_details_log.write("[dim]" + "=" * 50 + "[/dim]")
198
-
199
- # Handle different input types
200
- if isinstance(run.input_data, str):
201
- run_details_log.write(run.input_data)
202
- elif isinstance(run.input_data, dict):
203
- import json
262
+ if hasattr(run, "input_data"):
263
+ self._write_block(run_details_log, "Input", run.input_data, style="green")
204
264
 
205
- run_details_log.write(json.dumps(run.input_data, indent=2))
206
- else:
207
- run_details_log.write(str(run.input_data))
265
+ if hasattr(run, "resume_data") and run.resume_data:
266
+ self._write_block(run_details_log, "Resume", run.resume_data, style="green")
208
267
 
209
- run_details_log.write("")
210
-
211
- # Output section
212
- if hasattr(run, "output_data") and run.output_data is not None:
213
- run_details_log.write("[bold magenta]OUTPUT:[/bold magenta]")
214
- run_details_log.write("[dim]" + "=" * 50 + "[/dim]")
215
-
216
- # Handle different output types
217
- if isinstance(run.output_data, str):
218
- run_details_log.write(run.output_data)
219
- elif isinstance(run.output_data, dict):
220
- import json
221
-
222
- run_details_log.write(json.dumps(run.output_data, indent=2))
223
- else:
224
- run_details_log.write(str(run.output_data))
225
-
226
- run_details_log.write("")
268
+ if hasattr(run, "output_data"):
269
+ self._write_block(
270
+ run_details_log, "Output", run.output_data, style="magenta"
271
+ )
227
272
 
228
273
  # Error section (if applicable)
229
274
  if hasattr(run, "error") and run.error:
@@ -235,25 +280,6 @@ class RunDetailsPanel(Container):
235
280
  run_details_log.write(f"[red]\n{run.error.detail}[/red]")
236
281
  run_details_log.write("")
237
282
 
238
- # Additional metadata
239
- run_details_log.write("[bold]METADATA:[/bold]")
240
- run_details_log.write("[dim]" + "=" * 50 + "[/dim]")
241
-
242
- # Show available attributes
243
- for attr in ["id", "status", "start_time", "end_time", "duration_ms"]:
244
- if hasattr(run, attr):
245
- value = getattr(run, attr)
246
- if value is not None:
247
- run_details_log.write(f" {attr}: {value}")
248
-
249
- # Show traces count
250
- traces_count = len(run.traces) if run.traces else 0
251
- run_details_log.write(f" traces_count: {traces_count}")
252
-
253
- # Show logs count
254
- logs_count = len(run.logs) if run.logs else 0
255
- run_details_log.write(f" logs_count: {logs_count}")
256
-
257
283
  def _rebuild_spans_tree(self):
258
284
  """Rebuild the spans tree from current run's traces."""
259
285
  spans_tree = self.query_one("#spans-tree", 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 Button, ListItem, ListView, Static
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 Vertical():
20
- yield ListView(id="run-list", classes="run-list")
21
- yield Button(
22
- "+ New Run", id="new-run-btn", variant="primary", classes="new-run-btn"
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."""
@@ -0,0 +1,23 @@
1
+ import json
2
+
3
+ from textual.widgets import TextArea
4
+
5
+
6
+ class JsonInput(TextArea):
7
+ """TextArea that validates JSON on change."""
8
+
9
+ def validate_json(self) -> bool:
10
+ text = self.text.strip()
11
+ if not text:
12
+ self.remove_class("invalid")
13
+ return True
14
+ try:
15
+ json.loads(text)
16
+ self.remove_class("invalid")
17
+ return True
18
+ except json.JSONDecodeError:
19
+ self.add_class("invalid")
20
+ return False
21
+
22
+ def on_text_area_changed(self, event: TextArea.Changed) -> None:
23
+ self.validate_json()
@@ -5,7 +5,9 @@ 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
+
10
+ from ._json_input import JsonInput
9
11
 
10
12
 
11
13
  def mock_json_from_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
@@ -63,32 +65,31 @@ class NewRunPanel(Container):
63
65
  )
64
66
 
65
67
  def compose(self) -> ComposeResult:
66
- with Vertical():
67
- options = [(path, path) for path in self.entrypoint_paths]
68
- yield Select(
69
- options,
70
- id="entrypoint-select",
71
- value=self.selected_entrypoint,
72
- allow_blank=False,
73
- )
74
-
75
- yield TextArea(
76
- text=self.initial_input,
77
- language="json",
78
- id="json-input",
79
- classes="input-field json-input",
80
- )
81
-
82
- with Horizontal(classes="run-actions"):
83
- yield Button(
84
- "▶ Run", id="execute-btn", variant="primary", classes="action-btn"
85
- )
86
- yield Button(
87
- "Cancel",
88
- id="cancel-btn",
89
- variant="default",
90
- classes="action-btn cancel-btn",
91
- )
68
+ with TabbedContent():
69
+ with TabPane("New run", id="new-tab"):
70
+ with Vertical():
71
+ options = [(path, path) for path in self.entrypoint_paths]
72
+ yield Select(
73
+ options,
74
+ id="entrypoint-select",
75
+ value=self.selected_entrypoint,
76
+ allow_blank=False,
77
+ )
78
+
79
+ yield JsonInput(
80
+ text=self.initial_input,
81
+ language="json",
82
+ id="json-input",
83
+ classes="input-field json-input",
84
+ )
85
+
86
+ with Horizontal(classes="run-actions"):
87
+ yield Button(
88
+ "▶ Run",
89
+ id="execute-btn",
90
+ variant="primary",
91
+ classes="action-btn",
92
+ )
92
93
 
93
94
  async def on_select_changed(self, event: Select.Changed) -> None:
94
95
  """Update JSON input when user selects an entrypoint."""
@@ -0,0 +1,35 @@
1
+ import json
2
+
3
+ from textual.app import ComposeResult
4
+ from textual.containers import Container, Horizontal, Vertical
5
+ from textual.widgets import Button, TextArea
6
+
7
+ from ._json_input import JsonInput
8
+
9
+
10
+ class ResumePanel(Container):
11
+ """Panel for resuming a suspended run."""
12
+
13
+ def __init__(self, **kwargs):
14
+ super().__init__(**kwargs)
15
+
16
+ def compose(self) -> ComposeResult:
17
+ with Vertical():
18
+ yield JsonInput(
19
+ text=json.dumps({"value": ""}, indent=2),
20
+ language="json",
21
+ id="resume-json-input",
22
+ classes="input-field json-input",
23
+ )
24
+ with Horizontal(classes="run-actions"):
25
+ yield Button(
26
+ "▶ Resume",
27
+ id="resume-btn",
28
+ variant="primary",
29
+ classes="action-btn",
30
+ )
31
+
32
+ def get_input_values(self) -> str:
33
+ """Return the JSON text to resume with."""
34
+ json_input = self.query_one("#resume-json-input", TextArea)
35
+ return json_input.text.strip()
@@ -1,8 +1,10 @@
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
+
6
8
  from ...._runtime._contracts import UiPathErrorContract
7
9
  from ._messages import LogMessage, TraceMessage
8
10
 
@@ -10,11 +12,12 @@ from ._messages import LogMessage, TraceMessage
10
12
  class ExecutionRun:
11
13
  """Represents a single execution run."""
12
14
 
13
- def __init__(self, entrypoint: str, input_data: str):
15
+ def __init__(self, entrypoint: str, input_data: Dict[str, Any]):
14
16
  self.id = str(uuid4())[:8]
15
17
  self.entrypoint = entrypoint
16
18
  self.input_data = input_data
17
- self.output_data: Optional[str] = None
19
+ self.resume_data: Optional[Dict[str, Any]] = None
20
+ self.output_data: Optional[Dict[str, Any]] = None
18
21
  self.start_time = datetime.now()
19
22
  self.end_time: Optional[datetime] = None
20
23
  self.status = "running" # running, completed, failed
@@ -32,14 +35,32 @@ class ExecutionRun:
32
35
  return f"{delta.total_seconds():.1f}s"
33
36
 
34
37
  @property
35
- def display_name(self) -> str:
36
- status_icon = {"running": "⚙️", "completed": "✅", "failed": "❌"}.get(
37
- self.status, ""
38
- )
38
+ def display_name(self) -> Text:
39
+ status_colors = {
40
+ "running": "yellow",
41
+ "suspended": "cyan",
42
+ "completed": "green",
43
+ "failed": "red",
44
+ }
45
+
46
+ status_icon = {
47
+ "running": "▶",
48
+ "suspended": "⏸",
49
+ "completed": "✔",
50
+ "failed": "✖",
51
+ }.get(self.status, "?")
39
52
 
40
53
  script_name = (
41
54
  os.path.basename(self.entrypoint) if self.entrypoint else "untitled"
42
55
  )
56
+ truncated_script = script_name[:10]
43
57
  time_str = self.start_time.strftime("%H:%M:%S")
58
+ duration_str = self.duration[:6]
59
+
60
+ text = Text()
61
+ text.append(f"{status_icon:<2} ", style=status_colors.get(self.status, "white"))
62
+ text.append(f"{truncated_script:<10} ")
63
+ text.append(f"({time_str:<8}) ")
64
+ text.append(f"[{duration_str:<6}]")
44
65
 
45
- return f"{status_icon} {script_name} ({time_str}) [{self.duration}]"
66
+ 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 {
@@ -34,6 +22,11 @@ Screen {
34
22
  color: #ffaa00;
35
23
  }
36
24
 
25
+ .run-suspended {
26
+ border-left: solid #00FFFF;
27
+ color: #e0e0e0;
28
+ }
29
+
37
30
  .run-completed {
38
31
  border-left: solid #00ff88;
39
32
  color: #e0e0e0;
@@ -47,43 +40,27 @@ Screen {
47
40
  .new-run-btn {
48
41
  width: 100%;
49
42
  margin-bottom: 1;
50
- background: #00d4ff;
51
- color: #000000;
52
43
  border: none;
53
44
  text-style: bold;
54
45
  }
55
-
56
- .new-run-btn:hover {
57
- background: #00a0cc;
58
- }
59
-
60
- /* Main content area */
61
46
  .main-content {
62
47
  width: 70%;
63
48
  padding-left: 1;
64
49
  }
65
50
 
66
- /* New run panel with embedded titles */
67
51
  .new-run-title {
68
- color: #00d4ff;
69
52
  text-style: bold;
70
- background: #252525;
71
53
  padding: 0 1;
72
54
  height: 1;
73
- border: solid #404040;
74
55
  margin-bottom: 0;
75
56
  }
76
57
 
77
58
  .new-run-panel {
78
59
  height: 100%;
79
- background: #252525;
80
- border: solid #404040;
81
60
  }
82
61
 
83
62
  .field-label {
84
- color: #00d4ff;
85
63
  text-style: bold;
86
- background: #252525;
87
64
  }
88
65
 
89
66
  .run-actions {
@@ -94,26 +71,10 @@ Screen {
94
71
  .action-btn {
95
72
  margin-right: 2;
96
73
  min-width: 8;
97
- background: #00ff88;
98
- color: #000000;
99
74
  border: none;
100
75
  text-style: bold;
101
76
  }
102
77
 
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
78
  .details-content {
118
79
  height: 1fr;
119
80
  }
@@ -134,12 +95,10 @@ Screen {
134
95
 
135
96
  .detail-log {
136
97
  height: 1fr;
137
- background: #252525;
138
98
  padding: 1;
139
99
  padding-top: 0;
140
100
  }
141
101
 
142
- /* Status indicators for buttons */
143
102
  .status-running {
144
103
  background: #ffaa00;
145
104
  color: #000000;
@@ -158,53 +117,16 @@ Screen {
158
117
  border: solid #ff4444;
159
118
  }
160
119
 
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
120
  .hidden {
192
121
  display: none;
193
122
  }
194
123
 
195
- /* Header and Footer */
196
- Header {
197
- background: #000000;
198
- color: #00d4ff;
199
- }
200
-
201
124
  Footer {
202
- background: #000000;
203
- color: #888888;
204
- border-top: solid #404040;
125
+ margin-top:1;
126
+ height: auto;
127
+ dock: bottom;
205
128
  }
206
129
 
207
- /* Tabbed content styling */
208
130
  TabbedContent {
209
131
  height: 100%;
210
132
  }
@@ -214,7 +136,6 @@ TabPane {
214
136
  padding: 0;
215
137
  }
216
138
 
217
- /* Traces tab layout */
218
139
  .traces-content {
219
140
  height: 100%;
220
141
  }
@@ -231,60 +152,24 @@ TabPane {
231
152
  padding-left: 1;
232
153
  }
233
154
 
234
- /* Tree styling */
235
155
  .spans-tree {
236
156
  height: 100%;
237
- background: #252525;
238
157
  padding: 1;
239
158
  padding-top: 0;
240
159
  }
241
160
 
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
161
  Label {
273
162
  margin: 1 1;
274
163
  width: 100%;
275
164
  height: 100%;
276
- background: $panel;
277
165
  border: tall $primary;
278
166
  content-align: center middle;
279
167
  }
280
168
 
281
- /* Content areas */
282
169
  ContentSwitcher {
283
170
  height: 1fr;
284
- background: transparent;
285
171
  }
286
172
 
287
- /* Span details styling */
288
173
  SpanDetailsDisplay {
289
174
  height: 100%;
290
175
  }
@@ -297,35 +182,22 @@ SpanDetailsDisplay {
297
182
  height: 100%;
298
183
  }
299
184
 
300
- /* Panels */
301
185
  .new-run-panel {
302
186
  height: 100%;
303
- background: #252525;
304
- padding: 1;
305
187
  }
306
188
 
307
- /* Section Titles */
308
189
  .new-run-title {
309
- color: #00d4ff;
310
190
  text-style: bold;
311
- background: #1f1f1f;
312
191
  padding: 0 1;
313
192
  height: 2;
314
193
  content-align: left middle;
315
194
  }
316
195
 
317
- /* Labels */
318
196
  .field-label {
319
- color: #00d4ff;
320
197
  text-style: bold;
321
198
  margin: 1 0;
322
199
  }
323
200
 
324
- .input-field {
325
- background: #1a1a1a;
326
- color: #e0e0e0;
327
- }
328
-
329
201
  .script-input {
330
202
  height: 3;
331
203
  }
@@ -347,15 +219,6 @@ SpanDetailsDisplay {
347
219
  border: none;
348
220
  }
349
221
 
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;
222
+ TextArea.invalid {
223
+ border: tall red;
361
224
  }
@@ -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
- else:
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.31
3
+ Version: 2.1.33
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,15 @@ 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=3dodd1MH9iIQG1timRtkuuMCk1QidDEjs3OWuPkLg3s,8790
35
- uipath/_cli/_dev/_terminal/_components/_details.py,sha256=IR76fZn20ST2Cc7LonRGlWldL2dJl3QWSrS-QBWEOgQ,15476
36
- uipath/_cli/_dev/_terminal/_components/_history.py,sha256=bpIm2uLP9sIP6v4meN0i4Pk2xOwVwXI4iPrWpQIzlDc,1807
37
- uipath/_cli/_dev/_terminal/_components/_new.py,sha256=81FVClAl_ou8B861PsgwU5flXFfxYVOLEr5gCdKia8c,4450
38
- uipath/_cli/_dev/_terminal/_models/_execution.py,sha256=XbU5b3IJ3Y-XIlTxUd1cRbZUfSJw28XxpUWSRRZ69p8,1499
34
+ uipath/_cli/_dev/_terminal/__init__.py,sha256=08aBD5-I6rcO9Sjp3sWWlinoRvHpa67Ss7yawXBhkBI,10136
35
+ uipath/_cli/_dev/_terminal/_components/_details.py,sha256=HzCFvi7CsXWsGXSFXo2X_QvUSpjtC8NfEM8Yu1wuOOA,16228
36
+ uipath/_cli/_dev/_terminal/_components/_history.py,sha256=-0lystNcVUCUbHgEUVQ-CdxAfV3_X5uhjxWevxs19Z0,2054
37
+ uipath/_cli/_dev/_terminal/_components/_json_input.py,sha256=MPkaeiA5KfkwJZKuNJ02hQksVtluZlmJv9nLRRAWYQI,592
38
+ uipath/_cli/_dev/_terminal/_components/_new.py,sha256=jxDFOQ6NCzTgesgx3srRr45ij1FqdICAB0uo6vXeh4I,4614
39
+ uipath/_cli/_dev/_terminal/_components/_resume.py,sha256=LW5TlgmhNjTv2nHLjGRmgzgtWvzuTr1T3WdPNujsLmo,1083
40
+ uipath/_cli/_dev/_terminal/_models/_execution.py,sha256=_tI01TX5W1GwG6OXBDDd28zUn-qp_Bf5hUaUqwMBOYo,2110
39
41
  uipath/_cli/_dev/_terminal/_models/_messages.py,sha256=TR7D1yLL0PNYGUMts_cGLgF8zj67urNwuX-5xSGqWgM,1762
40
- uipath/_cli/_dev/_terminal/_styles/terminal.tcss,sha256=k455ZxeB54hzPyH3CAj8VNLUtQPCCHr0IbTU1mqhD3U,5012
42
+ uipath/_cli/_dev/_terminal/_styles/terminal.tcss,sha256=t7PFpvwZ_TitoOCUQjW5_VB5AHHXg6QHxB-cB8ZXj6Q,2707
41
43
  uipath/_cli/_dev/_terminal/_traces/_exporter.py,sha256=oI6D_eMwrh_2aqDYUh4GrJg8VLGrLYhDahR-_o0uJns,4144
42
44
  uipath/_cli/_dev/_terminal/_traces/_logger.py,sha256=Dmfba3X9GmAZtXpzu_KDsleRCrpVo8_y-W6jizwFYq0,880
43
45
  uipath/_cli/_evals/evaluation_service.py,sha256=zqYRB-tZpTTFqMctjIpEli3joIlmrz3dCVZsxekxIps,22053
@@ -58,7 +60,7 @@ uipath/_cli/_runtime/_contracts.py,sha256=ays9ki4PQjdiy_z_kuR_Z0mHYVy_MZ6DvBG6g_
58
60
  uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
59
61
  uipath/_cli/_runtime/_hitl.py,sha256=aexwe0dIXvh6SlVS1jVnO_aGZc6e3gLsmGkCyha5AHo,11300
60
62
  uipath/_cli/_runtime/_logging.py,sha256=MGklGKPjYKjs7J5Jy9eplA9zCDsdtEbkZdCbTwgut_4,8311
61
- uipath/_cli/_runtime/_runtime.py,sha256=tgoMYALRTMGL8pSYbSL5nXJfq0lf_RGuNc7fmS4dlf4,11419
63
+ uipath/_cli/_runtime/_runtime.py,sha256=TXtXzscRPLdYJURH0Y-7sXsigC-2k_LttBOz7EUfWUQ,11449
62
64
  uipath/_cli/_templates/.psmdcp.template,sha256=C7pBJPt98ovEljcBvGtEUGoWjjQhu9jls1bpYjeLOKA,611
63
65
  uipath/_cli/_templates/.rels.template,sha256=-fTcw7OA1AcymHr0LzBqbMAAtzZTRXLTNa_ljq087Jk,406
64
66
  uipath/_cli/_templates/[Content_Types].xml.template,sha256=bYsKDz31PkIF9QksjgAY_bqm57YC8U_owsZeNZAiBxQ,584
@@ -126,8 +128,8 @@ uipath/tracing/_traced.py,sha256=qeVDrds2OUnpdUIA0RhtF0kg2dlAZhyC1RRkI-qivTM,185
126
128
  uipath/tracing/_utils.py,sha256=wJRELaPu69iY0AhV432Dk5QYf_N_ViRU4kAUG1BI1ew,10384
127
129
  uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
128
130
  uipath/utils/_endpoints_manager.py,sha256=iRTl5Q0XAm_YgcnMcJOXtj-8052sr6jpWuPNz6CgT0Q,8408
129
- uipath-2.1.31.dist-info/METADATA,sha256=FNf2u5VRm05BzVqs-z97iBkeOsH_Y78fGNozWYXekxo,6450
130
- uipath-2.1.31.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
131
- uipath-2.1.31.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
132
- uipath-2.1.31.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
133
- uipath-2.1.31.dist-info/RECORD,,
131
+ uipath-2.1.33.dist-info/METADATA,sha256=8ilJfyu-w3YSekotgT-mJKdVHHgeUBDFXhZMufMR4BY,6450
132
+ uipath-2.1.33.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
133
+ uipath-2.1.33.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
134
+ uipath-2.1.33.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
135
+ uipath-2.1.33.dist-info/RECORD,,