aline-ai 0.6.2__py3-none-any.whl → 0.6.3__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.
@@ -80,23 +80,16 @@ class EventsTable(Container):
80
80
  }
81
81
 
82
82
  EventsTable .table-container {
83
- height: auto;
83
+ height: 1fr;
84
84
  overflow-x: auto;
85
- overflow-y: hidden;
85
+ overflow-y: auto;
86
86
  }
87
87
 
88
88
  EventsTable DataTable {
89
89
  height: auto;
90
90
  max-height: 100%;
91
91
  overflow-x: auto;
92
- overflow-y: hidden;
93
- }
94
-
95
- EventsTable .pagination-info {
96
- height: 1;
97
- margin-top: 1;
98
- color: $text-muted;
99
- text-align: center;
92
+ overflow-y: auto;
100
93
  }
101
94
 
102
95
  EventsTable .stats-info {
@@ -107,9 +100,9 @@ class EventsTable(Container):
107
100
  """
108
101
 
109
102
  # Reactive properties
110
- current_page: reactive[int] = reactive(1)
111
- rows_per_page: reactive[int] = reactive(10)
112
103
  wrap_mode: reactive[bool] = reactive(False)
104
+ # Maximum events to load (for scrollable list)
105
+ MAX_EVENTS: int = 500
113
106
 
114
107
  def __init__(self) -> None:
115
108
  super().__init__()
@@ -122,8 +115,9 @@ class EventsTable(Container):
122
115
  self._refresh_worker: Optional[Worker] = None
123
116
  self._share_export_worker: Optional[Worker] = None
124
117
  self._refresh_timer = None
125
- self._active_refresh_snapshot: Optional[tuple[int, int]] = None
126
- self._pending_refresh_snapshot: Optional[tuple[int, int]] = None
118
+ self._is_refreshing: bool = False
119
+ self._pending_refresh: bool = False
120
+ self._saved_cursor_event_id: Optional[str] = None
127
121
 
128
122
  def compose(self) -> ComposeResult:
129
123
  """Compose the events table layout."""
@@ -150,7 +144,6 @@ class EventsTable(Container):
150
144
  yield Static(id="section-header", classes="section-header")
151
145
  with Container(classes="table-container"):
152
146
  yield EventsListTable(id="events-table")
153
- yield Static(id="pagination-info", classes="pagination-info")
154
147
  yield Static(id="stats-info", classes="stats-info")
155
148
  logger.debug("EventsTable.compose() completed")
156
149
  except Exception as e:
@@ -164,22 +157,19 @@ class EventsTable(Container):
164
157
  table = self.query_one("#events-table", EventsListTable)
165
158
  table.owner = self
166
159
  self._setup_table_columns(table)
167
-
168
- # Calculate initial rows per page
169
- self._calculate_rows_per_page()
170
160
  logger.debug("EventsTable.on_mount() completed")
171
161
  except Exception as e:
172
162
  logger.error(f"EventsTable.on_mount() failed: {e}\n{traceback.format_exc()}")
173
163
  raise
174
164
 
175
165
  def on_resize(self) -> None:
176
- """Handle window resize to adjust rows per page."""
177
- self._sync_to_available_height()
166
+ """Handle window resize."""
167
+ pass # No longer need to recalculate pagination
178
168
 
179
169
  def on_show(self) -> None:
180
- """Re-sync pagination when the tab becomes visible."""
170
+ """Refresh data when the tab becomes visible."""
181
171
  if self._refresh_timer is None:
182
- self._refresh_timer = self.set_interval(5.0, self._on_refresh_timer)
172
+ self._refresh_timer = self.set_interval(60.0, self._on_refresh_timer)
183
173
  else:
184
174
  try:
185
175
  self._refresh_timer.resume()
@@ -197,9 +187,7 @@ class EventsTable(Container):
197
187
  pass
198
188
 
199
189
  def _on_became_visible(self) -> None:
200
- self._sync_to_available_height()
201
190
  self._load_events()
202
- self._update_display()
203
191
  try:
204
192
  self.query_one("#events-table", DataTable).focus()
205
193
  except Exception:
@@ -388,41 +376,6 @@ class EventsTable(Container):
388
376
  share_btn = self.query_one("#share-event-btn", Button)
389
377
  share_btn.disabled = selected_count == 0
390
378
 
391
- def _sync_to_available_height(self) -> None:
392
- """Recalculate rows per page and reload if the page size changed."""
393
- old_rows_per_page = self.rows_per_page
394
- self._calculate_rows_per_page()
395
-
396
- if self.rows_per_page != old_rows_per_page:
397
- total_pages = self._get_total_pages()
398
- if self.current_page > total_pages:
399
- self.current_page = total_pages
400
- self._load_events()
401
-
402
- self._update_display()
403
-
404
- def _calculate_rows_per_page(self) -> None:
405
- """Calculate rows per page based on available height."""
406
- try:
407
- panel_height = self.size.height
408
-
409
- # Calculate exact space needed:
410
- # - Summary section: ~1 line content + 2 border + 2 padding + 1 margin = 6
411
- # - Section header: 1 line + 1 margin = 2
412
- # - Table header row: 1
413
- # - Pagination info: 1 line + 1 margin = 2
414
- # - Panel padding: 2 (top + bottom)
415
- # - Extra buffer: 3
416
-
417
- fixed_height = 6 + 2 + 1 + 2 + 2 + 3 # = 16
418
-
419
- available_for_rows = panel_height - fixed_height
420
- rows = max(available_for_rows, 3) # At least 3 rows
421
-
422
- self.rows_per_page = rows
423
- except Exception:
424
- self.rows_per_page = 10
425
-
426
379
  async def on_button_pressed(self, event: Button.Pressed) -> None:
427
380
  button_id = event.button.id or ""
428
381
  if button_id == "share-import-btn":
@@ -442,25 +395,6 @@ class EventsTable(Container):
442
395
 
443
396
  self.app.push_screen(ShareImportScreen())
444
397
 
445
- def _get_total_pages(self) -> int:
446
- """Calculate total pages."""
447
- if self._total_events == 0:
448
- return 1
449
- return (self._total_events + self.rows_per_page - 1) // self.rows_per_page
450
-
451
- def action_next_page(self) -> None:
452
- """Go to next page."""
453
- total_pages = self._get_total_pages()
454
- if self.current_page < total_pages:
455
- self.current_page += 1
456
- self._load_events()
457
-
458
- def action_prev_page(self) -> None:
459
- """Go to previous page."""
460
- if self.current_page > 1:
461
- self.current_page -= 1
462
- self._load_events()
463
-
464
398
  def _on_refresh_timer(self) -> None:
465
399
  self.refresh_data(force=False)
466
400
 
@@ -469,26 +403,37 @@ class EventsTable(Container):
469
403
  if not self.display:
470
404
  return
471
405
 
472
- snapshot = (int(self.current_page), int(self.rows_per_page))
473
406
  if self._refresh_worker is not None and self._refresh_worker.state in (
474
407
  WorkerState.PENDING,
475
408
  WorkerState.RUNNING,
476
409
  ):
477
410
  if force:
478
- self._pending_refresh_snapshot = snapshot
411
+ self._pending_refresh = True
479
412
  return
480
413
 
481
- if force and self._pending_refresh_snapshot is not None:
482
- snapshot = self._pending_refresh_snapshot
483
- self._pending_refresh_snapshot = None
414
+ # Save current cursor position before refresh
415
+ self._save_cursor_position()
484
416
 
485
417
  def work() -> dict:
486
- return self._collect_snapshot(*snapshot)
418
+ return self._collect_all_events()
487
419
 
488
- self._active_refresh_snapshot = snapshot
489
- self._pending_refresh_snapshot = None
420
+ self._is_refreshing = True
421
+ self._pending_refresh = False
490
422
  self._refresh_worker = self.run_worker(work, thread=True, exit_on_error=False)
491
423
 
424
+ def _save_cursor_position(self) -> None:
425
+ """Save the current cursor event ID to restore after refresh."""
426
+ try:
427
+ table = self.query_one("#events-table", DataTable)
428
+ if table.row_count > 0:
429
+ self._saved_cursor_event_id = str(
430
+ table.coordinate_to_cell_key(table.cursor_coordinate)[0].value
431
+ )
432
+ else:
433
+ self._saved_cursor_event_id = None
434
+ except Exception:
435
+ self._saved_cursor_event_id = None
436
+
492
437
  def _load_events(self) -> None:
493
438
  """Compatibility hook (tests stub this); default triggers async refresh."""
494
439
  if not self.is_mounted:
@@ -510,30 +455,29 @@ class EventsTable(Container):
510
455
 
511
456
  if event.state == WorkerState.ERROR:
512
457
  result = {
513
- "snapshot": self._active_refresh_snapshot,
514
458
  "total_events": 0,
515
459
  "events": [],
516
460
  }
461
+ self._is_refreshing = False
517
462
  elif event.state != WorkerState.SUCCESS:
518
463
  return
519
464
  else:
520
465
  result = self._refresh_worker.result or {}
466
+ self._is_refreshing = False
521
467
 
522
- snapshot = result.get("snapshot")
523
- if snapshot == (int(self.current_page), int(self.rows_per_page)):
524
- try:
525
- self._total_events = int(result.get("total_events") or 0)
526
- except Exception:
527
- self._total_events = 0
528
- try:
529
- self._events = list(result.get("events") or [])
530
- self._events_by_id = {e["id"]: e for e in self._events}
531
- except Exception:
532
- self._events = []
533
- self._events_by_id = {}
534
- self._update_display()
468
+ try:
469
+ self._total_events = int(result.get("total_events") or 0)
470
+ except Exception:
471
+ self._total_events = 0
472
+ try:
473
+ self._events = list(result.get("events") or [])
474
+ self._events_by_id = {e["id"]: e for e in self._events}
475
+ except Exception:
476
+ self._events = []
477
+ self._events_by_id = {}
478
+ self._update_display()
535
479
 
536
- if self._pending_refresh_snapshot is not None:
480
+ if self._pending_refresh:
537
481
  self.refresh_data()
538
482
 
539
483
  def _start_share_export(self) -> None:
@@ -718,8 +662,8 @@ class EventsTable(Container):
718
662
  return ""
719
663
  return ""
720
664
 
721
- def _collect_snapshot(self, page: int, rows_per_page: int) -> dict:
722
- """Collect events for a single page (background thread)."""
665
+ def _collect_all_events(self) -> dict:
666
+ """Collect all events (background thread)."""
723
667
  total_events: int = 0
724
668
  events: list[dict] = []
725
669
 
@@ -733,8 +677,7 @@ class EventsTable(Container):
733
677
  row = conn.execute("SELECT COUNT(*) FROM events").fetchone()
734
678
  total_events = int(row[0]) if row else 0
735
679
 
736
- # Get paginated events with session count
737
- offset = (int(page) - 1) * int(rows_per_page)
680
+ # Get all events (up to MAX_EVENTS)
738
681
  try:
739
682
  rows = conn.execute(
740
683
  """
@@ -749,9 +692,9 @@ class EventsTable(Container):
749
692
  (SELECT COUNT(*) FROM event_sessions WHERE event_id = e.id) AS session_count
750
693
  FROM events e
751
694
  ORDER BY e.created_at DESC
752
- LIMIT ? OFFSET ?
695
+ LIMIT ?
753
696
  """,
754
- (int(rows_per_page), int(offset)),
697
+ (self.MAX_EVENTS,),
755
698
  ).fetchall()
756
699
  has_new_columns = True
757
700
  except Exception:
@@ -766,9 +709,9 @@ class EventsTable(Container):
766
709
  (SELECT COUNT(*) FROM event_sessions WHERE event_id = e.id) AS session_count
767
710
  FROM events e
768
711
  ORDER BY e.created_at DESC
769
- LIMIT ? OFFSET ?
712
+ LIMIT ?
770
713
  """,
771
- (int(rows_per_page), int(offset)),
714
+ (self.MAX_EVENTS,),
772
715
  ).fetchall()
