move 'ProductTypeIconMapping' to common project model

This commit is contained in:
Jakub Trllo 2025-09-15 11:38:58 +02:00
parent d8045df9a7
commit 7b92047a6b
5 changed files with 108 additions and 82 deletions

View file

@ -10,6 +10,7 @@ from .projects import (
PROJECTS_MODEL_SENDER,
FolderTypeItem,
TaskTypeItem,
ProductTypeIconMapping,
)
from .hierarchy import (
FolderItem,
@ -34,6 +35,7 @@ __all__ = (
"PROJECTS_MODEL_SENDER",
"FolderTypeItem",
"TaskTypeItem",
"ProductTypeIconMapping",
"FolderItem",
"TaskItem",

View file

@ -2,7 +2,7 @@ from __future__ import annotations
import contextlib
from abc import ABC, abstractmethod
from typing import Dict, Any
from typing import Any, Optional
from dataclasses import dataclass
import ayon_api
@ -51,7 +51,7 @@ class StatusItem:
self.icon: str = icon
self.state: str = state
def to_data(self) -> Dict[str, Any]:
def to_data(self) -> dict[str, Any]:
return {
"name": self.name,
"color": self.color,
@ -218,6 +218,54 @@ class ProjectItem:
return cls(**data)
class ProductTypeIconMapping:
def __init__(
self,
default: Optional[dict[str, str]] = None,
definitions: Optional[list[dict[str, str]]] = None,
):
self._default = default or {}
self._definitions = definitions or []
self._default_def = None
self._definitions_by_name = None
def get_icon(
self,
product_base_type: Optional[str] = None,
product_type: Optional[str] = None,
) -> dict[str, str]:
defs = self._get_defs_by_name()
icon = defs.get(product_type)
if icon is None:
icon = defs.get(product_base_type)
if icon is None:
icon = self._get_default_def()
return icon.copy()
def _get_default_def(self) -> dict[str, str]:
if self._default_def is None:
self._default_def = {
"type": "material-symbols",
"name": self._default.get("icon", "deployed_code"),
"color": self._default.get("color", "#cccccc"),
}
return self._default_def
def _get_defs_by_name(self) -> dict[str, dict[str, str]]:
if self._definitions_by_name is None:
self._definitions_by_name = {
product_base_type_def["name"]: {
"type": "material-symbols",
"name": product_base_type_def.get("icon", "deployed_code"),
"color": product_base_type_def.get("color", "#cccccc"),
}
for product_base_type_def in self._definitions
}
return self._definitions_by_name
def _get_project_items_from_entitiy(
projects: list[dict[str, Any]]
) -> list[ProjectItem]:
@ -242,6 +290,9 @@ class ProjectsModel(object):
self._projects_by_name = NestedCacheItem(
levels=1, default_factory=list
)
self._product_type_icons_mapping = NestedCacheItem(
levels=1, default_factory=ProductTypeIconMapping
)
self._project_statuses_cache = {}
self._folder_types_cache = {}
self._task_types_cache = {}
@ -255,6 +306,7 @@ class ProjectsModel(object):
self._task_types_cache = {}
self._projects_cache.reset()
self._projects_by_name.reset()
self._product_type_icons_mapping.reset()
def refresh(self):
"""Refresh project items.
@ -390,6 +442,27 @@ class ProjectsModel(object):
self._task_type_items_getter,
)
def get_product_type_icons_mapping(
self, project_name: Optional[str]
) -> ProductTypeIconMapping:
cache = self._product_type_icons_mapping[project_name]
if cache.is_valid:
return cache.get_data()
project_entity = self.get_project_entity(project_name)
icons_mapping = ProductTypeIconMapping()
if project_entity:
product_base_types = (
project_entity["config"].get("productBaseTypes", {})
)
icons_mapping = ProductTypeIconMapping(
product_base_types.get("default"),
product_base_types.get("definitions")
)
cache.update_data(icons_mapping)
return icons_mapping
def _get_project_items(
self, project_name, sender, item_type, cache_obj, getter
):

View file

@ -9,7 +9,11 @@ from ayon_core.lib.attribute_definitions import (
deserialize_attr_defs,
serialize_attr_defs,
)
from ayon_core.tools.common_models import TaskItem, TagItem
from ayon_core.tools.common_models import (
TaskItem,
TagItem,
ProductTypeIconMapping,
)
class ProductTypeItem:
@ -492,8 +496,8 @@ class BackendLoaderController(_BaseLoaderController):
topic (str): Event topic name.
data (Optional[dict[str, Any]]): Event data.
source (Optional[str]): Event source.
"""
"""
pass
@abstractmethod
@ -502,14 +506,20 @@ class BackendLoaderController(_BaseLoaderController):
Returns:
set[str]: Set of loaded product ids.
"""
"""
pass
@abstractmethod
def get_project_entity(
def get_product_type_icons_mapping(
self, project_name: Optional[str]
) -> Optional[dict[str, Any]]:
) -> ProductTypeIconMapping:
"""Product type icons mapping.
Returns:
ProductTypeIconMapping: Product type icons mapping.
"""
pass

View file

@ -17,6 +17,7 @@ from ayon_core.tools.common_models import (
HierarchyModel,
ThumbnailsModel,
TagItem,
ProductTypeIconMapping,
)
from .abstract import (
@ -189,11 +190,6 @@ class LoaderController(BackendLoaderController, FrontendLoaderController):
def get_project_items(self, sender=None):
return self._projects_model.get_project_items(sender)
def get_project_entity(
self, project_name: Optional[str]
) -> Optional[dict[str, Any]]:
return self._projects_model.get_project_entity(project_name)
def get_folder_type_items(self, project_name, sender=None):
return self._projects_model.get_folder_type_items(
project_name, sender
@ -204,6 +200,13 @@ class LoaderController(BackendLoaderController, FrontendLoaderController):
project_name, sender
)
def get_product_type_icons_mapping(
self, project_name: Optional[str]
) -> ProductTypeIconMapping:
return self._projects_model.get_product_type_icons_mapping(
project_name
)
def get_folder_items(self, project_name, sender=None):
return self._hierarchy_model.get_folder_items(project_name, sender)

View file

@ -11,6 +11,7 @@ from ayon_api.operations import OperationsSession
from ayon_core.lib import NestedCacheItem
from ayon_core.style import get_default_entity_icon_color
from ayon_core.tools.common_models import ProductTypeIconMapping
from ayon_core.tools.loader.abstract import (
ProductTypeItem,
ProductBaseTypeItem,
@ -29,54 +30,6 @@ if TYPE_CHECKING:
PRODUCTS_MODEL_SENDER = "products.model"
class ProductBaseTypeIconMapping:
def __init__(
self,
default: Optional[dict[str, str]] = None,
definitions: Optional[list[dict[str, str]]] = None,
):
self._default = default or {}
self._definitions = definitions or []
self._default_def = None
self._definitions_by_name = None
def get_icon(
self,
product_base_type: Optional[str] = None,
product_type: Optional[str] = None,
) -> dict[str, str]:
defs = self._get_defs_by_name()
icon = defs.get(product_type)
if icon is None:
icon = defs.get(product_base_type)
if icon is None:
icon = self._get_default_def()
return icon.copy()
def _get_default_def(self) -> dict[str, str]:
if self._default_def is None:
self._default_def = {
"type": "material-symbols",
"name": self._default.get("icon", "deployed_code"),
"color": self._default.get("color", "#cccccc"),
}
return self._default_def
def _get_defs_by_name(self) -> dict[str, dict[str, str]]:
if self._definitions_by_name is None:
self._definitions_by_name = {
product_base_type_def["name"]: {
"type": "material-symbols",
"name": product_base_type_def.get("icon", "deployed_code"),
"color": product_base_type_def.get("color", "#cccccc"),
}
for product_base_type_def in self._definitions
}
return self._definitions_by_name
def version_item_from_entity(version):
version_attribs = version["attrib"]
tags = version["tags"]
@ -211,8 +164,6 @@ class ProductsModel:
self._product_folder_ids_mapping = collections.defaultdict(dict)
# Cache helpers
self._product_type_icons_mapping = NestedCacheItem(
levels=1, default_factory=list, lifetime=self.lifetime)
self._product_type_items_cache = NestedCacheItem(
levels=1, default_factory=list, lifetime=self.lifetime)
self._product_base_type_items_cache = NestedCacheItem(
@ -229,7 +180,6 @@ class ProductsModel:
self._version_item_by_id.clear()
self._product_folder_ids_mapping.clear()
self._product_type_icons_mapping.reset()
self._product_type_items_cache.reset()
self._product_items_cache.reset()
self._repre_items_cache.reset()
@ -267,6 +217,10 @@ class ProductsModel:
) -> list[ProductBaseTypeItem]:
"""Product base type items for the project.
Notes:
This will be used for filtering product types in UI when
product base types are fully implemented.
Args:
project_name (optional, str): Project name.
@ -510,24 +464,8 @@ class ProductsModel:
def _get_product_type_icons(
self, project_name: Optional[str]
) -> ProductBaseTypeIconMapping:
cache = self._product_type_icons_mapping[project_name]
if cache.is_valid:
return cache.get_data()
project_entity = self._controller.get_project_entity(project_name)
icons_mapping = ProductBaseTypeIconMapping()
if project_entity:
product_base_types = (
project_entity["config"].get("productBaseTypes", {})
)
icons_mapping = ProductBaseTypeIconMapping(
product_base_types.get("default"),
product_base_types.get("definitions")
)
cache.update_data(icons_mapping)
return icons_mapping
) -> ProductTypeIconMapping:
return self._controller.get_product_type_icons_mapping(project_name)
def _get_product_items_by_id(self, project_name, product_ids):
product_item_by_id = self._product_item_by_id[project_name]
@ -542,7 +480,7 @@ class ProductsModel:
output.update(
self._query_product_items_by_ids(
project_name, missing_product_ids
project_name, product_ids=missing_product_ids
)
)
return output