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
|
@@ -4,9 +4,19 @@ from typing import Optional, List, Dict, Any
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
import tempfile
|
|
6
6
|
from PySide6.QtWidgets import (
|
|
7
|
-
QDialog,
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
QDialog,
|
|
8
|
+
QVBoxLayout,
|
|
9
|
+
QHBoxLayout,
|
|
10
|
+
QLabel,
|
|
11
|
+
QComboBox,
|
|
12
|
+
QPushButton,
|
|
13
|
+
QProgressBar,
|
|
14
|
+
QTextEdit,
|
|
15
|
+
QGroupBox,
|
|
16
|
+
QFormLayout,
|
|
17
|
+
QSpinBox,
|
|
18
|
+
QCheckBox,
|
|
19
|
+
QMessageBox,
|
|
10
20
|
)
|
|
11
21
|
from PySide6.QtCore import QThread, Signal
|
|
12
22
|
|
|
@@ -17,17 +27,17 @@ from vector_inspector.core.logging import log_info, log_error
|
|
|
17
27
|
|
|
18
28
|
class MigrationThread(QThread):
|
|
19
29
|
"""Background thread for migrating data between databases using backup/restore."""
|
|
20
|
-
|
|
30
|
+
|
|
21
31
|
progress = Signal(int, str) # progress percentage, status message
|
|
22
32
|
finished = Signal(bool, str) # success, message
|
|
23
|
-
|
|
33
|
+
|
|
24
34
|
def __init__(
|
|
25
35
|
self,
|
|
26
36
|
source_conn: ConnectionInstance,
|
|
27
37
|
target_conn: ConnectionInstance,
|
|
28
38
|
source_collection: str,
|
|
29
39
|
target_collection: str,
|
|
30
|
-
include_embeddings: bool
|
|
40
|
+
include_embeddings: bool,
|
|
31
41
|
):
|
|
32
42
|
super().__init__()
|
|
33
43
|
self.source_conn = source_conn
|
|
@@ -37,11 +47,11 @@ class MigrationThread(QThread):
|
|
|
37
47
|
self.include_embeddings = include_embeddings
|
|
38
48
|
self._cancelled = False
|
|
39
49
|
self.backup_service = BackupRestoreService()
|
|
40
|
-
|
|
50
|
+
|
|
41
51
|
def cancel(self):
|
|
42
52
|
"""Cancel the migration."""
|
|
43
53
|
self._cancelled = True
|
|
44
|
-
|
|
54
|
+
|
|
45
55
|
def run(self):
|
|
46
56
|
"""Run the migration using backup and restore."""
|
|
47
57
|
temp_backup_path = None
|
|
@@ -49,92 +59,106 @@ class MigrationThread(QThread):
|
|
|
49
59
|
if self._cancelled:
|
|
50
60
|
self.finished.emit(False, "Migration cancelled by user.")
|
|
51
61
|
return
|
|
52
|
-
|
|
62
|
+
|
|
53
63
|
# Ensure connections are active
|
|
54
|
-
if not self.source_conn.
|
|
64
|
+
if not self.source_conn.is_connected:
|
|
55
65
|
self.finished.emit(False, "Source connection is not active.")
|
|
56
66
|
return
|
|
57
|
-
|
|
58
|
-
if not self.target_conn.
|
|
67
|
+
|
|
68
|
+
if not self.target_conn.is_connected:
|
|
59
69
|
self.finished.emit(False, "Target connection is not active.")
|
|
60
70
|
return
|
|
61
|
-
|
|
71
|
+
|
|
62
72
|
# Create temporary directory for backup
|
|
63
73
|
temp_dir = tempfile.mkdtemp(prefix="vector_migration_")
|
|
64
|
-
|
|
74
|
+
|
|
65
75
|
# Step 1: Create backup of source collection
|
|
66
76
|
self.progress.emit(10, f"Creating backup of {self.source_collection}...")
|
|
67
|
-
|
|
77
|
+
|
|
68
78
|
temp_backup_path = self.backup_service.backup_collection(
|
|
69
79
|
self.source_conn.connection,
|
|
70
80
|
self.source_collection,
|
|
71
81
|
temp_dir,
|
|
72
|
-
include_embeddings=self.include_embeddings
|
|
82
|
+
include_embeddings=self.include_embeddings,
|
|
83
|
+
connection_id=self.source_conn.id,
|
|
73
84
|
)
|
|
74
|
-
|
|
85
|
+
|
|
75
86
|
if not temp_backup_path:
|
|
76
87
|
self.finished.emit(False, "Failed to create backup.")
|
|
77
88
|
return
|
|
78
|
-
|
|
89
|
+
|
|
79
90
|
if self._cancelled:
|
|
80
91
|
self.finished.emit(False, "Migration cancelled by user.")
|
|
81
92
|
return
|
|
82
|
-
|
|
93
|
+
|
|
83
94
|
# Step 2: Restore to target collection
|
|
84
95
|
self.progress.emit(50, f"Restoring to {self.target_collection}...")
|
|
85
|
-
|
|
96
|
+
|
|
86
97
|
# Verify target connection before restore
|
|
87
|
-
if not self.target_conn.
|
|
98
|
+
if not self.target_conn.is_connected:
|
|
88
99
|
# Try to reconnect
|
|
89
|
-
if not self.target_conn.
|
|
100
|
+
if not self.target_conn.connect():
|
|
90
101
|
self.finished.emit(False, "Target connection lost. Please try again.")
|
|
91
102
|
return
|
|
92
|
-
|
|
103
|
+
|
|
93
104
|
# Check if target collection exists
|
|
94
105
|
target_exists = self.target_collection in self.target_conn.collections
|
|
95
|
-
|
|
106
|
+
|
|
96
107
|
success = self.backup_service.restore_collection(
|
|
97
108
|
self.target_conn.connection,
|
|
98
109
|
temp_backup_path,
|
|
99
110
|
collection_name=self.target_collection,
|
|
100
|
-
overwrite=target_exists
|
|
111
|
+
overwrite=target_exists,
|
|
112
|
+
connection_id=self.target_conn.id,
|
|
101
113
|
)
|
|
102
|
-
|
|
114
|
+
|
|
103
115
|
if self._cancelled:
|
|
104
116
|
self.finished.emit(False, "Migration cancelled by user.")
|
|
105
117
|
return
|
|
106
|
-
|
|
118
|
+
|
|
107
119
|
if success:
|
|
108
120
|
self.progress.emit(100, f"Migration complete!")
|
|
109
|
-
self.finished.emit(
|
|
121
|
+
self.finished.emit(
|
|
122
|
+
True,
|
|
123
|
+
f"Successfully migrated {self.source_collection} to {self.target_collection}",
|
|
124
|
+
)
|
|
110
125
|
else:
|
|
111
126
|
# Clean up target collection on failure
|
|
112
127
|
try:
|
|
113
|
-
if self.target_collection in self.target_conn.
|
|
128
|
+
if self.target_collection in self.target_conn.list_collections():
|
|
114
129
|
self.progress.emit(90, "Cleaning up failed migration...")
|
|
115
|
-
log_info(
|
|
116
|
-
|
|
130
|
+
log_info(
|
|
131
|
+
"Cleaning up failed migration: deleting target collection '%s'",
|
|
132
|
+
self.target_collection,
|
|
133
|
+
)
|
|
134
|
+
self.target_conn.delete_collection(self.target_collection)
|
|
117
135
|
except Exception as cleanup_error:
|
|
118
136
|
log_error("Warning: Failed to clean up target collection: %s", cleanup_error)
|
|
119
|
-
|
|
120
|
-
self.finished.emit(
|
|
121
|
-
|
|
137
|
+
|
|
138
|
+
self.finished.emit(
|
|
139
|
+
False, "Failed to restore to target collection. Target collection cleaned up."
|
|
140
|
+
)
|
|
141
|
+
|
|
122
142
|
except Exception as e:
|
|
123
143
|
import traceback
|
|
144
|
+
|
|
124
145
|
error_details = traceback.format_exc()
|
|
125
146
|
log_error("Migration error details:\n%s", error_details)
|
|
126
|
-
|
|
147
|
+
|
|
127
148
|
# Clean up target collection on exception
|
|
128
149
|
try:
|
|
129
|
-
if self.target_conn and self.target_conn.
|
|
130
|
-
if self.target_collection in self.target_conn.
|
|
131
|
-
log_info(
|
|
132
|
-
|
|
150
|
+
if self.target_conn and self.target_conn.is_connected:
|
|
151
|
+
if self.target_collection in self.target_conn.list_collections():
|
|
152
|
+
log_info(
|
|
153
|
+
"Cleaning up failed migration: deleting target collection '%s'",
|
|
154
|
+
self.target_collection,
|
|
155
|
+
)
|
|
156
|
+
self.target_conn.delete_collection(self.target_collection)
|
|
133
157
|
except Exception as cleanup_error:
|
|
134
|
-
|
|
135
|
-
|
|
158
|
+
log_error("Warning: Failed to clean up target collection: %s", cleanup_error)
|
|
159
|
+
|
|
136
160
|
self.finished.emit(False, f"Migration error: {str(e)}")
|
|
137
|
-
|
|
161
|
+
|
|
138
162
|
finally:
|
|
139
163
|
# Clean up temporary backup file
|
|
140
164
|
if temp_backup_path:
|
|
@@ -150,112 +174,112 @@ class MigrationThread(QThread):
|
|
|
150
174
|
|
|
151
175
|
class CrossDatabaseMigrationDialog(QDialog):
|
|
152
176
|
"""Dialog for migrating data between vector databases."""
|
|
153
|
-
|
|
177
|
+
|
|
154
178
|
def __init__(self, connection_manager: ConnectionManager, parent=None):
|
|
155
179
|
super().__init__(parent)
|
|
156
180
|
self.connection_manager = connection_manager
|
|
157
181
|
self.migration_thread: Optional[MigrationThread] = None
|
|
158
|
-
|
|
182
|
+
|
|
159
183
|
self.setWindowTitle("Cross-Database Migration")
|
|
160
184
|
self.setMinimumWidth(600)
|
|
161
185
|
self.setMinimumHeight(400)
|
|
162
|
-
|
|
186
|
+
|
|
163
187
|
self._setup_ui()
|
|
164
188
|
self._populate_connections()
|
|
165
|
-
|
|
189
|
+
|
|
166
190
|
def _setup_ui(self):
|
|
167
191
|
"""Setup the UI."""
|
|
168
192
|
layout = QVBoxLayout(self)
|
|
169
|
-
|
|
193
|
+
|
|
170
194
|
# Source section
|
|
171
195
|
source_group = QGroupBox("Source")
|
|
172
196
|
source_layout = QFormLayout()
|
|
173
|
-
|
|
197
|
+
|
|
174
198
|
self.source_connection_combo = QComboBox()
|
|
175
199
|
self.source_connection_combo.currentIndexChanged.connect(self._on_source_connection_changed)
|
|
176
200
|
source_layout.addRow("Connection:", self.source_connection_combo)
|
|
177
|
-
|
|
201
|
+
|
|
178
202
|
self.source_collection_combo = QComboBox()
|
|
179
203
|
source_layout.addRow("Collection:", self.source_collection_combo)
|
|
180
|
-
|
|
204
|
+
|
|
181
205
|
source_group.setLayout(source_layout)
|
|
182
206
|
layout.addWidget(source_group)
|
|
183
|
-
|
|
207
|
+
|
|
184
208
|
# Target section
|
|
185
209
|
target_group = QGroupBox("Target")
|
|
186
210
|
target_layout = QFormLayout()
|
|
187
|
-
|
|
211
|
+
|
|
188
212
|
self.target_connection_combo = QComboBox()
|
|
189
213
|
self.target_connection_combo.currentIndexChanged.connect(self._on_target_connection_changed)
|
|
190
214
|
target_layout.addRow("Connection:", self.target_connection_combo)
|
|
191
|
-
|
|
215
|
+
|
|
192
216
|
self.target_collection_combo = QComboBox()
|
|
193
217
|
self.target_collection_combo.setEditable(True)
|
|
194
218
|
target_layout.addRow("Collection:", self.target_collection_combo)
|
|
195
|
-
|
|
219
|
+
|
|
196
220
|
self.create_new_check = QCheckBox("Create new collection if it doesn't exist")
|
|
197
221
|
self.create_new_check.setChecked(True)
|
|
198
222
|
target_layout.addRow("", self.create_new_check)
|
|
199
|
-
|
|
223
|
+
|
|
200
224
|
target_group.setLayout(target_layout)
|
|
201
225
|
layout.addWidget(target_group)
|
|
202
|
-
|
|
226
|
+
|
|
203
227
|
# Options
|
|
204
228
|
options_group = QGroupBox("Options")
|
|
205
229
|
options_layout = QFormLayout()
|
|
206
|
-
|
|
230
|
+
|
|
207
231
|
self.include_embeddings_check = QCheckBox("Include Embeddings")
|
|
208
232
|
self.include_embeddings_check.setChecked(True)
|
|
209
233
|
options_layout.addRow("", self.include_embeddings_check)
|
|
210
|
-
|
|
234
|
+
|
|
211
235
|
options_group.setLayout(options_layout)
|
|
212
236
|
layout.addWidget(options_group)
|
|
213
|
-
|
|
237
|
+
|
|
214
238
|
# Progress section
|
|
215
239
|
self.progress_bar = QProgressBar()
|
|
216
240
|
self.progress_bar.setRange(0, 100)
|
|
217
241
|
self.progress_bar.setValue(0)
|
|
218
242
|
layout.addWidget(self.progress_bar)
|
|
219
|
-
|
|
243
|
+
|
|
220
244
|
self.status_text = QTextEdit()
|
|
221
245
|
self.status_text.setReadOnly(True)
|
|
222
246
|
self.status_text.setMaximumHeight(100)
|
|
223
247
|
layout.addWidget(self.status_text)
|
|
224
|
-
|
|
248
|
+
|
|
225
249
|
# Buttons
|
|
226
250
|
button_layout = QHBoxLayout()
|
|
227
|
-
|
|
251
|
+
|
|
228
252
|
self.start_button = QPushButton("Start Migration")
|
|
229
253
|
self.start_button.clicked.connect(self._start_migration)
|
|
230
254
|
button_layout.addWidget(self.start_button)
|
|
231
|
-
|
|
255
|
+
|
|
232
256
|
self.cancel_button = QPushButton("Cancel")
|
|
233
257
|
self.cancel_button.clicked.connect(self._cancel_migration)
|
|
234
258
|
self.cancel_button.setEnabled(False)
|
|
235
259
|
button_layout.addWidget(self.cancel_button)
|
|
236
|
-
|
|
260
|
+
|
|
237
261
|
self.close_button = QPushButton("Close")
|
|
238
262
|
self.close_button.clicked.connect(self.close)
|
|
239
263
|
button_layout.addWidget(self.close_button)
|
|
240
|
-
|
|
264
|
+
|
|
241
265
|
layout.addLayout(button_layout)
|
|
242
|
-
|
|
266
|
+
|
|
243
267
|
def _populate_connections(self):
|
|
244
268
|
"""Populate connection dropdowns."""
|
|
245
269
|
connections = self.connection_manager.get_all_connections()
|
|
246
|
-
|
|
270
|
+
|
|
247
271
|
self.source_connection_combo.clear()
|
|
248
272
|
self.target_connection_combo.clear()
|
|
249
|
-
|
|
273
|
+
|
|
250
274
|
for conn in connections:
|
|
251
275
|
self.source_connection_combo.addItem(conn.get_display_name(), conn.id)
|
|
252
276
|
self.target_connection_combo.addItem(conn.get_display_name(), conn.id)
|
|
253
|
-
|
|
277
|
+
|
|
254
278
|
# Populate collections for first connection
|
|
255
279
|
if connections:
|
|
256
280
|
self._on_source_connection_changed(0)
|
|
257
281
|
self._on_target_connection_changed(0)
|
|
258
|
-
|
|
282
|
+
|
|
259
283
|
def _on_source_connection_changed(self, index: int):
|
|
260
284
|
"""Handle source connection change."""
|
|
261
285
|
connection_id = self.source_connection_combo.currentData()
|
|
@@ -264,7 +288,7 @@ class CrossDatabaseMigrationDialog(QDialog):
|
|
|
264
288
|
if instance:
|
|
265
289
|
self.source_collection_combo.clear()
|
|
266
290
|
self.source_collection_combo.addItems(instance.collections)
|
|
267
|
-
|
|
291
|
+
|
|
268
292
|
def _on_target_connection_changed(self, index: int):
|
|
269
293
|
"""Handle target connection change."""
|
|
270
294
|
connection_id = self.target_connection_combo.currentData()
|
|
@@ -273,17 +297,19 @@ class CrossDatabaseMigrationDialog(QDialog):
|
|
|
273
297
|
if instance:
|
|
274
298
|
self.target_collection_combo.clear()
|
|
275
299
|
self.target_collection_combo.addItems(instance.collections)
|
|
276
|
-
|
|
300
|
+
|
|
277
301
|
def _start_migration(self):
|
|
278
302
|
"""Start the migration."""
|
|
279
303
|
# Validate selection
|
|
280
304
|
source_conn_id = self.source_connection_combo.currentData()
|
|
281
305
|
target_conn_id = self.target_connection_combo.currentData()
|
|
282
|
-
|
|
306
|
+
|
|
283
307
|
if not source_conn_id or not target_conn_id:
|
|
284
|
-
QMessageBox.warning(
|
|
308
|
+
QMessageBox.warning(
|
|
309
|
+
self, "Invalid Selection", "Please select both source and target connections."
|
|
310
|
+
)
|
|
285
311
|
return
|
|
286
|
-
|
|
312
|
+
|
|
287
313
|
if source_conn_id == target_conn_id:
|
|
288
314
|
source_coll = self.source_collection_combo.currentText()
|
|
289
315
|
target_coll = self.target_collection_combo.currentText()
|
|
@@ -291,37 +317,39 @@ class CrossDatabaseMigrationDialog(QDialog):
|
|
|
291
317
|
QMessageBox.warning(
|
|
292
318
|
self,
|
|
293
319
|
"Invalid Selection",
|
|
294
|
-
"Source and target cannot be the same collection in the same connection."
|
|
320
|
+
"Source and target cannot be the same collection in the same connection.",
|
|
295
321
|
)
|
|
296
322
|
return
|
|
297
|
-
|
|
323
|
+
|
|
298
324
|
source_conn = self.connection_manager.get_connection(source_conn_id)
|
|
299
325
|
target_conn = self.connection_manager.get_connection(target_conn_id)
|
|
300
|
-
|
|
326
|
+
|
|
301
327
|
if not source_conn or not target_conn:
|
|
302
328
|
QMessageBox.warning(self, "Error", "Failed to get connection instances.")
|
|
303
329
|
return
|
|
304
|
-
|
|
330
|
+
|
|
305
331
|
source_collection = self.source_collection_combo.currentText()
|
|
306
332
|
target_collection = self.target_collection_combo.currentText().strip()
|
|
307
|
-
|
|
333
|
+
|
|
308
334
|
if not source_collection or not target_collection:
|
|
309
|
-
QMessageBox.warning(
|
|
335
|
+
QMessageBox.warning(
|
|
336
|
+
self, "Invalid Selection", "Please select both source and target collections."
|
|
337
|
+
)
|
|
310
338
|
return
|
|
311
|
-
|
|
339
|
+
|
|
312
340
|
# Check if target collection exists
|
|
313
341
|
target_exists = target_collection in target_conn.collections
|
|
314
|
-
|
|
342
|
+
|
|
315
343
|
# If target doesn't exist and we're not set to create, warn user
|
|
316
344
|
if not target_exists and not self.create_new_check.isChecked():
|
|
317
345
|
QMessageBox.warning(
|
|
318
346
|
self,
|
|
319
347
|
"Collection Does Not Exist",
|
|
320
348
|
f"Target collection '{target_collection}' does not exist.\n"
|
|
321
|
-
"Please check 'Create new collection' to allow automatic creation during migration."
|
|
349
|
+
"Please check 'Create new collection' to allow automatic creation during migration.",
|
|
322
350
|
)
|
|
323
351
|
return
|
|
324
|
-
|
|
352
|
+
|
|
325
353
|
# Confirm
|
|
326
354
|
action = "create and migrate" if not target_exists else "migrate"
|
|
327
355
|
reply = QMessageBox.question(
|
|
@@ -330,55 +358,54 @@ class CrossDatabaseMigrationDialog(QDialog):
|
|
|
330
358
|
f"Migrate data from:\n {source_conn.name}/{source_collection}\n"
|
|
331
359
|
f"to:\n {target_conn.name}/{target_collection}\n\n"
|
|
332
360
|
f"This will {action} all data. Continue?",
|
|
333
|
-
QMessageBox.Yes | QMessageBox.No
|
|
361
|
+
QMessageBox.Yes | QMessageBox.No,
|
|
334
362
|
)
|
|
335
|
-
|
|
363
|
+
|
|
336
364
|
if reply != QMessageBox.Yes:
|
|
337
365
|
return
|
|
338
|
-
|
|
366
|
+
|
|
339
367
|
# Start migration thread
|
|
340
368
|
self.migration_thread = MigrationThread(
|
|
341
369
|
source_conn=source_conn,
|
|
342
370
|
target_conn=target_conn,
|
|
343
371
|
source_collection=source_collection,
|
|
344
372
|
target_collection=target_collection,
|
|
345
|
-
include_embeddings=self.include_embeddings_check.isChecked()
|
|
373
|
+
include_embeddings=self.include_embeddings_check.isChecked(),
|
|
346
374
|
)
|
|
347
|
-
|
|
375
|
+
|
|
348
376
|
self.migration_thread.progress.connect(self._on_migration_progress)
|
|
349
377
|
self.migration_thread.finished.connect(self._on_migration_finished)
|
|
350
|
-
|
|
378
|
+
|
|
351
379
|
self.start_button.setEnabled(False)
|
|
352
380
|
self.cancel_button.setEnabled(True)
|
|
353
381
|
self.close_button.setEnabled(False)
|
|
354
|
-
|
|
382
|
+
|
|
355
383
|
self.status_text.clear()
|
|
356
384
|
self.progress_bar.setValue(0)
|
|
357
|
-
|
|
385
|
+
|
|
358
386
|
self.migration_thread.start()
|
|
359
|
-
|
|
387
|
+
|
|
360
388
|
def _cancel_migration(self):
|
|
361
389
|
"""Cancel the migration."""
|
|
362
390
|
if self.migration_thread:
|
|
363
391
|
self.migration_thread.cancel()
|
|
364
392
|
self.status_text.append("Cancelling migration...")
|
|
365
|
-
|
|
393
|
+
|
|
366
394
|
def _on_migration_progress(self, progress: int, message: str):
|
|
367
395
|
"""Handle migration progress update."""
|
|
368
396
|
self.progress_bar.setValue(progress)
|
|
369
397
|
self.status_text.append(message)
|
|
370
|
-
|
|
398
|
+
|
|
371
399
|
def _on_migration_finished(self, success: bool, message: str):
|
|
372
400
|
"""Handle migration completion."""
|
|
373
401
|
self.status_text.append(message)
|
|
374
|
-
|
|
402
|
+
|
|
375
403
|
if success:
|
|
376
404
|
QMessageBox.information(self, "Success", message)
|
|
377
405
|
else:
|
|
378
406
|
QMessageBox.warning(self, "Failed", message)
|
|
379
|
-
|
|
407
|
+
|
|
380
408
|
self.start_button.setEnabled(True)
|
|
381
409
|
self.cancel_button.setEnabled(False)
|
|
382
410
|
self.close_button.setEnabled(True)
|
|
383
411
|
self.migration_thread = None
|
|
384
|
-
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
from PySide6.QtWidgets import (
|
|
2
|
+
QCheckBox,
|
|
2
3
|
QDialog,
|
|
3
|
-
QVBoxLayout,
|
|
4
4
|
QHBoxLayout,
|
|
5
5
|
QLabel,
|
|
6
|
-
QCheckBox,
|
|
7
|
-
QComboBox,
|
|
8
|
-
QSpinBox,
|
|
9
6
|
QPushButton,
|
|
7
|
+
QSpinBox,
|
|
8
|
+
QVBoxLayout,
|
|
10
9
|
)
|
|
11
|
-
from PySide6.QtCore import Qt
|
|
12
10
|
|
|
13
|
-
from vector_inspector.services.settings_service import SettingsService
|
|
14
11
|
from vector_inspector.extensions import settings_panel_hook
|
|
12
|
+
from vector_inspector.services.settings_service import SettingsService
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
class SettingsDialog(QDialog):
|
|
@@ -47,6 +45,10 @@ class SettingsDialog(QDialog):
|
|
|
47
45
|
self.restore_geometry_checkbox = QCheckBox("Restore window size/position on startup")
|
|
48
46
|
layout.addWidget(self.restore_geometry_checkbox)
|
|
49
47
|
|
|
48
|
+
# Loading screen
|
|
49
|
+
self.hide_splash_checkbox = QCheckBox("Hide loading screen on startup")
|
|
50
|
+
layout.addWidget(self.hide_splash_checkbox)
|
|
51
|
+
|
|
50
52
|
# Buttons
|
|
51
53
|
btn_layout = QHBoxLayout()
|
|
52
54
|
self.apply_btn = QPushButton("Apply")
|
|
@@ -81,6 +83,9 @@ class SettingsDialog(QDialog):
|
|
|
81
83
|
self.restore_geometry_checkbox.stateChanged.connect(
|
|
82
84
|
lambda s: self.settings.set_window_restore_geometry(bool(s))
|
|
83
85
|
)
|
|
86
|
+
self.hide_splash_checkbox.stateChanged.connect(
|
|
87
|
+
lambda s: self.settings.set("hide_loading_screen", bool(s))
|
|
88
|
+
)
|
|
84
89
|
|
|
85
90
|
# Container for programmatic sections
|
|
86
91
|
self._extra_sections = []
|
|
@@ -107,6 +112,7 @@ class SettingsDialog(QDialog):
|
|
|
107
112
|
self.default_results.setValue(self.settings.get_default_n_results())
|
|
108
113
|
self.auto_embed_checkbox.setChecked(self.settings.get_auto_generate_embeddings())
|
|
109
114
|
self.restore_geometry_checkbox.setChecked(self.settings.get_window_restore_geometry())
|
|
115
|
+
self.hide_splash_checkbox.setChecked(self.settings.get("hide_loading_screen", False))
|
|
110
116
|
|
|
111
117
|
def _apply(self):
|
|
112
118
|
# Values are already applied on change; ensure persistence and close
|
|
@@ -121,4 +127,5 @@ class SettingsDialog(QDialog):
|
|
|
121
127
|
self.default_results.setValue(10)
|
|
122
128
|
self.auto_embed_checkbox.setChecked(True)
|
|
123
129
|
self.restore_geometry_checkbox.setChecked(True)
|
|
130
|
+
self.hide_splash_checkbox.setChecked(False)
|
|
124
131
|
self._apply()
|