773
716
  has_new_columns = False
774
717
 
@@ -826,7 +769,7 @@ class EventsTable(Container):
826
769
 
827
770
  events.append(
828
771
  {
829
- "index": offset + i + 1,
772
+ "index": i + 1,
830
773
  "id": event_id,
831
774
  "short_id": self._shorten_id(event_id),
832
775
  "title": title,
@@ -844,7 +787,6 @@ class EventsTable(Container):
844
787
  events = []
845
788
 
846
789
  return {
847
- "snapshot": (int(page), int(rows_per_page)),
848
790
  "total_events": total_events,
849
791
  "events": events,
850
792
  }
@@ -860,18 +802,23 @@ class EventsTable(Container):
860
802
 
861
803
  # Update table
862
804
  table = self.query_one("#events-table", DataTable)
863
- selected_event_id = None
864
- try:
865
- if table.row_count > 0:
866
- selected_event_id = str(
867
- table.coordinate_to_cell_key(table.cursor_coordinate)[0].value
868
- )
869
- except Exception:
870
- selected_event_id = None
805
+
806
+ # Use saved cursor position if available, otherwise try to get current
807
+ restore_event_id = self._saved_cursor_event_id
808
+ if restore_event_id is None:
809
+ try:
810
+ if table.row_count > 0:
811
+ restore_event_id = str(
812
+ table.coordinate_to_cell_key(table.cursor_coordinate)[0].value
813
+ )
814
+ except Exception:
815
+ restore_event_id = None
816
+
871
817
  table.clear()
872
818
 
873
- # Always enable horizontal scrollbar
819
+ # Always enable scrollbars
874
820
  table.styles.overflow_x = "auto"
821
+ table.styles.overflow_y = "auto"
875
822
  table.show_horizontal_scrollbar = True
876
823
 
877
824
  for event in self._events:
@@ -902,10 +849,10 @@ class EventsTable(Container):
902
849
  )
903
850
 
904
851
  if table.row_count > 0:
905
- if selected_event_id:
852
+ if restore_event_id:
906
853
  try:
907
854
  table.cursor_coordinate = (
908
- table.get_row_index(selected_event_id),
855
+ table.get_row_index(restore_event_id),
909
856
  0,
910
857
  )
911
858
  except Exception:
@@ -913,12 +860,8 @@ class EventsTable(Container):
913
860
  else:
914
861
  table.cursor_coordinate = (0, 0)
915
862
 
916
- # Update pagination info
917
- total_pages = self._get_total_pages()
918
- pagination_widget = self.query_one("#pagination-info", Static)
919
- pagination_widget.update(
920
- f"[dim]Page {self.current_page}/{total_pages} ({self._total_events} total) │ (p) prev (n) next[/dim]"
921
- )
863
+ # Clear saved cursor position after restore
864
+ self._saved_cursor_event_id = None
922
865
 
923
866
  def _shorten_id(self, event_id: str) -> str:
924
867
  """Shorten an event ID for display."""