vector-inspector 0.3.11__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.
- vector_inspector/__init__.py +1 -1
- vector_inspector/core/connection_manager.py +91 -19
- vector_inspector/core/connections/base_connection.py +43 -43
- vector_inspector/core/connections/chroma_connection.py +1 -1
- vector_inspector/core/connections/pgvector_connection.py +11 -171
- vector_inspector/core/connections/pinecone_connection.py +596 -99
- vector_inspector/core/connections/qdrant_connection.py +35 -44
- vector_inspector/core/embedding_utils.py +14 -5
- vector_inspector/core/logging.py +3 -1
- vector_inspector/main.py +42 -15
- vector_inspector/services/backup_restore_service.py +228 -15
- vector_inspector/services/settings_service.py +71 -19
- vector_inspector/ui/components/backup_restore_dialog.py +215 -101
- vector_inspector/ui/components/connection_manager_panel.py +155 -14
- vector_inspector/ui/dialogs/cross_db_migration.py +126 -99
- vector_inspector/ui/dialogs/settings_dialog.py +13 -6
- vector_inspector/ui/loading_screen.py +169 -0
- vector_inspector/ui/main_window.py +44 -19
- vector_inspector/ui/services/dialog_service.py +1 -0
- vector_inspector/ui/views/collection_browser.py +36 -34
- vector_inspector/ui/views/connection_view.py +7 -1
- vector_inspector/ui/views/info_panel.py +118 -52
- vector_inspector/ui/views/metadata_view.py +30 -31
- vector_inspector/ui/views/search_view.py +20 -19
- vector_inspector/ui/views/visualization_view.py +18 -15
- {vector_inspector-0.3.11.dist-info → vector_inspector-0.3.12.dist-info}/METADATA +17 -4
- {vector_inspector-0.3.11.dist-info → vector_inspector-0.3.12.dist-info}/RECORD +30 -28
- vector_inspector-0.3.12.dist-info/licenses/LICENSE +1 -0
- {vector_inspector-0.3.11.dist-info → vector_inspector-0.3.12.dist-info}/WHEEL +0 -0
- {vector_inspector-0.3.11.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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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.
|
|
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.
|
|
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()
|