vector-inspector 0.3.7__tar.gz → 0.3.8__tar.gz
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-0.3.7 → vector_inspector-0.3.8}/PKG-INFO +27 -9
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/README.md +26 -8
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/pyproject.toml +1 -1
- vector_inspector-0.3.8/src/vector_inspector/core/provider_factory.py +97 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/splash_window.py +14 -2
- vector_inspector-0.3.8/src/vector_inspector/ui/controllers/__init__.py +1 -0
- vector_inspector-0.3.8/src/vector_inspector/ui/controllers/connection_controller.py +177 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/main_window.py +85 -332
- vector_inspector-0.3.8/src/vector_inspector/ui/main_window_shell.py +106 -0
- vector_inspector-0.3.8/src/vector_inspector/ui/services/__init__.py +1 -0
- vector_inspector-0.3.8/src/vector_inspector/ui/services/dialog_service.py +113 -0
- vector_inspector-0.3.8/src/vector_inspector/ui/tabs.py +64 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/__main__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/config/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/config/known_embedding_models.json +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/cache_manager.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connection_manager.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/base_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/chroma_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/pgvector_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/pinecone_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/qdrant_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/qdrant_helpers/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/qdrant_helpers/qdrant_embedding_resolver.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/qdrant_helpers/qdrant_filter_builder.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/connections/template_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/embedding_providers/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/embedding_providers/base_provider.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/embedding_providers/clip_provider.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/embedding_providers/provider_factory.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/embedding_providers/sentence_transformer_provider.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/embedding_utils.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/logging.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/core/model_registry.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/main.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/backup_helpers.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/backup_restore_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/credential_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/filter_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/import_export_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/profile_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/settings_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/update_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/services/visualization_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/backup_restore_dialog.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/connection_manager_panel.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/filter_builder.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/item_dialog.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/loading_dialog.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/profile_manager_panel.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/components/update_details_dialog.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/dialogs/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/dialogs/cross_db_migration.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/dialogs/embedding_config_dialog.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/dialogs/provider_type_dialog.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/views/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/views/collection_browser.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/views/connection_view.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/views/info_panel.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/views/metadata_view.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/views/search_view.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/ui/views/visualization_view.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/utils/__init__.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/utils/lazy_imports.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/src/vector_inspector/utils/version.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_backup_helpers.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_backup_restore_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_chroma_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_filter_service.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_pgvector_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_pinecone_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_qdrant_connection.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_runner.py +0 -0
- {vector_inspector-0.3.7 → vector_inspector-0.3.8}/tests/test_settings_service.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vector-inspector
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: A comprehensive desktop application for visualizing, querying, and managing vector database data
|
|
5
5
|
Author-Email: Anthony Dawson <anthonypdawson+github@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -31,13 +31,31 @@ Requires-Dist: pgvector>=0.4.2
|
|
|
31
31
|
Description-Content-Type: text/markdown
|
|
32
32
|
|
|
33
33
|
# Latest updates
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
|
|
35
|
+
## Vector Inspector 2026.01 Release Notes
|
|
36
|
+
|
|
37
|
+
### Major Refactor and Studio-Ready Architecture
|
|
38
|
+
- Refactored main window into modular components:
|
|
39
|
+
- InspectorShell: reusable UI shell (splitter, tabs, layout)
|
|
40
|
+
- ProviderFactory: centralized connection creation
|
|
41
|
+
- DialogService: dialog management
|
|
42
|
+
- ConnectionController: connection lifecycle and threading
|
|
43
|
+
- InspectorTabs: pluggable tab registry
|
|
44
|
+
- MainWindow now inherits from InspectorShell and is fully reusable as a widget
|
|
45
|
+
- Bootstrap logic is separated from UI logic—Studio can host Inspector as a component
|
|
46
|
+
- Tab system is now pluggable: Studio and Inspector can add, remove, or override tabs via TabDefinition
|
|
47
|
+
- All Inspector UI logic is self-contained; Studio can extend without modifying Inspector code
|
|
48
|
+
|
|
49
|
+
### Data Browser Improvements
|
|
50
|
+
- Added a checkbox: Generate embeddings on edit (default: checked)
|
|
51
|
+
- When unchecked, editing a row skips embedding regeneration
|
|
52
|
+
- Setting is persisted per user
|
|
53
|
+
|
|
54
|
+
### Developer and Architecture Notes
|
|
55
|
+
- All modules pass syntax checks and are ready for Studio integration
|
|
56
|
+
- No breaking changes for existing Inspector users
|
|
57
|
+
- Inspector is now a true UI module, not just an application
|
|
58
|
+
|
|
41
59
|
---
|
|
42
60
|
|
|
43
61
|
# Vector Inspector
|
|
@@ -45,7 +63,7 @@ Description-Content-Type: text/markdown
|
|
|
45
63
|
> **Disclaimer:** This tool is currently under active development and is **not production ready**. Not all features have been thoroughly tested and code is released frequently. Use with caution in critical or production environments.
|
|
46
64
|
|
|
47
65
|
[](https://github.com/anthonypdawson/vector-inspector/actions/workflows/ci-tests.yml)
|
|
48
|
-
[](https://github.com/anthonypdawson/vector-inspector/actions/workflows/publish.yml)
|
|
66
|
+
[](https://github.com/anthonypdawson/vector-inspector/actions/workflows/publish%20copy.yml)
|
|
49
67
|
|
|
50
68
|
[](https://pypi.org/project/vector-inspector/)
|
|
51
69
|
[](https://pepy.tech/projects/vector-inspector)
|
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
# Latest updates
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
|
|
3
|
+
## Vector Inspector 2026.01 Release Notes
|
|
4
|
+
|
|
5
|
+
### Major Refactor and Studio-Ready Architecture
|
|
6
|
+
- Refactored main window into modular components:
|
|
7
|
+
- InspectorShell: reusable UI shell (splitter, tabs, layout)
|
|
8
|
+
- ProviderFactory: centralized connection creation
|
|
9
|
+
- DialogService: dialog management
|
|
10
|
+
- ConnectionController: connection lifecycle and threading
|
|
11
|
+
- InspectorTabs: pluggable tab registry
|
|
12
|
+
- MainWindow now inherits from InspectorShell and is fully reusable as a widget
|
|
13
|
+
- Bootstrap logic is separated from UI logic—Studio can host Inspector as a component
|
|
14
|
+
- Tab system is now pluggable: Studio and Inspector can add, remove, or override tabs via TabDefinition
|
|
15
|
+
- All Inspector UI logic is self-contained; Studio can extend without modifying Inspector code
|
|
16
|
+
|
|
17
|
+
### Data Browser Improvements
|
|
18
|
+
- Added a checkbox: Generate embeddings on edit (default: checked)
|
|
19
|
+
- When unchecked, editing a row skips embedding regeneration
|
|
20
|
+
- Setting is persisted per user
|
|
21
|
+
|
|
22
|
+
### Developer and Architecture Notes
|
|
23
|
+
- All modules pass syntax checks and are ready for Studio integration
|
|
24
|
+
- No breaking changes for existing Inspector users
|
|
25
|
+
- Inspector is now a true UI module, not just an application
|
|
26
|
+
|
|
9
27
|
---
|
|
10
28
|
|
|
11
29
|
# Vector Inspector
|
|
@@ -13,7 +31,7 @@
|
|
|
13
31
|
> **Disclaimer:** This tool is currently under active development and is **not production ready**. Not all features have been thoroughly tested and code is released frequently. Use with caution in critical or production environments.
|
|
14
32
|
|
|
15
33
|
[](https://github.com/anthonypdawson/vector-inspector/actions/workflows/ci-tests.yml)
|
|
16
|
-
[](https://github.com/anthonypdawson/vector-inspector/actions/workflows/publish.yml)
|
|
34
|
+
[](https://github.com/anthonypdawson/vector-inspector/actions/workflows/publish%20copy.yml)
|
|
17
35
|
|
|
18
36
|
[](https://pypi.org/project/vector-inspector/)
|
|
19
37
|
[](https://pepy.tech/projects/vector-inspector)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "vector-inspector"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.8"
|
|
4
4
|
description = "A comprehensive desktop application for visualizing, querying, and managing vector database data"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Anthony Dawson", email = "anthonypdawson+github@gmail.com" },
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Factory for creating vector database connections from provider configs."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
from vector_inspector.core.connections.base_connection import VectorDBConnection
|
|
5
|
+
from vector_inspector.core.connections.chroma_connection import ChromaDBConnection
|
|
6
|
+
from vector_inspector.core.connections.qdrant_connection import QdrantConnection
|
|
7
|
+
from vector_inspector.core.connections.pinecone_connection import PineconeConnection
|
|
8
|
+
from vector_inspector.core.connections.pgvector_connection import PgVectorConnection
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ProviderFactory:
|
|
12
|
+
"""Factory for creating database connections from configuration."""
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def create(
|
|
16
|
+
provider: str, config: Dict[str, Any], credentials: Dict[str, Any] = None
|
|
17
|
+
) -> VectorDBConnection:
|
|
18
|
+
"""Create a connection object for the specified provider.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
provider: Provider type (chromadb, qdrant, pinecone, pgvector)
|
|
22
|
+
config: Provider-specific configuration
|
|
23
|
+
credentials: Optional credentials (API keys, passwords, etc.)
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
VectorDBConnection instance
|
|
27
|
+
|
|
28
|
+
Raises:
|
|
29
|
+
ValueError: If provider is unsupported or configuration is invalid
|
|
30
|
+
"""
|
|
31
|
+
credentials = credentials or {}
|
|
32
|
+
|
|
33
|
+
if provider == "chromadb":
|
|
34
|
+
return ProviderFactory._create_chroma(config, credentials)
|
|
35
|
+
elif provider == "qdrant":
|
|
36
|
+
return ProviderFactory._create_qdrant(config, credentials)
|
|
37
|
+
elif provider == "pinecone":
|
|
38
|
+
return ProviderFactory._create_pinecone(config, credentials)
|
|
39
|
+
elif provider == "pgvector":
|
|
40
|
+
return ProviderFactory._create_pgvector(config, credentials)
|
|
41
|
+
else:
|
|
42
|
+
raise ValueError(f"Unsupported provider: {provider}")
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _create_chroma(config: Dict[str, Any], credentials: Dict[str, Any]) -> ChromaDBConnection:
|
|
46
|
+
"""Create a ChromaDB connection."""
|
|
47
|
+
conn_type = config.get("type")
|
|
48
|
+
|
|
49
|
+
if conn_type == "persistent":
|
|
50
|
+
return ChromaDBConnection(path=config.get("path"))
|
|
51
|
+
elif conn_type == "http":
|
|
52
|
+
return ChromaDBConnection(host=config.get("host"), port=config.get("port"))
|
|
53
|
+
else: # ephemeral
|
|
54
|
+
return ChromaDBConnection()
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _create_qdrant(config: Dict[str, Any], credentials: Dict[str, Any]) -> QdrantConnection:
|
|
58
|
+
"""Create a Qdrant connection."""
|
|
59
|
+
conn_type = config.get("type")
|
|
60
|
+
api_key = credentials.get("api_key")
|
|
61
|
+
|
|
62
|
+
if conn_type == "persistent":
|
|
63
|
+
return QdrantConnection(path=config.get("path"))
|
|
64
|
+
elif conn_type == "http":
|
|
65
|
+
return QdrantConnection(
|
|
66
|
+
host=config.get("host"), port=config.get("port"), api_key=api_key
|
|
67
|
+
)
|
|
68
|
+
else: # ephemeral
|
|
69
|
+
return QdrantConnection()
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def _create_pinecone(config: Dict[str, Any], credentials: Dict[str, Any]) -> PineconeConnection:
|
|
73
|
+
"""Create a Pinecone connection."""
|
|
74
|
+
api_key = credentials.get("api_key")
|
|
75
|
+
if not api_key:
|
|
76
|
+
raise ValueError("Pinecone requires an API key")
|
|
77
|
+
|
|
78
|
+
return PineconeConnection(api_key=api_key)
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def _create_pgvector(config: Dict[str, Any], credentials: Dict[str, Any]) -> PgVectorConnection:
|
|
82
|
+
"""Create a PgVector/Postgres connection."""
|
|
83
|
+
conn_type = config.get("type")
|
|
84
|
+
|
|
85
|
+
if conn_type == "http":
|
|
86
|
+
host = config.get("host", "localhost")
|
|
87
|
+
port = int(config.get("port", 5432))
|
|
88
|
+
database = config.get("database")
|
|
89
|
+
user = config.get("user")
|
|
90
|
+
# Prefer password from credentials
|
|
91
|
+
password = credentials.get("password")
|
|
92
|
+
|
|
93
|
+
return PgVectorConnection(
|
|
94
|
+
host=host, port=port, database=database, user=user, password=password
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
raise ValueError("Unsupported connection type for PgVector profile")
|
|
@@ -34,10 +34,22 @@ class SplashWindow(QDialog):
|
|
|
34
34
|
layout.addWidget(github)
|
|
35
35
|
|
|
36
36
|
# About info (reuse About dialog text)
|
|
37
|
-
from vector_inspector.
|
|
37
|
+
from vector_inspector.utils.version import get_app_version
|
|
38
38
|
|
|
39
39
|
about = QTextBrowser()
|
|
40
|
-
|
|
40
|
+
version = get_app_version()
|
|
41
|
+
version_html = (
|
|
42
|
+
f"<h2>Vector Inspector {version}</h2>" if version else "<h2>Vector Inspector</h2>"
|
|
43
|
+
)
|
|
44
|
+
about_text = (
|
|
45
|
+
version_html + "<p>A comprehensive desktop application for visualizing, "
|
|
46
|
+
"querying, and managing multiple vector databases simultaneously.</p>"
|
|
47
|
+
'<p><a href="https://github.com/anthonypdawson/vector-inspector" style="color:#2980b9;">GitHub Project Page</a></p>'
|
|
48
|
+
"<hr />"
|
|
49
|
+
"<p>Built with PySide6</p>"
|
|
50
|
+
"<p><b>New:</b> Pinecone support!</p>"
|
|
51
|
+
)
|
|
52
|
+
about.setHtml(about_text)
|
|
41
53
|
about.setOpenExternalLinks(True)
|
|
42
54
|
about.setMaximumHeight(160)
|
|
43
55
|
layout.addWidget(about)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""UI controllers for managing application logic."""
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""Controller for managing connection lifecycle and threading."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Optional
|
|
4
|
+
from PySide6.QtCore import QObject, Signal, QThread
|
|
5
|
+
from PySide6.QtWidgets import QMessageBox, QWidget
|
|
6
|
+
|
|
7
|
+
from vector_inspector.core.connection_manager import ConnectionManager, ConnectionState
|
|
8
|
+
from vector_inspector.core.connections.base_connection import VectorDBConnection
|
|
9
|
+
from vector_inspector.core.provider_factory import ProviderFactory
|
|
10
|
+
from vector_inspector.services.profile_service import ProfileService
|
|
11
|
+
from vector_inspector.ui.components.loading_dialog import LoadingDialog
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ConnectionThread(QThread):
|
|
15
|
+
"""Background thread for connecting to database."""
|
|
16
|
+
|
|
17
|
+
finished = Signal(bool, list, str) # success, collections, error_message
|
|
18
|
+
|
|
19
|
+
def __init__(self, connection: VectorDBConnection):
|
|
20
|
+
super().__init__()
|
|
21
|
+
self.connection = connection
|
|
22
|
+
|
|
23
|
+
def run(self):
|
|
24
|
+
"""Connect to database and get collections."""
|
|
25
|
+
try:
|
|
26
|
+
success = self.connection.connect()
|
|
27
|
+
if success:
|
|
28
|
+
collections = self.connection.list_collections()
|
|
29
|
+
self.finished.emit(True, collections, "")
|
|
30
|
+
else:
|
|
31
|
+
self.finished.emit(False, [], "Connection failed")
|
|
32
|
+
except Exception as e:
|
|
33
|
+
self.finished.emit(False, [], str(e))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ConnectionController(QObject):
|
|
37
|
+
"""Controller for managing connection operations and lifecycle.
|
|
38
|
+
|
|
39
|
+
This handles:
|
|
40
|
+
- Creating connections from profiles
|
|
41
|
+
- Starting connection threads
|
|
42
|
+
- Handling connection results
|
|
43
|
+
- Managing loading dialogs
|
|
44
|
+
- Emitting signals for UI updates
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
connection_completed = Signal(
|
|
48
|
+
str, bool, list, str
|
|
49
|
+
) # connection_id, success, collections, error
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
connection_manager: ConnectionManager,
|
|
54
|
+
profile_service: ProfileService,
|
|
55
|
+
parent: Optional[QWidget] = None,
|
|
56
|
+
):
|
|
57
|
+
super().__init__(parent)
|
|
58
|
+
self.connection_manager = connection_manager
|
|
59
|
+
self.profile_service = profile_service
|
|
60
|
+
self.parent_widget = parent
|
|
61
|
+
|
|
62
|
+
# State
|
|
63
|
+
self._connection_threads: Dict[str, ConnectionThread] = {}
|
|
64
|
+
self.loading_dialog = LoadingDialog("Loading...", parent)
|
|
65
|
+
|
|
66
|
+
def connect_to_profile(self, profile_id: str) -> bool:
|
|
67
|
+
"""Connect to a profile.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
profile_id: ID of the profile to connect to
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
True if connection initiated successfully, False otherwise
|
|
74
|
+
"""
|
|
75
|
+
profile_data = self.profile_service.get_profile_with_credentials(profile_id)
|
|
76
|
+
if not profile_data:
|
|
77
|
+
QMessageBox.warning(self.parent_widget, "Error", "Profile not found.")
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
# Check connection limit
|
|
81
|
+
if self.connection_manager.get_connection_count() >= ConnectionManager.MAX_CONNECTIONS:
|
|
82
|
+
QMessageBox.warning(
|
|
83
|
+
self.parent_widget,
|
|
84
|
+
"Connection Limit",
|
|
85
|
+
f"Maximum number of connections ({ConnectionManager.MAX_CONNECTIONS}) reached. "
|
|
86
|
+
"Please close a connection first.",
|
|
87
|
+
)
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
# Create connection
|
|
91
|
+
provider = profile_data["provider"]
|
|
92
|
+
config = profile_data["config"]
|
|
93
|
+
credentials = profile_data.get("credentials", {})
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
# Create connection object using factory
|
|
97
|
+
connection = ProviderFactory.create(provider, config, credentials)
|
|
98
|
+
|
|
99
|
+
# Register with connection manager, using profile_id as connection_id for persistence
|
|
100
|
+
connection_id = self.connection_manager.create_connection(
|
|
101
|
+
name=profile_data["name"],
|
|
102
|
+
provider=provider,
|
|
103
|
+
connection=connection,
|
|
104
|
+
config=config,
|
|
105
|
+
connection_id=profile_data["id"],
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Update state to connecting
|
|
109
|
+
self.connection_manager.update_connection_state(
|
|
110
|
+
connection_id, ConnectionState.CONNECTING
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Connect in background thread
|
|
114
|
+
thread = ConnectionThread(connection)
|
|
115
|
+
thread.finished.connect(
|
|
116
|
+
lambda success, collections, error: self._on_connection_finished(
|
|
117
|
+
connection_id, success, collections, error
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
self._connection_threads[connection_id] = thread
|
|
121
|
+
thread.start()
|
|
122
|
+
|
|
123
|
+
# Show loading dialog
|
|
124
|
+
self.loading_dialog.show_loading(f"Connecting to {profile_data['name']}...")
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
except Exception as e:
|
|
128
|
+
QMessageBox.critical(
|
|
129
|
+
self.parent_widget, "Connection Error", f"Failed to create connection: {e}"
|
|
130
|
+
)
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
def _on_connection_finished(
|
|
134
|
+
self, connection_id: str, success: bool, collections: list, error: str
|
|
135
|
+
):
|
|
136
|
+
"""Handle connection thread completion."""
|
|
137
|
+
self.loading_dialog.hide_loading()
|
|
138
|
+
|
|
139
|
+
# Clean up thread
|
|
140
|
+
thread = self._connection_threads.pop(connection_id, None)
|
|
141
|
+
if thread:
|
|
142
|
+
thread.wait() # Wait for thread to fully finish
|
|
143
|
+
thread.deleteLater()
|
|
144
|
+
|
|
145
|
+
if success:
|
|
146
|
+
# Update state to connected
|
|
147
|
+
self.connection_manager.update_connection_state(
|
|
148
|
+
connection_id, ConnectionState.CONNECTED
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Mark connection as opened first (will show in UI)
|
|
152
|
+
self.connection_manager.mark_connection_opened(connection_id)
|
|
153
|
+
|
|
154
|
+
# Then update collections (UI item now exists to receive them)
|
|
155
|
+
self.connection_manager.update_collections(connection_id, collections)
|
|
156
|
+
else:
|
|
157
|
+
# Update state to error
|
|
158
|
+
self.connection_manager.update_connection_state(
|
|
159
|
+
connection_id, ConnectionState.ERROR, error
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
QMessageBox.warning(
|
|
163
|
+
self.parent_widget, "Connection Failed", f"Failed to connect: {error}"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Remove the failed connection
|
|
167
|
+
self.connection_manager.close_connection(connection_id)
|
|
168
|
+
|
|
169
|
+
# Emit signal for UI updates
|
|
170
|
+
self.connection_completed.emit(connection_id, success, collections, error)
|
|
171
|
+
|
|
172
|
+
def cleanup(self):
|
|
173
|
+
"""Clean up connection threads on shutdown."""
|
|
174
|
+
for thread in list(self._connection_threads.values()):
|
|
175
|
+
if thread.isRunning():
|
|
176
|
+
thread.quit()
|
|
177
|
+
thread.wait(1000) # Wait up to 1 second
|