kiwi-code 0.0.4__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,271 @@
1
+ """Actions execution screen."""
2
+
3
+ from datetime import datetime
4
+ from textual.app import ComposeResult
5
+ from textual.screen import Screen
6
+ from textual.containers import Container, Horizontal, Vertical, ScrollableContainer
7
+ from textual.widgets import Header, Footer, Static, DataTable, Button, Input, Label
8
+ from loguru import logger
9
+
10
+ from ..models import Action, ActionExecution, ActionStatus
11
+ from ..widgets import StatusBadge, ActionButton, InfoPanel
12
+
13
+
14
+ class ActionsScreen(Screen):
15
+ """Screen for viewing and executing actions."""
16
+
17
+ CSS = """
18
+ ActionsScreen {
19
+ background: $surface;
20
+ }
21
+
22
+ #actions-header {
23
+ height: auto;
24
+ padding: 1;
25
+ background: $panel;
26
+ border-bottom: solid $primary;
27
+ }
28
+
29
+ #actions-title {
30
+ text-style: bold;
31
+ color: $accent;
32
+ text-align: center;
33
+ }
34
+
35
+ #main-content {
36
+ height: 1fr;
37
+ }
38
+
39
+ #left-panel {
40
+ width: 1fr;
41
+ padding: 1;
42
+ border-right: solid $primary;
43
+ }
44
+
45
+ #right-panel {
46
+ width: 2fr;
47
+ padding: 1;
48
+ }
49
+
50
+ #actions-list {
51
+ height: 1fr;
52
+ margin-top: 1;
53
+ }
54
+
55
+ #execution-container {
56
+ height: 1fr;
57
+ }
58
+
59
+ #action-buttons {
60
+ height: auto;
61
+ padding: 1;
62
+ align: center middle;
63
+ }
64
+
65
+ .section-title {
66
+ text-style: bold;
67
+ color: $accent;
68
+ padding: 1 0;
69
+ }
70
+
71
+ #status-display {
72
+ height: auto;
73
+ padding: 1;
74
+ border: solid $primary;
75
+ margin: 1 0;
76
+ }
77
+ """
78
+
79
+ BINDINGS = [
80
+ ("escape", "back", "Back"),
81
+ ("e", "execute", "Execute"),
82
+ ("r", "refresh", "Refresh"),
83
+ ("q", "quit", "Quit"),
84
+ ]
85
+
86
+ def __init__(self):
87
+ """Initialize actions screen."""
88
+ super().__init__()
89
+ self.actions: list[Action] = []
90
+ self.executions: list[ActionExecution] = []
91
+ self.selected_action: Action | None = None
92
+
93
+ def compose(self) -> ComposeResult:
94
+ """Compose actions screen widgets."""
95
+ yield Header()
96
+
97
+ with Container(id="actions-header"):
98
+ yield Static("⚡ Actions & Execution", id="actions-title")
99
+
100
+ with Horizontal(id="main-content"):
101
+ # Left panel - Actions list
102
+ with Vertical(id="left-panel"):
103
+ yield Static("Available Actions", classes="section-title")
104
+ yield DataTable(id="actions-list")
105
+
106
+ # Right panel - Execution details
107
+ with ScrollableContainer(id="right-panel"):
108
+ yield Static("Action Details", classes="section-title")
109
+
110
+ yield InfoPanel(
111
+ "No Action Selected",
112
+ "Select an action from the list to view details and execute.",
113
+ id="action-details"
114
+ )
115
+
116
+ with Horizontal(id="action-buttons"):
117
+ yield ActionButton("▶ Execute", variant="success", id="btn-execute")
118
+ yield ActionButton("⏹ Stop", variant="danger", id="btn-stop")
119
+
120
+ yield Static("Execution History", classes="section-title")
121
+ yield Container(id="execution-container")
122
+
123
+ yield Footer()
124
+
125
+ def on_mount(self) -> None:
126
+ """Called when screen is mounted."""
127
+ logger.info("Actions screen mounted")
128
+
129
+ # Setup table
130
+ table = self.query_one("#actions-list", DataTable)
131
+ table.cursor_type = "row"
132
+ table.zebra_stripes = True
133
+ table.add_columns("ID", "Name", "Autobot")
134
+
135
+ # Load actions
136
+ self.load_actions()
137
+
138
+ def load_actions(self) -> None:
139
+ """Load available actions."""
140
+ logger.debug("Loading actions")
141
+
142
+ # TODO: Fetch from autobots client
143
+ # Mock data
144
+ self.actions = [
145
+ Action(
146
+ id="act-001",
147
+ name="Generate Report",
148
+ description="Generate monthly sales report",
149
+ autobot_id="ab-002",
150
+ parameters={"format": "pdf", "month": "current"}
151
+ ),
152
+ Action(
153
+ id="act-002",
154
+ name="Send Notification",
155
+ description="Send notification to subscribers",
156
+ autobot_id="ab-005",
157
+ parameters={"channel": "email", "template": "newsletter"}
158
+ ),
159
+ Action(
160
+ id="act-003",
161
+ name="Analyze Data",
162
+ description="Run data analysis pipeline",
163
+ autobot_id="ab-002",
164
+ parameters={"dataset": "sales_2024", "model": "regression"}
165
+ ),
166
+ Action(
167
+ id="act-004",
168
+ name="Scrape Prices",
169
+ description="Scrape competitor pricing",
170
+ autobot_id="ab-003",
171
+ parameters={"urls": ["example.com"], "frequency": "daily"}
172
+ ),
173
+ ]
174
+
175
+ self.populate_table()
176
+
177
+ def populate_table(self) -> None:
178
+ """Populate actions table."""
179
+ table = self.query_one("#actions-list", DataTable)
180
+ table.clear()
181
+
182
+ for action in self.actions:
183
+ table.add_row(
184
+ action.id,
185
+ action.name,
186
+ action.autobot_id,
187
+ )
188
+
189
+ logger.info(f"Loaded {len(self.actions)} actions")
190
+
191
+ def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
192
+ """Handle action selection."""
193
+ row_key = event.row_key
194
+ table = self.query_one("#actions-list", DataTable)
195
+ row_data = table.get_row(row_key)
196
+
197
+ action_id = str(row_data[0])
198
+ self.selected_action = next(
199
+ (act for act in self.actions if act.id == action_id), None
200
+ )
201
+
202
+ if self.selected_action:
203
+ logger.info(f"Selected action: {self.selected_action.name}")
204
+ self.update_action_details()
205
+
206
+ def update_action_details(self) -> None:
207
+ """Update action details panel."""
208
+ if not self.selected_action:
209
+ return
210
+
211
+ details_text = f"{self.selected_action.description}\n\n"
212
+ details_text += f"ID: {self.selected_action.id}\n"
213
+ details_text += f"Autobot: {self.selected_action.autobot_id}\n\n"
214
+ details_text += "Parameters:\n"
215
+
216
+ for key, value in self.selected_action.parameters.items():
217
+ details_text += f" • {key}: {value}\n"
218
+
219
+ panel = self.query_one("#action-details", InfoPanel)
220
+ panel.query_one(".panel-title", Static).update(self.selected_action.name)
221
+ panel.update_content(details_text)
222
+
223
+ def on_button_pressed(self, event: Button.Pressed) -> None:
224
+ """Handle button press events."""
225
+ if event.button.id == "btn-execute":
226
+ self.action_execute()
227
+ elif event.button.id == "btn-stop":
228
+ self.stop_execution()
229
+
230
+ def action_execute(self) -> None:
231
+ """Execute selected action."""
232
+ if not self.selected_action:
233
+ self.notify("Please select an action first", severity="warning")
234
+ return
235
+
236
+ logger.info(f"Executing action: {self.selected_action.name}")
237
+
238
+ # TODO: Execute via autobots client
239
+ # Mock execution
240
+ execution = ActionExecution(
241
+ id=f"exec-{len(self.executions) + 1:03d}",
242
+ action_id=self.selected_action.id,
243
+ status=ActionStatus.RUNNING,
244
+ )
245
+ self.executions.append(execution)
246
+
247
+ self.notify(
248
+ f"Executing: {self.selected_action.name}",
249
+ severity="information"
250
+ )
251
+
252
+ def stop_execution(self) -> None:
253
+ """Stop running execution."""
254
+ logger.info("Stop execution requested")
255
+ self.notify("Stop execution coming soon!", severity="warning")
256
+
257
+ def action_back(self) -> None:
258
+ """Return to previous screen."""
259
+ logger.info("Returning to dashboard")
260
+ self.app.pop_screen()
261
+
262
+ def action_refresh(self) -> None:
263
+ """Refresh actions list."""
264
+ logger.info("Refreshing actions list")
265
+ self.load_actions()
266
+ self.notify("Actions list refreshed", severity="information")
267
+
268
+ def action_quit(self) -> None:
269
+ """Quit the application."""
270
+ logger.info("Quitting application from actions screen")
271
+ self.app.exit()
@@ -0,0 +1,216 @@
1
+ """Autobots list screen."""
2
+
3
+ from datetime import datetime
4
+ from textual.app import ComposeResult
5
+ from textual.screen import Screen
6
+ from textual.containers import Container, Vertical, Horizontal
7
+ from textual.widgets import Header, Footer, Static, DataTable, Button
8
+ from loguru import logger
9
+
10
+ from ..models import Autobot, AutobotType
11
+ from ..widgets import StatusBadge, ActionButton
12
+
13
+
14
+ class AutobotsScreen(Screen):
15
+ """Screen displaying list of autobots."""
16
+
17
+ CSS = """
18
+ AutobotsScreen {
19
+ background: $surface;
20
+ }
21
+
22
+ #autobots-header {
23
+ height: auto;
24
+ padding: 1;
25
+ background: $panel;
26
+ border-bottom: solid $primary;
27
+ }
28
+
29
+ #autobots-title {
30
+ text-style: bold;
31
+ color: $accent;
32
+ text-align: center;
33
+ }
34
+
35
+ #actions-bar {
36
+ height: auto;
37
+ padding: 1;
38
+ align: center middle;
39
+ }
40
+
41
+ #table-container {
42
+ height: 1fr;
43
+ padding: 1;
44
+ }
45
+
46
+ DataTable {
47
+ height: 100%;
48
+ }
49
+ """
50
+
51
+ BINDINGS = [
52
+ ("escape", "back", "Back"),
53
+ ("n", "new_autobot", "New"),
54
+ ("r", "refresh", "Refresh"),
55
+ ("q", "quit", "Quit"),
56
+ ]
57
+
58
+ def __init__(self):
59
+ """Initialize autobots screen."""
60
+ super().__init__()
61
+ self.autobots: list[Autobot] = []
62
+
63
+ def compose(self) -> ComposeResult:
64
+ """Compose autobots screen widgets."""
65
+ yield Header()
66
+
67
+ with Container(id="autobots-header"):
68
+ yield Static("🤖 Autobots Management", id="autobots-title")
69
+
70
+ with Horizontal(id="actions-bar"):
71
+ yield ActionButton("➕ New Autobot", variant="success", id="btn-new")
72
+ yield ActionButton("🔄 Refresh", variant="primary", id="btn-refresh")
73
+
74
+ with Container(id="table-container"):
75
+ yield DataTable(id="autobots-table")
76
+
77
+ yield Footer()
78
+
79
+ def on_mount(self) -> None:
80
+ """Called when screen is mounted."""
81
+ logger.info("Autobots screen mounted")
82
+
83
+ # Setup table
84
+ table = self.query_one(DataTable)
85
+ table.cursor_type = "row"
86
+ table.zebra_stripes = True
87
+
88
+ # Add columns
89
+ table.add_columns("ID", "Name", "Type", "Status", "Runs", "Last Run")
90
+
91
+ # Load autobots
92
+ self.load_autobots()
93
+
94
+ def load_autobots(self) -> None:
95
+ """Load autobots from backend."""
96
+ logger.debug("Loading autobots")
97
+
98
+ # TODO: Fetch from autobots client
99
+ # Mock data for now
100
+ self.autobots = [
101
+ Autobot(
102
+ id="ab-001",
103
+ name="Content Generator",
104
+ type=AutobotType.AUTOMATION,
105
+ description="Generates blog content automatically",
106
+ enabled=True,
107
+ run_count=45,
108
+ last_run=datetime.now(),
109
+ ),
110
+ Autobot(
111
+ id="ab-002",
112
+ name="Data Analyzer",
113
+ type=AutobotType.ANALYSIS,
114
+ description="Analyzes sales data and generates reports",
115
+ enabled=True,
116
+ run_count=23,
117
+ last_run=datetime.now(),
118
+ ),
119
+ Autobot(
120
+ id="ab-003",
121
+ name="Web Scraper",
122
+ type=AutobotType.SEARCH,
123
+ description="Scrapes competitor pricing data",
124
+ enabled=False,
125
+ run_count=12,
126
+ last_run=None,
127
+ ),
128
+ Autobot(
129
+ id="ab-004",
130
+ name="Chat Assistant",
131
+ type=AutobotType.CHAT,
132
+ description="Handles customer inquiries",
133
+ enabled=True,
134
+ run_count=156,
135
+ last_run=datetime.now(),
136
+ ),
137
+ Autobot(
138
+ id="ab-005",
139
+ name="Email Responder",
140
+ type=AutobotType.AUTOMATION,
141
+ description="Automated email responses",
142
+ enabled=True,
143
+ run_count=89,
144
+ last_run=datetime.now(),
145
+ ),
146
+ ]
147
+
148
+ self.populate_table()
149
+
150
+ def populate_table(self) -> None:
151
+ """Populate table with autobot data."""
152
+ table = self.query_one(DataTable)
153
+ table.clear()
154
+
155
+ for autobot in self.autobots:
156
+ status = "✓ Enabled" if autobot.enabled else "✗ Disabled"
157
+ last_run = (
158
+ autobot.last_run.strftime("%Y-%m-%d %H:%M")
159
+ if autobot.last_run
160
+ else "Never"
161
+ )
162
+
163
+ table.add_row(
164
+ autobot.id,
165
+ autobot.name,
166
+ autobot.type.value.title(),
167
+ status,
168
+ str(autobot.run_count),
169
+ last_run,
170
+ )
171
+
172
+ logger.info(f"Loaded {len(self.autobots)} autobots")
173
+
174
+ def on_button_pressed(self, event: Button.Pressed) -> None:
175
+ """Handle button press events."""
176
+ if event.button.id == "btn-new":
177
+ self.action_new_autobot()
178
+ elif event.button.id == "btn-refresh":
179
+ self.action_refresh()
180
+
181
+ def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
182
+ """Handle table row selection."""
183
+ row_key = event.row_key
184
+ table = self.query_one(DataTable)
185
+ row_data = table.get_row(row_key)
186
+
187
+ autobot_id = str(row_data[0])
188
+ autobot = next((ab for ab in self.autobots if ab.id == autobot_id), None)
189
+
190
+ if autobot:
191
+ logger.info(f"Selected autobot: {autobot.name}")
192
+ self.notify(
193
+ f"Selected: {autobot.name}\n{autobot.description}",
194
+ severity="information",
195
+ )
196
+
197
+ def action_back(self) -> None:
198
+ """Return to previous screen."""
199
+ logger.info("Returning to dashboard")
200
+ self.app.pop_screen()
201
+
202
+ def action_new_autobot(self) -> None:
203
+ """Create new autobot."""
204
+ logger.info("New autobot requested")
205
+ self.notify("New autobot creation coming soon!", severity="information")
206
+
207
+ def action_refresh(self) -> None:
208
+ """Refresh autobots list."""
209
+ logger.info("Refreshing autobots list")
210
+ self.load_autobots()
211
+ self.notify("Autobots list refreshed", severity="information")
212
+
213
+ def action_quit(self) -> None:
214
+ """Quit the application."""
215
+ logger.info("Quitting application from autobots screen")
216
+ self.app.exit()