uipath 2.1.26__py3-none-any.whl → 2.1.28__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.
@@ -0,0 +1,57 @@
1
+ from typing import List, Optional
2
+
3
+ from textual.app import ComposeResult
4
+ from textual.containers import Container, Vertical
5
+ from textual.widgets import Button, ListItem, ListView, Static
6
+
7
+ from .._models._execution import ExecutionRun
8
+
9
+
10
+ class RunHistoryPanel(Container):
11
+ """Left panel showing execution run history."""
12
+
13
+ def __init__(self, **kwargs):
14
+ super().__init__(**kwargs)
15
+ self.runs: List[ExecutionRun] = []
16
+ self.selected_run: Optional[ExecutionRun] = None
17
+
18
+ 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
+ )
24
+
25
+ def add_run(self, run: ExecutionRun):
26
+ """Add a new run to history."""
27
+ self.runs.insert(0, run) # Add to top
28
+ self.refresh_list()
29
+
30
+ def update_run(self, run: ExecutionRun):
31
+ """Update an existing run."""
32
+ self.refresh_list()
33
+
34
+ def refresh_list(self):
35
+ """Refresh the run list display."""
36
+ run_list = self.query_one("#run-list", ListView)
37
+ run_list.clear()
38
+
39
+ for run in self.runs:
40
+ item = ListItem(
41
+ Static(run.display_name), classes=f"run-item run-{run.status}"
42
+ )
43
+ # Store run id directly on the ListItem
44
+ item.run_id = run.id # type: ignore[attr-defined]
45
+ run_list.append(item)
46
+
47
+ def get_run_by_id(self, run_id: str) -> Optional[ExecutionRun]:
48
+ """Get run by id."""
49
+ for run in self.runs:
50
+ if run.id == run_id:
51
+ return run
52
+ return None
53
+
54
+ def clear_runs(self):
55
+ """Clear all runs from history."""
56
+ self.runs.clear()
57
+ self.refresh_list()
@@ -0,0 +1,133 @@
1
+ import json
2
+ import os
3
+ from typing import Any, Dict, Tuple, cast
4
+
5
+ from textual.app import ComposeResult
6
+ from textual.containers import Container, Horizontal, Vertical
7
+ from textual.reactive import reactive
8
+ from textual.widgets import Button, Select, TextArea
9
+
10
+
11
+ def mock_json_from_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
12
+ props = schema.get("properties", {})
13
+ required = schema.get("required", [])
14
+ mock = {}
15
+ for key, info in props.items():
16
+ if "default" in info:
17
+ mock[key] = info["default"]
18
+ continue
19
+ t = info.get("type")
20
+ if t == "string":
21
+ mock[key] = f"example_{key}" if key in required else ""
22
+ elif t == "integer":
23
+ mock[key] = 0 if key in required else None
24
+ elif t == "boolean":
25
+ mock[key] = True if key in required else False
26
+ elif t == "array":
27
+ item_schema = info.get("items", {"type": "string"})
28
+ mock[key] = [mock_json_from_schema(item_schema)]
29
+ elif t == "object":
30
+ mock[key] = mock_json_from_schema(info)
31
+ else:
32
+ mock[key] = None
33
+ return mock
34
+
35
+
36
+ class NewRunPanel(Container):
37
+ """Panel for creating new runs with a Select entrypoint selector."""
38
+
39
+ selected_entrypoint = reactive("")
40
+
41
+ def __init__(self, **kwargs):
42
+ super().__init__(**kwargs)
43
+ json_path = os.path.join(os.getcwd(), "uipath.json")
44
+ with open(json_path, "r") as f:
45
+ data = json.load(f)
46
+
47
+ self.entrypoints = data.get("entryPoints", [])
48
+ self.entrypoint_paths = [ep["filePath"] for ep in self.entrypoints]
49
+
50
+ self.selected_entrypoint = (
51
+ self.entrypoint_paths[0] if self.entrypoint_paths else ""
52
+ )
53
+ ep: Dict[str, Any] = next(
54
+ (
55
+ ep
56
+ for ep in self.entrypoints
57
+ if ep["filePath"] == self.selected_entrypoint
58
+ ),
59
+ {},
60
+ )
61
+ self.initial_input = json.dumps(
62
+ mock_json_from_schema(ep.get("input", {})), indent=2
63
+ )
64
+
65
+ 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
+ )
92
+
93
+ async def on_select_changed(self, event: Select.Changed) -> None:
94
+ """Update JSON input when user selects an entrypoint."""
95
+ self.selected_entrypoint = cast(str, event.value)
96
+
97
+ ep: Dict[str, Any] = next(
98
+ (
99
+ ep
100
+ for ep in self.entrypoints
101
+ if ep["filePath"] == self.selected_entrypoint
102
+ ),
103
+ {},
104
+ )
105
+ json_input = self.query_one("#json-input", TextArea)
106
+ json_input.text = json.dumps(
107
+ mock_json_from_schema(ep.get("input", {})), indent=2
108
+ )
109
+
110
+ def get_input_values(self) -> Tuple[str, str]:
111
+ json_input = self.query_one("#json-input", TextArea)
112
+ return self.selected_entrypoint, json_input.text.strip()
113
+
114
+ def reset_form(self):
115
+ """Reset selection and JSON input to defaults."""
116
+ self.selected_entrypoint = (
117
+ self.entrypoint_paths[0] if self.entrypoint_paths else ""
118
+ )
119
+ select = self.query_one("#entrypoint-select", Select)
120
+ select.value = self.selected_entrypoint
121
+
122
+ ep: Dict[str, Any] = next(
123
+ (
124
+ ep
125
+ for ep in self.entrypoints
126
+ if ep["filePath"] == self.selected_entrypoint
127
+ ),
128
+ {},
129
+ )
130
+ json_input = self.query_one("#json-input", TextArea)
131
+ json_input.text = json.dumps(
132
+ mock_json_from_schema(ep.get("input", {})), indent=2
133
+ )
@@ -0,0 +1,43 @@
1
+ import os
2
+ from datetime import datetime
3
+ from typing import List, Optional
4
+ from uuid import uuid4
5
+
6
+ from ._messages import LogMessage, TraceMessage
7
+
8
+
9
+ class ExecutionRun:
10
+ """Represents a single execution run."""
11
+
12
+ def __init__(self, entrypoint: str, input_data: str):
13
+ self.id = str(uuid4())[:8]
14
+ self.entrypoint = entrypoint
15
+ self.input_data = input_data
16
+ self.output_data: Optional[str] = None
17
+ self.start_time = datetime.now()
18
+ self.end_time: Optional[datetime] = None
19
+ self.status = "running" # running, completed, failed
20
+ self.traces: List[TraceMessage] = []
21
+ self.logs: List[LogMessage] = []
22
+
23
+ @property
24
+ def duration(self) -> str:
25
+ if self.end_time:
26
+ delta = self.end_time - self.start_time
27
+ return f"{delta.total_seconds():.1f}s"
28
+ else:
29
+ delta = datetime.now() - self.start_time
30
+ return f"{delta.total_seconds():.1f}s"
31
+
32
+ @property
33
+ def display_name(self) -> str:
34
+ status_icon = {"running": "⚙️", "completed": "✅", "failed": "❌"}.get(
35
+ self.status, "❓"
36
+ )
37
+
38
+ script_name = (
39
+ os.path.basename(self.entrypoint) if self.entrypoint else "untitled"
40
+ )
41
+ time_str = self.start_time.strftime("%H:%M:%S")
42
+
43
+ return f"{status_icon} {script_name} ({time_str}) [{self.duration}]"
@@ -0,0 +1,65 @@
1
+ from datetime import datetime
2
+ from typing import Any, Dict, Optional
3
+
4
+ from textual.message import Message
5
+
6
+
7
+ class ExecutionMessage(Message):
8
+ """Message sent when execution starts or completes."""
9
+
10
+ def __init__(
11
+ self,
12
+ run_id: str,
13
+ status: str,
14
+ success: Optional[bool] = None,
15
+ error: Optional[str] = None,
16
+ ):
17
+ self.run_id = run_id
18
+ self.status = status # "started", "completed", "failed"
19
+ self.success = success
20
+ self.error = error
21
+ super().__init__()
22
+
23
+
24
+ class LogMessage(Message):
25
+ """Message sent when a new log entry is created."""
26
+
27
+ def __init__(
28
+ self,
29
+ run_id: str,
30
+ level: str,
31
+ message: str,
32
+ timestamp: Optional[datetime] = None,
33
+ ):
34
+ self.run_id = run_id
35
+ self.level = level
36
+ self.message = message
37
+ self.timestamp = timestamp or datetime.now()
38
+ super().__init__()
39
+
40
+
41
+ class TraceMessage(Message):
42
+ """Message sent when a new trace entry is created."""
43
+
44
+ def __init__(
45
+ self,
46
+ run_id: str,
47
+ span_name: str,
48
+ span_id: str,
49
+ parent_span_id: Optional[str] = None,
50
+ trace_id: Optional[str] = None,
51
+ status: str = "running",
52
+ duration_ms: Optional[float] = None,
53
+ timestamp: Optional[datetime] = None,
54
+ attributes: Optional[Dict[str, Any]] = None,
55
+ ):
56
+ self.run_id = run_id
57
+ self.span_name = span_name
58
+ self.span_id = span_id
59
+ self.parent_span_id = parent_span_id
60
+ self.trace_id = trace_id
61
+ self.status = status
62
+ self.duration_ms = duration_ms
63
+ self.timestamp = timestamp or datetime.now()
64
+ self.attributes = attributes or {}
65
+ super().__init__()
@@ -0,0 +1,361 @@
1
+ /* Global layout - dark terminal theme */
2
+ Screen {
3
+ background: #1a1a1a;
4
+ color: #e0e0e0;
5
+ layout: horizontal;
6
+ }
7
+
8
+ /* Left sidebar - run history with embedded title */
9
+ .run-history {
10
+ width: 30%;
11
+ min-width: 25;
12
+ padding-right: 1;
13
+ }
14
+
15
+ .run-list {
16
+ height: 1fr;
17
+ margin-bottom: 1;
18
+ border: solid #404040;
19
+ background: #252525;
20
+ }
21
+
22
+ .run-item {
23
+ padding: 0 1;
24
+ background: transparent;
25
+ color: #e0e0e0;
26
+ }
27
+
28
+ .run-item:hover {
29
+ background: #333333;
30
+ }
31
+
32
+ .run-running {
33
+ border-left: solid #ffaa00;
34
+ color: #ffaa00;
35
+ }
36
+
37
+ .run-completed {
38
+ border-left: solid #00ff88;
39
+ color: #e0e0e0;
40
+ }
41
+
42
+ .run-failed {
43
+ border-left: solid #ff4444;
44
+ color: #ff4444;
45
+ }
46
+
47
+ .new-run-btn {
48
+ width: 100%;
49
+ margin-bottom: 1;
50
+ background: #00d4ff;
51
+ color: #000000;
52
+ border: none;
53
+ text-style: bold;
54
+ }
55
+
56
+ .new-run-btn:hover {
57
+ background: #00a0cc;
58
+ }
59
+
60
+ /* Main content area */
61
+ .main-content {
62
+ width: 70%;
63
+ padding-left: 1;
64
+ }
65
+
66
+ /* New run panel with embedded titles */
67
+ .new-run-title {
68
+ color: #00d4ff;
69
+ text-style: bold;
70
+ background: #252525;
71
+ padding: 0 1;
72
+ height: 1;
73
+ border: solid #404040;
74
+ margin-bottom: 0;
75
+ }
76
+
77
+ .new-run-panel {
78
+ height: 100%;
79
+ background: #252525;
80
+ border: solid #404040;
81
+ }
82
+
83
+ .field-label {
84
+ color: #00d4ff;
85
+ text-style: bold;
86
+ background: #252525;
87
+ }
88
+
89
+ .run-actions {
90
+ height: 2;
91
+ align: left middle;
92
+ }
93
+
94
+ .action-btn {
95
+ margin-right: 2;
96
+ min-width: 8;
97
+ background: #00ff88;
98
+ color: #000000;
99
+ border: none;
100
+ text-style: bold;
101
+ }
102
+
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
+ .details-content {
118
+ height: 1fr;
119
+ }
120
+
121
+ .traces-section,
122
+ .logs-section {
123
+ width: 50%;
124
+ height: 100%;
125
+ }
126
+
127
+ .traces-section {
128
+ width: 50%;
129
+ }
130
+
131
+ .logs-section {
132
+ width: 50%;
133
+ }
134
+
135
+ .detail-log {
136
+ height: 1fr;
137
+ background: #252525;
138
+ padding: 1;
139
+ padding-top: 0;
140
+ }
141
+
142
+ /* Status indicators for buttons */
143
+ .status-running {
144
+ background: #ffaa00;
145
+ color: #000000;
146
+ border: solid #ffaa00;
147
+ }
148
+
149
+ .status-success {
150
+ background: #00ff88;
151
+ color: #000000;
152
+ border: solid #00ff88;
153
+ }
154
+
155
+ .status-error {
156
+ background: #ff4444;
157
+ color: #ffffff;
158
+ border: solid #ff4444;
159
+ }
160
+
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
+ .hidden {
192
+ display: none;
193
+ }
194
+
195
+ /* Header and Footer */
196
+ Header {
197
+ background: #000000;
198
+ color: #00d4ff;
199
+ }
200
+
201
+ Footer {
202
+ background: #000000;
203
+ color: #888888;
204
+ border-top: solid #404040;
205
+ }
206
+
207
+ /* Tabbed content styling */
208
+ TabbedContent {
209
+ height: 100%;
210
+ }
211
+
212
+ TabPane {
213
+ height: 100%;
214
+ padding: 0;
215
+ }
216
+
217
+ /* Traces tab layout */
218
+ .traces-content {
219
+ height: 100%;
220
+ }
221
+
222
+ .spans-tree-section {
223
+ width: 40%;
224
+ height: 100%;
225
+ padding-right: 1;
226
+ }
227
+
228
+ .span-details-section {
229
+ width: 60%;
230
+ height: 100%;
231
+ padding-left: 1;
232
+ }
233
+
234
+ /* Tree styling */
235
+ .spans-tree {
236
+ height: 100%;
237
+ background: #252525;
238
+ padding: 1;
239
+ padding-top: 0;
240
+ }
241
+
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
+ Label {
273
+ margin: 1 1;
274
+ width: 100%;
275
+ height: 100%;
276
+ background: $panel;
277
+ border: tall $primary;
278
+ content-align: center middle;
279
+ }
280
+
281
+ /* Content areas */
282
+ ContentSwitcher {
283
+ height: 1fr;
284
+ background: transparent;
285
+ }
286
+
287
+ /* Span details styling */
288
+ SpanDetailsDisplay {
289
+ height: 100%;
290
+ }
291
+
292
+ #span-details-display {
293
+ height: 100%;
294
+ }
295
+
296
+ #span-details {
297
+ height: 100%;
298
+ }
299
+
300
+ /* Panels */
301
+ .new-run-panel {
302
+ height: 100%;
303
+ background: #252525;
304
+ padding: 1;
305
+ }
306
+
307
+ /* Section Titles */
308
+ .new-run-title {
309
+ color: #00d4ff;
310
+ text-style: bold;
311
+ background: #1f1f1f;
312
+ padding: 0 1;
313
+ height: 2;
314
+ content-align: left middle;
315
+ }
316
+
317
+ /* Labels */
318
+ .field-label {
319
+ color: #00d4ff;
320
+ text-style: bold;
321
+ margin: 1 0;
322
+ }
323
+
324
+ .input-field {
325
+ background: #1a1a1a;
326
+ color: #e0e0e0;
327
+ }
328
+
329
+ .script-input {
330
+ height: 3;
331
+ }
332
+
333
+ .json-input {
334
+ margin-top: 1;
335
+ height: 12;
336
+ }
337
+
338
+ .run-actions {
339
+ height: auto;
340
+ padding: 1;
341
+ }
342
+
343
+ .action-btn {
344
+ min-width: 10;
345
+ padding: 0 2;
346
+ text-style: bold;
347
+ border: none;
348
+ }
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
+ }