diff --git a/bpy_speckle/states/speckle_state.py b/bpy_speckle/states/speckle_state.py index 076dabb..a140f0b 100644 --- a/bpy_speckle/states/speckle_state.py +++ b/bpy_speckle/states/speckle_state.py @@ -2,12 +2,9 @@ from bpy.props import CollectionProperty, StringProperty, IntProperty, IntVectorProperty from ..ui.model_selection_dialog import speckle_model -from ..ui.version_selection_dialog import speckle_version from ..ui.model_card import speckle_model_card class SpeckleState(bpy.types.PropertyGroup): - models: CollectionProperty(type=speckle_model) - versions: CollectionProperty(type=speckle_version) ui_mode: StringProperty(name="UI Mode", default="NONE") model_cards: CollectionProperty(type=speckle_model_card) model_card_index: IntProperty(name="Model Card Index", default=0) diff --git a/bpy_speckle/ui/model_selection_dialog.py b/bpy_speckle/ui/model_selection_dialog.py index 95cdb8b..c01c14c 100644 --- a/bpy_speckle/ui/model_selection_dialog.py +++ b/bpy_speckle/ui/model_selection_dialog.py @@ -100,15 +100,11 @@ def execute(self, context: Context) -> set[str]: return {'FINISHED'} def invoke(self, context: Context, event: Event) -> set[str]: - wm = context.window_manager # Ensure WindowManager has the projects collection if not hasattr(WindowManager, "speckle_models"): # Register the collection property WindowManager.speckle_models = bpy.props.CollectionProperty(type=speckle_model) - - # Clear existing models - wm.speckle_models.clear() # Update models list self.update_models_list(context) diff --git a/bpy_speckle/ui/selection_filter_dialog.py b/bpy_speckle/ui/selection_filter_dialog.py index 0094a49..76d565a 100644 --- a/bpy_speckle/ui/selection_filter_dialog.py +++ b/bpy_speckle/ui/selection_filter_dialog.py @@ -22,12 +22,24 @@ class SPECKLE_OT_selection_filter_dialog(MousePositionMixin, bpy.types.Operator) default="" ) + project_id: bpy.props.StringProperty( + name="Project ID", + description="ID of the selected project", + default="" + ) + model_name: bpy.props.StringProperty( name="Model Name", description="Name of the selected model", default="" ) + model_id: bpy.props.StringProperty( + name="Model ID", + description="ID of the selected model", + default="" + ) + def execute(self, context): model_card = context.scene.speckle_state.model_cards.add() model_card.project_name = self.project_name diff --git a/bpy_speckle/ui/version_selection_dialog.py b/bpy_speckle/ui/version_selection_dialog.py index a894db7..2df3450 100644 --- a/bpy_speckle/ui/version_selection_dialog.py +++ b/bpy_speckle/ui/version_selection_dialog.py @@ -1,7 +1,8 @@ import bpy -from bpy.types import UILayout, Context, UIList, PropertyGroup, Operator, Event +from bpy.types import WindowManager, UILayout, Context, UIList, PropertyGroup, Operator, Event from typing import List, Tuple from .mouse_position_mixin import MousePositionMixin +from ..utils.version_manager import get_versions_for_model class speckle_version(bpy.types.PropertyGroup): """ @@ -62,14 +63,42 @@ class SPECKLE_OT_version_selection_dialog(MousePositionMixin, bpy.types.Operator default="" ) - versions: List[Tuple[str, str, str]] = [ - ("648896", "Message 1", "12 day ago"), - ("658465", "Message 2", "15 days ago"), - ("154651", "Message 3", "20 days ago"), - ] + project_id: bpy.props.StringProperty( + name="Project ID", + description="ID of the selected project", + default="" + ) + + model_id: bpy.props.StringProperty( + name="Model ID", + description="ID of the selected model", + default="" + ) version_index: bpy.props.IntProperty(name="Model Index", default=0) + def update_versions_list(self, context): + wm = context.window_manager + # Clear existing versions + wm.speckle_versions.clear() + + # Get versions for the selected model + search = self.search_query if self.search_query.strip() else None + versions = get_versions_for_model( + account_id=wm.selected_account_id, + project_id=self.project_id, + model_id=self.model_id, + search=search + ) + + # Populate versions list + for id, message, updated in versions: + version = wm.speckle_versions.add() + version.id = id + version.message = message + version.updated = updated + + return None def execute(self, context: Context) -> set[str]: model_card = context.scene.speckle_state.model_cards.add() @@ -77,22 +106,23 @@ def execute(self, context: Context) -> set[str]: model_card.model_name = self.model_name model_card.is_publish = False # Store the selected version ID - selected_version = context.scene.speckle_state.versions[self.version_index] + selected_version = context.window_manager.speckle_versions[self.version_index] model_card.version_id = selected_version.id return {'FINISHED'} def invoke(self, context: Context, event: Event) -> set[str]: - # Clear existing versions - context.scene.speckle_state.versions.clear() - # Populate with new versions - for id, message, updated in self.versions: - version = context.scene.speckle_state.versions.add() - version.id = id - version.message = message - version.updated = updated + + # Ensure WindowManager has the versions collection + if not hasattr(WindowManager, "speckle_versions"): + # Register the collection property + WindowManager.speckle_versions = bpy.props.CollectionProperty(type=speckle_version) + + # Update versions list + self.update_versions_list(context) # Initialize mouse position self.init_mouse_position(context, event) + return context.window_manager.invoke_props_dialog(self) def draw(self, context: Context) -> None: @@ -104,7 +134,7 @@ def draw(self, context: Context) -> None: row = layout.row(align=True) row.prop(self, "search_query", icon='VIEWZOOM', text="") # Versions UIList - layout.template_list("SPECKLE_UL_versions_list", "", context.scene.speckle_state, "versions", self, "version_index") + layout.template_list("SPECKLE_UL_versions_list", "", context.window_manager, "speckle_versions", self, "version_index") layout.separator() diff --git a/bpy_speckle/utils/version_manager.py b/bpy_speckle/utils/version_manager.py new file mode 100644 index 0000000..23c0898 --- /dev/null +++ b/bpy_speckle/utils/version_manager.py @@ -0,0 +1,47 @@ +from specklepy.api.client import SpeckleClient +from specklepy.api.credentials import get_local_accounts +from typing import List, Tuple, Optional +from .misc import format_relative_time +from specklepy.core.api.inputs.model_inputs import ModelVersionsFilter + +def get_versions_for_model(account_id: str, project_id: str, model_id: str, search: Optional[str] = None) -> List[Tuple[str, str, str]]: + """ + Fetch versions for a given model from the Speckle server. + + Args: + account_id: The ID of the Speckle account to fetch versions for + project_id: The ID of the project containing the model + model_id: The ID of the model to fetch versions from + search: Optional search string to filter versions + + Returns: + List of tuples containing (version_id, message, last_updated) + Returns empty list if any error occurs + """ + try: + # Validate inputs + if not account_id or not project_id or not model_id: + print(f"Error: Invalid inputs - account_id: {account_id}, project_id: {project_id}, model_id: {model_id}") + return [] + + # Get the account info + account = next((acc for acc in get_local_accounts() if acc.id == account_id), None) + if not account: + print(f"Error: Could not find account with ID: {account_id}") + return [] + + # Initialize the client + client = SpeckleClient(host=account.serverInfo.url) + # Authenticate + client.authenticate_with_account(account) + + filter = ModelVersionsFilter(search=search, priorityIds=[]) + + # Get versions + versions = client.version.get_versions(project_id=project_id, model_id=model_id, limit=10, filter=filter).items + + return [(version.id, version.message or "No message", format_relative_time(version.createdAt)) for version in versions] + + except Exception as e: + print(f"Error fetching versions: {str(e)}") + return [] \ No newline at end of file