vector-inspector 0.3.9__py3-none-any.whl → 0.3.12__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.
Files changed (33) hide show
  1. vector_inspector/__init__.py +10 -1
  2. vector_inspector/core/connection_manager.py +91 -19
  3. vector_inspector/core/connections/base_connection.py +43 -43
  4. vector_inspector/core/connections/chroma_connection.py +1 -1
  5. vector_inspector/core/connections/pgvector_connection.py +12 -172
  6. vector_inspector/core/connections/pinecone_connection.py +596 -99
  7. vector_inspector/core/connections/qdrant_connection.py +35 -44
  8. vector_inspector/core/embedding_utils.py +14 -5
  9. vector_inspector/core/logging.py +3 -1
  10. vector_inspector/extensions/__init__.py +6 -0
  11. vector_inspector/extensions/telemetry_settings_panel.py +25 -0
  12. vector_inspector/main.py +45 -2
  13. vector_inspector/services/backup_restore_service.py +228 -15
  14. vector_inspector/services/settings_service.py +79 -19
  15. vector_inspector/services/telemetry_service.py +88 -0
  16. vector_inspector/ui/components/backup_restore_dialog.py +215 -101
  17. vector_inspector/ui/components/connection_manager_panel.py +155 -14
  18. vector_inspector/ui/dialogs/cross_db_migration.py +126 -99
  19. vector_inspector/ui/dialogs/settings_dialog.py +13 -6
  20. vector_inspector/ui/loading_screen.py +169 -0
  21. vector_inspector/ui/main_window.py +44 -19
  22. vector_inspector/ui/services/dialog_service.py +1 -0
  23. vector_inspector/ui/views/collection_browser.py +36 -34
  24. vector_inspector/ui/views/connection_view.py +7 -1
  25. vector_inspector/ui/views/info_panel.py +118 -52
  26. vector_inspector/ui/views/metadata_view.py +30 -31
  27. vector_inspector/ui/views/search_view.py +20 -19
  28. vector_inspector/ui/views/visualization_view.py +18 -15
  29. {vector_inspector-0.3.9.dist-info → vector_inspector-0.3.12.dist-info}/METADATA +19 -37
  30. {vector_inspector-0.3.9.dist-info → vector_inspector-0.3.12.dist-info}/RECORD +33 -29
  31. {vector_inspector-0.3.9.dist-info → vector_inspector-0.3.12.dist-info}/WHEEL +1 -1
  32. vector_inspector-0.3.12.dist-info/licenses/LICENSE +1 -0
  33. {vector_inspector-0.3.9.dist-info → vector_inspector-0.3.12.dist-info}/entry_points.txt +0 -0
@@ -1,25 +1,31 @@
1
1
  """Connection manager panel showing multiple active connections."""
2
2
 
3
+ from PySide6.QtCore import Qt, Signal
4
+ from PySide6.QtGui import QIcon
3
5
  from PySide6.QtWidgets import (
4
- QWidget,
5
- QVBoxLayout,
6
- QTreeWidget,
7
- QTreeWidgetItem,
8
- QPushButton,
6
+ QApplication,
7
+ QCheckBox,
8
+ QDialog,
9
+ QDialogButtonBox,
9
10
  QHBoxLayout,
10
- QMenu,
11
- QMessageBox,
12
11
  QInputDialog,
13
12
  QLabel,
13
+ QLineEdit,
14
+ QMenu,
15
+ QMessageBox,
16
+ QPushButton,
17
+ QTreeWidget,
18
+ QTreeWidgetItem,
19
+ QVBoxLayout,
20
+ QWidget,
14
21
  )
15
- from PySide6.QtCore import Qt, Signal
16
- from PySide6.QtGui import QIcon, QColor, QBrush
17
22
 
18
23
  from vector_inspector.core.connection_manager import (
19
24
  ConnectionManager,
20
- ConnectionInstance,
21
25
  ConnectionState,
22
26
  )
