Merge pull request #690 from ynput/feature/AY-5635_Action-to-update-to-latest-approved-version

Scene Inventory: Action to update to latest approved version
This commit is contained in:
Jakub Trllo 2024-06-25 11:40:32 +02:00 committed by GitHub
commit e76ad2faa8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 153 additions and 26 deletions

View file

@ -2,6 +2,8 @@
from .cache import CacheItem, NestedCacheItem
from .projects import (
StatusItem,
StatusStates,
ProjectItem,
ProjectsModel,
PROJECTS_MODEL_SENDER,
@ -21,6 +23,8 @@ __all__ = (
"CacheItem",
"NestedCacheItem",
"StatusItem",
"StatusStates",
"ProjectItem",
"ProjectsModel",
"PROJECTS_MODEL_SENDER",

View file

@ -1,8 +1,8 @@
import contextlib
from abc import ABCMeta, abstractmethod
from abc import ABC, abstractmethod
from typing import Dict, Any
import ayon_api
import six
from ayon_core.style import get_default_entity_icon_color
from ayon_core.lib import CacheItem, NestedCacheItem
@ -10,8 +10,14 @@ from ayon_core.lib import CacheItem, NestedCacheItem
PROJECTS_MODEL_SENDER = "projects.model"
@six.add_metaclass(ABCMeta)
class AbstractHierarchyController:
class StatusStates:
not_started = "not_started"
in_progress = "in_progress"
done = "done"
blocked = "blocked"
class AbstractHierarchyController(ABC):
@abstractmethod
def emit_event(self, topic, data, source):
pass
@ -25,18 +31,24 @@ class StatusItem:
color (str): Status color in hex ("#434a56").
short (str): Short status name ("NRD").
icon (str): Icon name in MaterialIcons ("fiber_new").
state (Literal["not_started", "in_progress", "done", "blocked"]):
Status state.
state (str): Status state.
"""
def __init__(self, name, color, short, icon, state):
self.name = name
self.color = color
self.short = short
self.icon = icon
self.state = state
def __init__(
self,
name: str,
color: str,
short: str,
icon: str,
state: str
):
self.name: str = name
self.color: str = color
self.short: str = short
self.icon: str = icon
self.state: str = state
def to_data(self):
def to_data(self) -> Dict[str, Any]:
return {
"name": self.name,
"color": self.color,

View file

@ -217,7 +217,9 @@ class InventoryModel(QtGui.QStandardItemModel):
version_label = format_version(version_item.version)
is_hero = version_item.version < 0
is_latest = version_item.is_latest
if not is_latest:
# TODO maybe use different colors for last approved and last
# version? Or don't care about color at all?
if not is_latest and not version_item.is_last_approved:
version_color = self.OUTDATED_COLOR
status_name = version_item.status

View file

@ -3,7 +3,9 @@ import collections
import ayon_api
from ayon_api.graphql import GraphQlQuery
from ayon_core.host import ILoadHost
from ayon_core.tools.common_models.projects import StatusStates
# --- Implementation that should be in ayon-python-api ---
@ -149,26 +151,35 @@ class RepresentationInfo:
class VersionItem:
def __init__(self, version_id, product_id, version, status, is_latest):
self.version = version
self.version_id = version_id
self.product_id = product_id
self.version = version
self.status = status
self.is_latest = is_latest
def __init__(
self,
version_id: str,
product_id: str,
version: int,
status: str,
is_latest: bool,
is_last_approved: bool,
):
self.version_id: str = version_id
self.product_id: str = product_id
self.version: int = version
self.status: str = status
self.is_latest: bool = is_latest
self.is_last_approved: bool = is_last_approved
@property
def is_hero(self):
return self.version < 0
@classmethod
def from_entity(cls, version_entity, is_latest):
def from_entity(cls, version_entity, is_latest, is_last_approved):
return cls(
version_id=version_entity["id"],
product_id=version_entity["productId"],
version=version_entity["version"],
status=version_entity["status"],
is_latest=is_latest,
is_last_approved=is_last_approved,
)
@ -275,6 +286,11 @@ class ContainersModel:
if product_id not in self._version_items_by_product_id
}
if missing_ids:
status_items_by_name = {
status_item.name: status_item
for status_item in self._controller.get_project_status_items()
}
def version_sorted(entity):
return entity["version"]
@ -300,9 +316,21 @@ class ContainersModel:
version_entities_by_product_id.items()
):
last_version = abs(version_entities[-1]["version"])
last_approved_id = None
for version_entity in version_entities:
status_item = status_items_by_name.get(
version_entity["status"]
)
if status_item is None:
continue
if status_item.state == StatusStates.done:
last_approved_id = version_entity["id"]
version_items_by_id = {
entity["id"]: VersionItem.from_entity(
entity, abs(entity["version"]) == last_version
entity,
abs(entity["version"]) == last_version,
entity["id"] == last_approved_id
)
for entity in version_entities
}

View file

@ -233,19 +233,38 @@ class SceneInventoryView(QtWidgets.QTreeView):
has_outdated = False
has_loaded_hero_versions = False
has_available_hero_version = False
for version_items_by_id in version_items_by_product_id.values():
has_outdated_approved = False
last_version_by_product_id = {}
for product_id, version_items_by_id in (
version_items_by_product_id.items()
):
_has_outdated_approved = False
_last_approved_version_item = None
for version_item in version_items_by_id.values():
if version_item.is_hero:
has_available_hero_version = True
elif version_item.is_last_approved:
_last_approved_version_item = version_item
_has_outdated_approved = True
if version_item.version_id not in version_ids:
continue
if version_item.is_hero:
has_loaded_hero_versions = True
elif not version_item.is_latest:
has_outdated = True
if (
_has_outdated_approved
and _last_approved_version_item is not None
):
last_version_by_product_id[product_id] = (
_last_approved_version_item
)
has_outdated_approved = True
switch_to_versioned = None
if has_loaded_hero_versions:
update_icon = qtawesome.icon(
@ -261,6 +280,42 @@ class SceneInventoryView(QtWidgets.QTreeView):
lambda: self._on_switch_to_versioned(item_ids)
)
update_to_last_approved_action = None
approved_version_by_item_id = {}
if has_outdated_approved:
for container_item in container_items_by_id.values():
repre_id = container_item.representation_id
repre_info = repre_info_by_id.get(repre_id)
if not repre_info or not repre_info.is_valid:
continue
version_item = last_version_by_product_id.get(
repre_info.product_id
)
if (
version_item is None
or version_item.version_id == repre_info.version_id
):
continue
approved_version_by_item_id[container_item.item_id] = (
version_item.version
)
if approved_version_by_item_id:
update_icon = qtawesome.icon(
"fa.angle-double-up",
color="#00f0b4"
)
update_to_last_approved_action = QtWidgets.QAction(
update_icon,
"Update to last approved",
menu
)
update_to_last_approved_action.triggered.connect(
lambda: self._update_containers_to_approved_versions(
approved_version_by_item_id
)
)
update_to_latest_action = None
if has_outdated or has_loaded_hero_versions:
update_icon = qtawesome.icon(
@ -299,7 +354,9 @@ class SceneInventoryView(QtWidgets.QTreeView):
# set version
set_version_action = None
if active_repre_id is not None:
set_version_icon = qtawesome.icon("fa.hashtag", color=DEFAULT_COLOR)
set_version_icon = qtawesome.icon(
"fa.hashtag", color=DEFAULT_COLOR
)
set_version_action = QtWidgets.QAction(
set_version_icon,
"Set version",
@ -323,6 +380,9 @@ class SceneInventoryView(QtWidgets.QTreeView):
if switch_to_versioned:
menu.addAction(switch_to_versioned)
if update_to_last_approved_action:
menu.addAction(update_to_last_approved_action)
if update_to_latest_action:
menu.addAction(update_to_latest_action)
@ -970,3 +1030,24 @@ class SceneInventoryView(QtWidgets.QTreeView):
"""
versions = [version for _ in range(len(item_ids))]
self._update_containers(item_ids, versions)
def _update_containers_to_approved_versions(
self, approved_version_by_item_id
):
"""Helper to update items to given version (or version per item)
If at least one item is specified this will always try to refresh
the inventory even if errors occurred on any of the items.
Arguments:
approved_version_by_item_id (Dict[str, int]): Version to set by
item id.
"""
versions = []
item_ids = []
for item_id, version in approved_version_by_item_id.items():
item_ids.append(item_id)
versions.append(version)
self._update_containers(item_ids, versions)