From 55a7db79899be57494591e434b447bc3319245c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 23 Jul 2025 16:59:20 +0200 Subject: [PATCH 1/9] :recycle: revive linked assets/folders in template builder Adding back linked assets/folder feature that was there in template builder in OpenPype. This is now working with template type links of AYON. --- .../workfile/workfile_template_builder.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index b0fad8d2a1..276f90af80 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -313,7 +313,8 @@ class AbstractTemplateBuilder(ABC): if not folder_entity: return [] links = get_folder_links( - project_name, folder_entity["id"], link_direction="in" + project_name, + folder_entity["id"], link_types=["template"], link_direction="in" ) linked_folder_ids = { link["entityId"] @@ -1429,8 +1430,7 @@ class PlaceholderLoadMixin(object): builder_type_enum_items = [ {"label": "Current folder", "value": "context_folder"}, - # TODO implement linked folders - # {"label": "Linked folders", "value": "linked_folders"}, + {"label": "Linked folders", "value": "linked_folders"}, {"label": "All folders", "value": "all_folders"}, ] build_type_label = "Folder Builder Type" @@ -1607,10 +1607,7 @@ class PlaceholderLoadMixin(object): builder_type = placeholder.data["builder_type"] folder_ids = [] - if builder_type == "context_folder": - folder_ids = [current_folder_entity["id"]] - - elif builder_type == "all_folders": + if builder_type == "all_folders": folder_ids = { folder_entity["id"] for folder_entity in get_folders( @@ -1620,6 +1617,19 @@ class PlaceholderLoadMixin(object): ) } + elif builder_type == "context_folder": + folder_ids = [current_folder_entity["id"]] + + elif builder_type == "linked_folders": + # Get all linked folders for the current folder + if hasattr(self, "builder") and isinstance( + self.builder, AbstractTemplateBuilder): + # self.builder: AbstractTemplateBuilder + folder_ids = [ + linked_folder_entity["id"] + for linked_folder_entity in self.builder.linked_folder_entities # noqa: E501 + ] + if not folder_ids: return [] From cc9be12d22e7f5eb524d5f6eabfdb1ee9a049f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 23 Jul 2025 17:16:11 +0200 Subject: [PATCH 2/9] :recycle: break the long line --- .../ayon_core/pipeline/workfile/workfile_template_builder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 276f90af80..bfa192d834 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1627,7 +1627,8 @@ class PlaceholderLoadMixin(object): # self.builder: AbstractTemplateBuilder folder_ids = [ linked_folder_entity["id"] - for linked_folder_entity in self.builder.linked_folder_entities # noqa: E501 + for linked_folder_entity in ( + self.builder.linked_folder_entities) ] if not folder_ids: From 06dbaf2d635d42ad9ba82701593b37a453a5f6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Tue, 29 Jul 2025 18:01:34 +0200 Subject: [PATCH 3/9] :recycle: add link types --- .../workfile/workfile_template_builder.py | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index bfa192d834..6b82e3b04d 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -204,7 +204,9 @@ class AbstractTemplateBuilder(ABC): @property def linked_folder_entities(self): if self._linked_folder_entities is _NOT_SET: - self._linked_folder_entities = self._get_linked_folder_entities() + self._linked_folder_entities = self._get_linked_folder_entities( + link_type="template" + ) return self._linked_folder_entities @property @@ -307,14 +309,14 @@ class AbstractTemplateBuilder(ABC): self._loaders_by_name = get_loaders_by_name() return self._loaders_by_name - def _get_linked_folder_entities(self): + def _get_linked_folder_entities(self, link_type: str = "template"): project_name = self.project_name folder_entity = self.current_folder_entity if not folder_entity: return [] links = get_folder_links( project_name, - folder_entity["id"], link_types=["template"], link_direction="in" + folder_entity["id"], link_types=[link_type], link_direction="in" ) linked_folder_ids = { link["entityId"] @@ -1433,6 +1435,14 @@ class PlaceholderLoadMixin(object): {"label": "Linked folders", "value": "linked_folders"}, {"label": "All folders", "value": "all_folders"}, ] + + link_types = ayon_api.get_link_types(self.builder.project_name) + + link_types_enum_item = [ + {"label": link_type["name"], "value": link_type["linkType"]} + for link_type in link_types + + ] build_type_label = "Folder Builder Type" build_type_help = ( "Folder Builder Type\n" @@ -1461,6 +1471,17 @@ class PlaceholderLoadMixin(object): items=builder_type_enum_items, tooltip=build_type_help ), + attribute_definitions.EnumDef( + "link_type", + label="Link Type", + default="template", + items=link_types_enum_item, + tooltip=( + "Link Type\n" + "\nDefines what type of link will be used to" + " link the asset to the current folder." + ) + ), attribute_definitions.EnumDef( "product_type", label="Product type", From eaf47d8731a9dab98ff38d637984ea2d0837dc8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 30 Jul 2025 18:32:09 +0200 Subject: [PATCH 4/9] :recycle: don't allow duplicate loaders --- client/ayon_core/pipeline/load/plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/load/plugins.py b/client/ayon_core/pipeline/load/plugins.py index dc5bb0f66f..48e860e834 100644 --- a/client/ayon_core/pipeline/load/plugins.py +++ b/client/ayon_core/pipeline/load/plugins.py @@ -373,7 +373,7 @@ def discover_loader_plugins(project_name=None): if not project_name: project_name = get_current_project_name() project_settings = get_project_settings(project_name) - plugins = discover(LoaderPlugin) + plugins = discover(LoaderPlugin, allow_duplicates=False) hooks = discover(LoaderHookPlugin) sorted_hooks = sorted(hooks, key=lambda hook: hook.order) for plugin in plugins: From a85cf5d2e907c13dc19d1818231fc28ba0829000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Thu, 31 Jul 2025 15:41:47 +0200 Subject: [PATCH 5/9] :recycle: handle more link types --- .../workfile/workfile_template_builder.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 6b82e3b04d..7920abb23f 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -201,14 +201,6 @@ class AbstractTemplateBuilder(ABC): ) return self._current_folder_entity - @property - def linked_folder_entities(self): - if self._linked_folder_entities is _NOT_SET: - self._linked_folder_entities = self._get_linked_folder_entities( - link_type="template" - ) - return self._linked_folder_entities - @property def current_task_entity(self): if self._current_task_entity is _NOT_SET: @@ -309,7 +301,7 @@ class AbstractTemplateBuilder(ABC): self._loaders_by_name = get_loaders_by_name() return self._loaders_by_name - def _get_linked_folder_entities(self, link_type: str = "template"): + def get_linked_folder_entities(self, link_type: str = "template"): project_name = self.project_name folder_entity = self.current_folder_entity if not folder_entity: @@ -1642,6 +1634,8 @@ class PlaceholderLoadMixin(object): folder_ids = [current_folder_entity["id"]] elif builder_type == "linked_folders": + # link type from placeholder data or default to "template" + link_type = placeholder.data.get("link_type", "template") # Get all linked folders for the current folder if hasattr(self, "builder") and isinstance( self.builder, AbstractTemplateBuilder): @@ -1649,7 +1643,8 @@ class PlaceholderLoadMixin(object): folder_ids = [ linked_folder_entity["id"] for linked_folder_entity in ( - self.builder.linked_folder_entities) + self.builder.get_linked_folder_entities( + link_type=link_type)) ] if not folder_ids: From 2ee875b90b98cc501f9887867ab090b053b03038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Thu, 31 Jul 2025 17:17:44 +0200 Subject: [PATCH 6/9] :recycle: remove defaults --- .../ayon_core/pipeline/workfile/workfile_template_builder.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 7920abb23f..7b20747768 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -301,7 +301,7 @@ class AbstractTemplateBuilder(ABC): self._loaders_by_name = get_loaders_by_name() return self._loaders_by_name - def get_linked_folder_entities(self, link_type: str = "template"): + def get_linked_folder_entities(self, link_type: str): project_name = self.project_name folder_entity = self.current_folder_entity if not folder_entity: @@ -1466,7 +1466,6 @@ class PlaceholderLoadMixin(object): attribute_definitions.EnumDef( "link_type", label="Link Type", - default="template", items=link_types_enum_item, tooltip=( "Link Type\n" From 5fa11b24e4bb0b165b67cd779d0e8c25ed8a2984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Thu, 31 Jul 2025 17:21:21 +0200 Subject: [PATCH 7/9] :recycle: limit link types to folder <-> folder --- .../workfile/workfile_template_builder.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 7b20747768..6a36fd12e4 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -1430,11 +1430,21 @@ class PlaceholderLoadMixin(object): link_types = ayon_api.get_link_types(self.builder.project_name) - link_types_enum_item = [ + # Filter link types for folder to folder links + link_types_enum_items = [ {"label": link_type["name"], "value": link_type["linkType"]} for link_type in link_types - + if ( + link_type["inputType"] == "folder" + and link_type["outputType"] == "folder" + ) ] + + if not link_types_enum_items: + link_types_enum_items.append( + {"label": "", "value": None} + ) + build_type_label = "Folder Builder Type" build_type_help = ( "Folder Builder Type\n" @@ -1466,7 +1476,7 @@ class PlaceholderLoadMixin(object): attribute_definitions.EnumDef( "link_type", label="Link Type", - items=link_types_enum_item, + items=link_types_enum_items, tooltip=( "Link Type\n" "\nDefines what type of link will be used to" From c219403b13c1f9436b17758e095b2f7fdd6788d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Mon, 4 Aug 2025 18:18:10 +0200 Subject: [PATCH 8/9] Update client/ayon_core/pipeline/workfile/workfile_template_builder.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../ayon_core/pipeline/workfile/workfile_template_builder.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 6a36fd12e4..9994bcfd4e 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -301,7 +301,9 @@ class AbstractTemplateBuilder(ABC): self._loaders_by_name = get_loaders_by_name() return self._loaders_by_name - def get_linked_folder_entities(self, link_type: str): + def get_linked_folder_entities(self, link_type: Optional[str]): + if not link_type: + return [] project_name = self.project_name folder_entity = self.current_folder_entity if not folder_entity: From 80cd3a3ea811dc70dd2e0c44b22eb42ebb8d4d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Fri, 8 Aug 2025 12:23:43 +0200 Subject: [PATCH 9/9] :bug: fix import --- client/ayon_core/pipeline/workfile/workfile_template_builder.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/pipeline/workfile/workfile_template_builder.py b/client/ayon_core/pipeline/workfile/workfile_template_builder.py index 9994bcfd4e..e2add99752 100644 --- a/client/ayon_core/pipeline/workfile/workfile_template_builder.py +++ b/client/ayon_core/pipeline/workfile/workfile_template_builder.py @@ -16,6 +16,7 @@ import re import collections import copy from abc import ABC, abstractmethod +from typing import Optional import ayon_api from ayon_api import (