vector-inspector 0.3.4__py3-none-any.whl → 0.3.5__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/core/connections/base_connection.py +86 -1
- vector_inspector/core/connections/chroma_connection.py +23 -3
- vector_inspector/core/connections/pgvector_connection.py +1100 -0
- vector_inspector/core/connections/pinecone_connection.py +24 -4
- vector_inspector/core/connections/qdrant_connection.py +224 -189
- vector_inspector/core/embedding_providers/provider_factory.py +33 -38
- vector_inspector/core/embedding_utils.py +2 -2
- vector_inspector/services/backup_restore_service.py +41 -33
- vector_inspector/ui/components/connection_manager_panel.py +96 -77
- vector_inspector/ui/components/profile_manager_panel.py +315 -121
- vector_inspector/ui/dialogs/embedding_config_dialog.py +79 -58
- vector_inspector/ui/main_window.py +22 -0
- vector_inspector/ui/views/connection_view.py +215 -116
- vector_inspector/ui/views/info_panel.py +6 -6
- vector_inspector/ui/views/metadata_view.py +466 -187
- {vector_inspector-0.3.4.dist-info → vector_inspector-0.3.5.dist-info}/METADATA +4 -3
- {vector_inspector-0.3.4.dist-info → vector_inspector-0.3.5.dist-info}/RECORD +19 -18
- {vector_inspector-0.3.4.dist-info → vector_inspector-0.3.5.dist-info}/WHEEL +0 -0
- {vector_inspector-0.3.4.dist-info → vector_inspector-0.3.5.dist-info}/entry_points.txt +0 -0
|
@@ -1,30 +1,42 @@
|
|
|
1
1
|
"""Connection manager panel showing multiple active connections."""
|
|
2
2
|
|
|
3
3
|
from PySide6.QtWidgets import (
|
|
4
|
-
QWidget,
|
|
5
|
-
|
|
4
|
+
QWidget,
|
|
5
|
+
QVBoxLayout,
|
|
6
|
+
QTreeWidget,
|
|
7
|
+
QTreeWidgetItem,
|
|
8
|
+
QPushButton,
|
|
9
|
+
QHBoxLayout,
|
|
10
|
+
QMenu,
|
|
11
|
+
QMessageBox,
|
|
12
|
+
QInputDialog,
|
|
13
|
+
QLabel,
|
|
6
14
|
)
|
|
7
15
|
from PySide6.QtCore import Qt, Signal
|
|
8
16
|
from PySide6.QtGui import QIcon, QColor, QBrush
|
|
9
17
|
|
|
10
|
-
from vector_inspector.core.connection_manager import
|
|
18
|
+
from vector_inspector.core.connection_manager import (
|
|
19
|
+
ConnectionManager,
|
|
20
|
+
ConnectionInstance,
|
|
21
|
+
ConnectionState,
|
|
22
|
+
)
|
|
11
23
|
|
|
12
24
|
|
|
13
25
|
class ConnectionManagerPanel(QWidget):
|
|
14
26
|
"""Panel for managing multiple database connections.
|
|
15
|
-
|
|
27
|
+
|
|
16
28
|
Signals:
|
|
17
29
|
connection_selected: Emitted when a connection is clicked (connection_id)
|
|
18
30
|
collection_selected: Emitted when a collection is clicked (connection_id, collection_name)
|
|
19
31
|
"""
|
|
20
|
-
|
|
32
|
+
|
|
21
33
|
connection_selected = Signal(str) # connection_id
|
|
22
34
|
collection_selected = Signal(str, str) # connection_id, collection_name
|
|
23
|
-
|
|
35
|
+
|
|
24
36
|
def __init__(self, connection_manager: ConnectionManager, parent=None):
|
|
25
37
|
"""
|
|
26
38
|
Initialize connection manager panel.
|
|
27
|
-
|
|
39
|
+
|
|
28
40
|
Args:
|
|
29
41
|
connection_manager: The ConnectionManager instance
|
|
30
42
|
parent: Parent widget
|
|
@@ -32,30 +44,30 @@ class ConnectionManagerPanel(QWidget):
|
|
|
32
44
|
super().__init__(parent)
|
|
33
45
|
self.connection_manager = connection_manager
|
|
34
46
|
self._connection_items = {} # Map connection_id to tree item
|
|
35
|
-
|
|
47
|
+
|
|
36
48
|
self._setup_ui()
|
|
37
49
|
self._connect_signals()
|
|
38
|
-
|
|
50
|
+
|
|
39
51
|
def _setup_ui(self):
|
|
40
52
|
"""Setup the UI."""
|
|
41
53
|
layout = QVBoxLayout(self)
|
|
42
54
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
43
|
-
|
|
55
|
+
|
|
44
56
|
# Header
|
|
45
57
|
header_layout = QHBoxLayout()
|
|
46
58
|
header_label = QLabel("Connections")
|
|
47
59
|
header_label.setStyleSheet("font-weight: bold; font-size: 12px;")
|
|
48
60
|
header_layout.addWidget(header_label)
|
|
49
61
|
header_layout.addStretch()
|
|
50
|
-
|
|
62
|
+
|
|
51
63
|
# Add connection button
|
|
52
64
|
self.add_connection_btn = QPushButton("+")
|
|
53
65
|
self.add_connection_btn.setMaximumWidth(30)
|
|
54
66
|
self.add_connection_btn.setToolTip("Add new connection")
|
|
55
67
|
header_layout.addWidget(self.add_connection_btn)
|
|
56
|
-
|
|
68
|
+
|
|
57
69
|
layout.addLayout(header_layout)
|
|
58
|
-
|
|
70
|
+
|
|
59
71
|
# Connection tree
|
|
60
72
|
self.connection_tree = QTreeWidget()
|
|
61
73
|
self.connection_tree.setHeaderHidden(True)
|
|
@@ -64,50 +76,54 @@ class ConnectionManagerPanel(QWidget):
|
|
|
64
76
|
self.connection_tree.itemClicked.connect(self._on_item_clicked)
|
|
65
77
|
self.connection_tree.itemExpanded.connect(self._on_item_expanded)
|
|
66
78
|
# Match QListWidget selection style - use subtle highlight
|
|
67
|
-
self.connection_tree.setStyleSheet(
|
|
79
|
+
self.connection_tree.setStyleSheet("""
|
|
68
80
|
QTreeWidget::item:selected {
|
|
69
81
|
background: palette(highlight);
|
|
70
82
|
color: palette(highlighted-text);
|
|
71
83
|
}
|
|
72
|
-
|
|
84
|
+
""")
|
|
73
85
|
layout.addWidget(self.connection_tree)
|
|
74
|
-
|
|
86
|
+
|
|
75
87
|
def _connect_signals(self):
|
|
76
88
|
"""Connect to connection manager signals."""
|
|
77
89
|
self.connection_manager.connection_opened.connect(self._on_connection_opened)
|
|
78
90
|
self.connection_manager.connection_closed.connect(self._on_connection_closed)
|
|
79
91
|
self.connection_manager.connection_state_changed.connect(self._on_connection_state_changed)
|
|
80
|
-
self.connection_manager.active_connection_changed.connect(
|
|
81
|
-
|
|
92
|
+
self.connection_manager.active_connection_changed.connect(
|
|
93
|
+
self._on_active_connection_changed
|
|
94
|
+
)
|
|
95
|
+
self.connection_manager.active_collection_changed.connect(
|
|
96
|
+
self._on_active_collection_changed
|
|
97
|
+
)
|
|
82
98
|
self.connection_manager.collections_updated.connect(self._on_collections_updated)
|
|
83
|
-
|
|
99
|
+
|
|
84
100
|
def _on_connection_opened(self, connection_id: str):
|
|
85
101
|
"""Handle new connection opened (after successful connection)."""
|
|
86
102
|
instance = self.connection_manager.get_connection(connection_id)
|
|
87
103
|
if not instance:
|
|
88
104
|
return
|
|
89
|
-
|
|
105
|
+
|
|
90
106
|
# Only show if not already shown
|
|
91
107
|
if connection_id in self._connection_items:
|
|
92
108
|
return
|
|
93
|
-
|
|
109
|
+
|
|
94
110
|
# Create tree item for connection
|
|
95
111
|
item = QTreeWidgetItem(self.connection_tree)
|
|
96
112
|
item.setText(0, instance.get_display_name())
|
|
97
113
|
item.setData(0, Qt.UserRole, {"type": "connection", "connection_id": connection_id})
|
|
98
|
-
|
|
114
|
+
|
|
99
115
|
# Set icon/indicator based on state
|
|
100
116
|
self._update_connection_indicator(item, instance.state)
|
|
101
|
-
|
|
117
|
+
|
|
102
118
|
self._connection_items[connection_id] = item
|
|
103
|
-
|
|
119
|
+
|
|
104
120
|
# Expand by default to show collections
|
|
105
121
|
item.setExpanded(True)
|
|
106
|
-
|
|
122
|
+
|
|
107
123
|
# Select if active
|
|
108
124
|
if self.connection_manager.get_active_connection_id() == connection_id:
|
|
109
125
|
self.connection_tree.setCurrentItem(item)
|
|
110
|
-
|
|
126
|
+
|
|
111
127
|
def _on_connection_closed(self, connection_id: str):
|
|
112
128
|
"""Handle connection closed."""
|
|
113
129
|
item = self._connection_items.pop(connection_id, None)
|
|
@@ -115,13 +131,13 @@ class ConnectionManagerPanel(QWidget):
|
|
|
115
131
|
index = self.connection_tree.indexOfTopLevelItem(item)
|
|
116
132
|
if index >= 0:
|
|
117
133
|
self.connection_tree.takeTopLevelItem(index)
|
|
118
|
-
|
|
134
|
+
|
|
119
135
|
def _on_connection_state_changed(self, connection_id: str, state: ConnectionState):
|
|
120
136
|
"""Handle connection state change."""
|
|
121
137
|
item = self._connection_items.get(connection_id)
|
|
122
138
|
if item:
|
|
123
139
|
self._update_connection_indicator(item, state)
|
|
124
|
-
|
|
140
|
+
|
|
125
141
|
def _on_active_connection_changed(self, connection_id):
|
|
126
142
|
"""Handle active connection change."""
|
|
127
143
|
# Select the active connection item in the tree
|
|
@@ -129,13 +145,13 @@ class ConnectionManagerPanel(QWidget):
|
|
|
129
145
|
item = self._connection_items.get(connection_id)
|
|
130
146
|
if item:
|
|
131
147
|
self.connection_tree.setCurrentItem(item)
|
|
132
|
-
|
|
148
|
+
|
|
133
149
|
def _on_active_collection_changed(self, connection_id: str, collection_name):
|
|
134
150
|
"""Handle active collection change."""
|
|
135
151
|
item = self._connection_items.get(connection_id)
|
|
136
152
|
if not item:
|
|
137
153
|
return
|
|
138
|
-
|
|
154
|
+
|
|
139
155
|
# Select the active collection in the tree
|
|
140
156
|
if collection_name:
|
|
141
157
|
for i in range(item.childCount()):
|
|
@@ -144,27 +160,31 @@ class ConnectionManagerPanel(QWidget):
|
|
|
144
160
|
if data and data.get("collection_name") == collection_name:
|
|
145
161
|
self.connection_tree.setCurrentItem(child)
|
|
146
162
|
break
|
|
147
|
-
|
|
163
|
+
|
|
148
164
|
def _on_collections_updated(self, connection_id: str, collections: list):
|
|
149
165
|
"""Handle collections list updated."""
|
|
150
166
|
item = self._connection_items.get(connection_id)
|
|
151
167
|
if not item:
|
|
152
168
|
return
|
|
153
|
-
|
|
169
|
+
|
|
154
170
|
# Remove existing collection items
|
|
155
171
|
while item.childCount() > 0:
|
|
156
172
|
item.removeChild(item.child(0))
|
|
157
|
-
|
|
173
|
+
|
|
158
174
|
# Add new collection items
|
|
159
175
|
for collection_name in collections:
|
|
160
176
|
child = QTreeWidgetItem(item)
|
|
161
177
|
child.setText(0, collection_name)
|
|
162
|
-
child.setData(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
child.setData(
|
|
179
|
+
0,
|
|
180
|
+
Qt.UserRole,
|
|
181
|
+
{
|
|
182
|
+
"type": "collection",
|
|
183
|
+
"connection_id": connection_id,
|
|
184
|
+
"collection_name": collection_name,
|
|
185
|
+
},
|
|
186
|
+
)
|
|
187
|
+
|
|
168
188
|
def _update_connection_indicator(self, item: QTreeWidgetItem, state: ConnectionState):
|
|
169
189
|
"""Update visual indicator for connection state."""
|
|
170
190
|
if state == ConnectionState.CONNECTED:
|
|
@@ -175,23 +195,23 @@ class ConnectionManagerPanel(QWidget):
|
|
|
175
195
|
indicator = "🔴"
|
|
176
196
|
else:
|
|
177
197
|
indicator = "⚪"
|
|
178
|
-
|
|
198
|
+
|
|
179
199
|
data = item.data(0, Qt.UserRole)
|
|
180
200
|
connection_id = data.get("connection_id")
|
|
181
201
|
instance = self.connection_manager.get_connection(connection_id)
|
|
182
|
-
|
|
202
|
+
|
|
183
203
|
if instance:
|
|
184
204
|
item.setText(0, f"{indicator} {instance.get_display_name()}")
|
|
185
|
-
|
|
205
|
+
|
|
186
206
|
def _on_item_clicked(self, item: QTreeWidgetItem, column: int):
|
|
187
207
|
"""Handle tree item click."""
|
|
188
208
|
data = item.data(0, Qt.UserRole)
|
|
189
209
|
if not data:
|
|
190
210
|
return
|
|
191
|
-
|
|
211
|
+
|
|
192
212
|
item_type = data.get("type")
|
|
193
213
|
connection_id = data.get("connection_id")
|
|
194
|
-
|
|
214
|
+
|
|
195
215
|
if item_type == "connection":
|
|
196
216
|
# Set as active connection
|
|
197
217
|
self.connection_manager.set_active_connection(connection_id)
|
|
@@ -200,97 +220,97 @@ class ConnectionManagerPanel(QWidget):
|
|
|
200
220
|
# Set active connection first (if different)
|
|
201
221
|
if connection_id != self.connection_manager.get_active_connection_id():
|
|
202
222
|
self.connection_manager.set_active_connection(connection_id)
|
|
203
|
-
|
|
223
|
+
|
|
204
224
|
# Then set as active collection
|
|
205
225
|
collection_name = data.get("collection_name")
|
|
206
226
|
self.connection_manager.set_active_collection(connection_id, collection_name)
|
|
207
227
|
self.collection_selected.emit(connection_id, collection_name)
|
|
208
|
-
|
|
228
|
+
|
|
209
229
|
def _on_item_expanded(self, item: QTreeWidgetItem):
|
|
210
230
|
"""Handle tree item expansion."""
|
|
211
231
|
# Could trigger lazy loading of collections here if needed
|
|
212
232
|
pass
|
|
213
|
-
|
|
233
|
+
|
|
214
234
|
def _show_context_menu(self, pos):
|
|
215
235
|
"""Show context menu for connection/collection."""
|
|
216
236
|
item = self.connection_tree.itemAt(pos)
|
|
217
237
|
if not item:
|
|
218
238
|
return
|
|
219
|
-
|
|
239
|
+
|
|
220
240
|
data = item.data(0, Qt.UserRole)
|
|
221
241
|
if not data:
|
|
222
242
|
return
|
|
223
|
-
|
|
243
|
+
|
|
224
244
|
menu = QMenu(self)
|
|
225
245
|
item_type = data.get("type")
|
|
226
246
|
connection_id = data.get("connection_id")
|
|
227
|
-
|
|
247
|
+
|
|
228
248
|
if item_type == "connection":
|
|
229
249
|
# Connection context menu
|
|
230
250
|
set_active_action = menu.addAction("Set as Active")
|
|
231
251
|
set_active_action.triggered.connect(
|
|
232
252
|
lambda: self.connection_manager.set_active_connection(connection_id)
|
|
233
253
|
)
|
|
234
|
-
|
|
254
|
+
|
|
235
255
|
menu.addSeparator()
|
|
236
|
-
|
|
256
|
+
|
|
237
257
|
rename_action = menu.addAction("Rename...")
|
|
238
258
|
rename_action.triggered.connect(lambda: self._rename_connection(connection_id))
|
|
239
|
-
|
|
259
|
+
|
|
240
260
|
refresh_action = menu.addAction("Refresh Collections")
|
|
241
261
|
refresh_action.triggered.connect(lambda: self._refresh_collections(connection_id))
|
|
242
|
-
|
|
262
|
+
|
|
243
263
|
menu.addSeparator()
|
|
244
|
-
|
|
264
|
+
|
|
245
265
|
disconnect_action = menu.addAction("Disconnect")
|
|
246
266
|
disconnect_action.triggered.connect(lambda: self._disconnect_connection(connection_id))
|
|
247
|
-
|
|
267
|
+
|
|
248
268
|
elif item_type == "collection":
|
|
249
269
|
# Collection context menu
|
|
250
270
|
collection_name = data.get("collection_name")
|
|
251
|
-
|
|
271
|
+
|
|
252
272
|
select_action = menu.addAction("Select Collection")
|
|
253
273
|
select_action.triggered.connect(
|
|
254
|
-
lambda: self.connection_manager.set_active_collection(
|
|
274
|
+
lambda: self.connection_manager.set_active_collection(
|
|
275
|
+
connection_id, collection_name
|
|
276
|
+
)
|
|
255
277
|
)
|
|
256
|
-
|
|
278
|
+
|
|
257
279
|
menu.addSeparator()
|
|
258
|
-
|
|
280
|
+
|
|
259
281
|
info_action = menu.addAction("View Info")
|
|
260
282
|
info_action.triggered.connect(
|
|
261
283
|
lambda: self._view_collection_info(connection_id, collection_name)
|
|
262
284
|
)
|
|
263
|
-
|
|
285
|
+
|
|
264
286
|
menu.exec_(self.connection_tree.mapToGlobal(pos))
|
|
265
|
-
|
|
287
|
+
|
|
266
288
|
def _rename_connection(self, connection_id: str):
|
|
267
289
|
"""Rename a connection."""
|
|
268
290
|
instance = self.connection_manager.get_connection(connection_id)
|
|
269
291
|
if not instance:
|
|
270
292
|
return
|
|
271
|
-
|
|
293
|
+
|
|
272
294
|
new_name, ok = QInputDialog.getText(
|
|
273
|
-
self,
|
|
274
|
-
"Rename Connection",
|
|
275
|
-
"Enter new name:",
|
|
276
|
-
text=instance.name
|
|
295
|
+
self, "Rename Connection", "Enter new name:", text=instance.name
|
|
277
296
|
)
|
|
278
|
-
|
|
297
|
+
|
|
279
298
|
if ok and new_name:
|
|
280
299
|
if self.connection_manager.rename_connection(connection_id, new_name):
|
|
281
300
|
# Update tree item
|
|
282
301
|
item = self._connection_items.get(connection_id)
|
|
283
302
|
if item:
|
|
284
303
|
self._update_connection_indicator(item, instance.state)
|
|
285
|
-
|
|
304
|
+
|
|
286
305
|
def _refresh_collections(self, connection_id: str):
|
|
287
306
|
"""Refresh collections for a connection."""
|
|
288
307
|
instance = self.connection_manager.get_connection(connection_id)
|
|
289
308
|
if not instance or not instance.connection.is_connected:
|
|
290
309
|
return
|
|
291
|
-
|
|
310
|
+
|
|
292
311
|
# Show loading while refreshing
|
|
293
|
-
from
|
|
312
|
+
from vector_inspector.ui.components.loading_dialog import LoadingDialog
|
|
313
|
+
|
|
294
314
|
loading = LoadingDialog("Refreshing collections...", self)
|
|
295
315
|
loading.show_loading("Refreshing collections...")
|
|
296
316
|
QApplication.processEvents()
|
|
@@ -301,27 +321,26 @@ class ConnectionManagerPanel(QWidget):
|
|
|
301
321
|
QMessageBox.warning(self, "Error", f"Failed to refresh collections: {e}")
|
|
302
322
|
finally:
|
|
303
323
|
loading.hide_loading()
|
|
304
|
-
|
|
324
|
+
|
|
305
325
|
def _disconnect_connection(self, connection_id: str):
|
|
306
326
|
"""Disconnect a connection."""
|
|
307
327
|
instance = self.connection_manager.get_connection(connection_id)
|
|
308
328
|
if not instance:
|
|
309
329
|
return
|
|
310
|
-
|
|
330
|
+
|
|
311
331
|
reply = QMessageBox.question(
|
|
312
332
|
self,
|
|
313
333
|
"Disconnect",
|
|
314
334
|
f"Disconnect from '{instance.name}'?",
|
|
315
|
-
QMessageBox.Yes | QMessageBox.No
|
|
335
|
+
QMessageBox.Yes | QMessageBox.No,
|
|
316
336
|
)
|
|
317
|
-
|
|
337
|
+
|
|
318
338
|
if reply == QMessageBox.Yes:
|
|
319
339
|
self.connection_manager.close_connection(connection_id)
|
|
320
|
-
|
|
340
|
+
|
|
321
341
|
def _view_collection_info(self, connection_id: str, collection_name: str):
|
|
322
342
|
"""View collection info."""
|
|
323
343
|
# This would trigger showing collection details
|
|
324
344
|
# For now, just select it
|
|
325
345
|
self.connection_manager.set_active_collection(connection_id, collection_name)
|
|
326
346
|
self.collection_selected.emit(connection_id, collection_name)
|
|
327
|
-
|