27
+ from vector_inspector.services.settings_service import SettingsService
28
+ from vector_inspector.ui.components.loading_dialog import LoadingDialog
23
29
 
24
30
 
25
31
  class ConnectionManagerPanel(QWidget):
@@ -283,6 +289,18 @@ class ConnectionManagerPanel(QWidget):
283
289
  lambda: self._view_collection_info(connection_id, collection_name)
284
290
  )
285
291
 
292
+ menu.addSeparator()
293
+
294
+ delete_action = menu.addAction("Delete Collection...")
295
+ delete_action.triggered.connect(
296
+ lambda: self._delete_collection(connection_id, collection_name)
297
+ )
298
+ # Make delete action red/warning style
299
+ delete_action.setIcon(QIcon()) # Could add warning icon
300
+ font = delete_action.font()
301
+ font.setBold(True)
302
+ delete_action.setFont(font)
303
+
286
304
  menu.exec_(self.connection_tree.mapToGlobal(pos))
287
305
 
288
306
  def _rename_connection(self, connection_id: str):
@@ -305,17 +323,15 @@ class ConnectionManagerPanel(QWidget):
305
323
  def _refresh_collections(self, connection_id: str):
306
324
  """Refresh collections for a connection."""
307
325
  instance = self.connection_manager.get_connection(connection_id)
308
- if not instance or not instance.connection.is_connected:
326
+ if not instance or not instance.is_connected:
309
327
  return
310
328
 
311
329
  # Show loading while refreshing
312
- from vector_inspector.ui.components.loading_dialog import LoadingDialog
313
-
314
330
  loading = LoadingDialog("Refreshing collections...", self)
315
331
  loading.show_loading("Refreshing collections...")
316
332
  QApplication.processEvents()
317
333
  try:
318
- collections = instance.connection.list_collections()
334
+ collections = instance.list_collections()
319
335
  self.connection_manager.update_collections(connection_id, collections)
320
336
  except Exception as e:
321
337
  QMessageBox.warning(self, "Error", f"Failed to refresh collections: {e}")
@@ -344,3 +360,128 @@ class ConnectionManagerPanel(QWidget):
344
360
  # For now, just select it
345
361
  self.connection_manager.set_active_collection(connection_id, collection_name)
346
362
  self.collection_selected.emit(connection_id, collection_name)
363
+
364
+ def _delete_collection(self, connection_id: str, collection_name: str):
365
+ """Delete a collection with strict warning."""
366
+ instance = self.connection_manager.get_connection(connection_id)
367
+ if not instance:
368
+ return
369
+
370
+ # Get collection info for warning
371
+ try:
372
+ col_info = instance.get_collection_info(collection_name)
373
+ item_count = col_info.get("count", 0) if col_info else 0
374
+ except Exception:
375
+ item_count = 0
376
+
377
+ # Create a very strict warning dialog
378
+ dialog = QDialog(self)
379
+ dialog.setWindowTitle("⚠️ DELETE Collection - WARNING")
380
+ dialog.setMinimumWidth(500)
381
+ layout = QVBoxLayout(dialog)
382
+
383
+ # Warning header
384
+ warning_label = QLabel("⚠️ PERMANENT DELETION WARNING ⚠️")
385
+ warning_label.setStyleSheet(
386
+ "font-size: 16px; font-weight: bold; color: #d32f2f; padding: 10px;"
387
+ )
388
+ warning_label.setAlignment(Qt.AlignCenter)
389
+ layout.addWidget(warning_label)
390
+
391
+ # Details
392
+ details_text = (
393
+ f"You are about to PERMANENTLY DELETE the collection:\n\n"
394
+ f"Collection: {collection_name}\n"
395
+ f"Connection: {instance.name}\n"
396
+ f"Items: {item_count:,}\n\n"
397
+ f"⛔ THIS ACTION CANNOT BE UNDONE ⛔\n\n"
398
+ f"All vectors, documents, metadata, and embeddings in this collection\n"
399
+ f"will be PERMANENTLY DELETED from the database.\n\n"
400
+ f"If you have not created a backup, you will LOSE ALL DATA."
401
+ )
402
+ details_label = QLabel(details_text)
403
+ details_label.setWordWrap(True)
404
+ details_label.setStyleSheet("padding: 10px; border-radius: 5px;")
405
+ layout.addWidget(details_label)
406
+
407
+ # Confirmation checkbox
408
+ confirm_checkbox = QCheckBox(
409
+ f"I understand this will PERMANENTLY DELETE '{collection_name}' "
410
+ f"and all {item_count:,} items"
411
+ )
412
+ confirm_checkbox.setStyleSheet("font-weight: bold; color: #d32f2f; padding: 10px;")
413
+ layout.addWidget(confirm_checkbox)
414
+
415
+ # Type collection name to confirm
416
+ type_confirm_label = QLabel(
417
+ f"Type the collection name to confirm: <b>{collection_name}</b>"
418
+ )
419
+ layout.addWidget(type_confirm_label)
420
+
421
+ name_input = QLineEdit()
422
+ name_input.setPlaceholderText(f"Type '{collection_name}' here")
423
+ layout.addWidget(name_input)
424
+
425
+ # Buttons
426
+ button_box = QDialogButtonBox()
427
+ delete_button = button_box.addButton("DELETE PERMANENTLY", QDialogButtonBox.DestructiveRole)
428
+ delete_button.setEnabled(False) # Disabled until confirmed
429
+ delete_button.setStyleSheet(
430
+ "QPushButton { background-color: #d32f2f; color: white; font-weight: bold; "
431
+ "padding: 8px 16px; } "
432
+ "QPushButton:disabled { background-color: #cccccc; }"
433
+ )
434
+ cancel_button = button_box.addButton(QDialogButtonBox.Cancel)
435
+
436
+ # Enable delete button only when both confirmations are met
437
+ def check_confirmations():
438
+ checkbox_ok = confirm_checkbox.isChecked()
439
+ name_ok = name_input.text().strip() == collection_name
440
+ delete_button.setEnabled(checkbox_ok and name_ok)
441
+
442
+ confirm_checkbox.stateChanged.connect(check_confirmations)
443
+ name_input.textChanged.connect(check_confirmations)
444
+
445
+ delete_button.clicked.connect(dialog.accept)
446
+ cancel_button.clicked.connect(dialog.reject)
447
+
448
+ layout.addWidget(button_box)
449
+
450
+ # Show dialog
451
+ if dialog.exec() != QDialog.Accepted:
452
+ return
453
+
454
+ # Perform deletion
455
+ loading = LoadingDialog("Deleting collection...", self)
456
+ loading.show_loading(f"Deleting collection '{collection_name}'...")
457
+ try:
458
+ success = instance.delete_collection(collection_name)
459
+
460
+ if success:
461
+ # Remove embedding model info from settings
462
+ profile_name = instance.name
463
+ SettingsService().remove_embedding_model(profile_name, collection_name)
464
+
465
+ # Refresh collections list
466
+ collections = instance.list_collections()
467
+ self.connection_manager.update_collections(connection_id, collections)
468
+
469
+ # Clear active collection if it was this one
470
+ if instance.active_collection == collection_name:
471
+ self.connection_manager.set_active_collection(connection_id, None)
472
+
473
+ QMessageBox.information(
474
+ self,
475
+ "Collection Deleted",
476
+ f"Collection '{collection_name}' has been permanently deleted.",
477
+ )
478
+ else:
479
+ QMessageBox.warning(
480
+ self, "Deletion Failed", f"Failed to delete collection '{collection_name}'."
481
+ )
482
+ except Exception as e:
483
+ QMessageBox.critical(
484
+ self, "Deletion Error", f"Error deleting collection '{collection_name}': {e}"
485
+ )
486
+ finally:
487
+ loading.hide_loading()