From 5ee980041a13ae2097a9067e2f128b88967e04f9 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 19 Mar 2024 23:44:44 +0100 Subject: [PATCH 01/13] Fix outdated highlighting and filtering state for non-hero and hero version - Also optimize the query of highest version by doing one query per product id instead of one per representation id --- .../ayon_core/tools/sceneinventory/model.py | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index df0dea7a3d..92591206fb 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -68,13 +68,7 @@ class InventoryModel(TreeModel): } def outdated(self, item): - value = item.get("version") - if isinstance(value, HeroVersionType): - return False - - if item.get("version") == item.get("highest_version"): - return False - return True + return item.get("isOutdated", True) def data(self, index, role): if not index.isValid(): @@ -297,6 +291,23 @@ class InventoryModel(TreeModel): ) sites_info = self._controller.get_sites_information() + # Query the highest available version so the model can know + # whether current version is currently up-to-date. + highest_versions = ayon_api.get_versions( + project_name, + product_ids={ + group["version"]["productId"] for group in grouped.values() + }, + latest=True, + standard=True, + hero=False, + fields=["productId", "version"] + ) + highest_version_by_product_id = { + version["productId"]: version["version"] + for version in highest_versions + } + for repre_id, group_dict in sorted(grouped.items()): group_containers = group_dict["containers"] repre_entity = group_dict["representation"] @@ -306,12 +317,6 @@ class InventoryModel(TreeModel): product_type = product_entity["productType"] - # Store the highest available version so the model can know - # whether current version is currently up-to-date. - highest_version = ayon_api.get_last_version_by_product_id( - project_name, version_entity["productId"] - ) - # create the group header group_node = Item() group_node["Name"] = "{}_{}: ({})".format( @@ -321,7 +326,17 @@ class InventoryModel(TreeModel): ) group_node["representation"] = repre_id group_node["version"] = version_entity["version"] - group_node["highest_version"] = highest_version["version"] + + # We check against `abs(version)` because we allow a hero version + # which is represented by a negative number to also count as + # latest version + # If a hero version for whatever reason does not match the latest + # positive version number, we also consider it outdated + group_node["isOutdated"] = ( + abs(version_entity["version"]) != + highest_version_by_product_id.get(version_entity["productId"]) + ) + group_node["productType"] = product_type or "" group_node["productTypeIcon"] = product_type_icon group_node["count"] = len(group_containers) @@ -490,17 +505,15 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel): def _is_outdated(self, row, parent): """Return whether row is outdated. - A row is considered outdated if it has "version" and "highest_version" - data and in the internal data structure, and they are not of an - equal value. + A row is considered outdated if it has no "version" or the "isOutdated" + value is True. """ def outdated(node): version = node.get("version", None) - highest = node.get("highest_version", None) # Always allow indices that have no version data at all - if version is None and highest is None: + if version is None: return True # If either a version or highest is present but not the other @@ -508,9 +521,10 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel): if not self._hierarchy_view: # Skip this check if in hierarchy view, or the child item # node will be hidden even it's actually outdated. - if version is None or highest is None: + if version is None: return False - return version != highest + + return node.get("isOutdated", True) index = self.sourceModel().index(row, self.filterKeyColumn(), parent) From 7b5b2a980cf68afd3fa5e8051b0e15d9f88d913f Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 19 Mar 2024 23:56:54 +0100 Subject: [PATCH 02/13] Fix update to latest - it now updates to latest instead of hero version --- client/ayon_core/pipeline/load/utils.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/pipeline/load/utils.py b/client/ayon_core/pipeline/load/utils.py index f3d39800cd..66ead70c14 100644 --- a/client/ayon_core/pipeline/load/utils.py +++ b/client/ayon_core/pipeline/load/utils.py @@ -479,10 +479,15 @@ def update_container(container, version=-1): project_name, current_version["productId"] ) elif version == -1: - new_version = ayon_api.get_last_version_by_product_id( - project_name, current_version["productId"] - ) - + # TODO: Use `ayon_api.get_last_version_by_product_id` when fixed + # to not return hero versions instead of the last version + new_version = next(ayon_api.get_versions( + project_name, + product_ids=[current_version["productId"]], + standard=True, + hero=False, + latest=True, + ), None) else: new_version = ayon_api.get_version_by_name( project_name, version, current_version["productId"] From 7f83a62192bb8f52018b570105f984804d853011 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Mar 2024 09:56:23 +0100 Subject: [PATCH 03/13] Revert "Fix update to latest - it now updates to latest instead of hero version" This reverts commit 7b5b2a980cf68afd3fa5e8051b0e15d9f88d913f. --- client/ayon_core/pipeline/load/utils.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/client/ayon_core/pipeline/load/utils.py b/client/ayon_core/pipeline/load/utils.py index 66ead70c14..f3d39800cd 100644 --- a/client/ayon_core/pipeline/load/utils.py +++ b/client/ayon_core/pipeline/load/utils.py @@ -479,15 +479,10 @@ def update_container(container, version=-1): project_name, current_version["productId"] ) elif version == -1: - # TODO: Use `ayon_api.get_last_version_by_product_id` when fixed - # to not return hero versions instead of the last version - new_version = next(ayon_api.get_versions( - project_name, - product_ids=[current_version["productId"]], - standard=True, - hero=False, - latest=True, - ), None) + new_version = ayon_api.get_last_version_by_product_id( + project_name, current_version["productId"] + ) + else: new_version = ayon_api.get_version_by_name( project_name, version, current_version["productId"] From a71ea3a3e3318d69811dd00a2b257ceeb5ebc30e Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Mar 2024 09:58:07 +0100 Subject: [PATCH 04/13] Use more specific api call --- client/ayon_core/tools/sceneinventory/model.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index 92591206fb..b9b18b339e 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -293,14 +293,11 @@ class InventoryModel(TreeModel): # Query the highest available version so the model can know # whether current version is currently up-to-date. - highest_versions = ayon_api.get_versions( + highest_versions = ayon_api.get_last_versions( project_name, product_ids={ group["version"]["productId"] for group in grouped.values() }, - latest=True, - standard=True, - hero=False, fields=["productId", "version"] ) highest_version_by_product_id = { From bb5f83f6c4c49e1bf7086debc052d2ffe6e5bcb4 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Mar 2024 10:15:01 +0100 Subject: [PATCH 05/13] Refactor `ayon_api.get_last_versions` already returns `dict` by `productId` --- client/ayon_core/tools/sceneinventory/model.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index b9b18b339e..9c4d080470 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -293,16 +293,17 @@ class InventoryModel(TreeModel): # Query the highest available version so the model can know # whether current version is currently up-to-date. - highest_versions = ayon_api.get_last_versions( + highest_version_by_product_id = ayon_api.get_last_versions( project_name, product_ids={ group["version"]["productId"] for group in grouped.values() }, fields=["productId", "version"] ) + # Map value to `version` key highest_version_by_product_id = { - version["productId"]: version["version"] - for version in highest_versions + product_id: version["version"] + for product_id, version in highest_version_by_product_id.items() } for repre_id, group_dict in sorted(grouped.items()): From 88e81cca22a257e20330c5ba96092a80387d5492 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 20 Mar 2024 10:40:42 +0100 Subject: [PATCH 06/13] Remove unused import --- client/ayon_core/tools/sceneinventory/model.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index 9c4d080470..5f8b1ee81c 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -8,10 +8,7 @@ import ayon_api from qtpy import QtCore, QtGui import qtawesome -from ayon_core.pipeline import ( - get_current_project_name, - HeroVersionType, -) +from ayon_core.pipeline import get_current_project_name from ayon_core.style import get_default_entity_icon_color from ayon_core.tools.utils import get_qt_icon from ayon_core.tools.utils.models import TreeModel, Item From b8d1377904d4f830145b53dc8ad4d8ef1b3a1c3a Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 14:35:16 +0100 Subject: [PATCH 07/13] Do not consider hero versions outdated ever --- client/ayon_core/tools/sceneinventory/model.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index 5f8b1ee81c..befd0f5ab5 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -322,15 +322,15 @@ class InventoryModel(TreeModel): group_node["representation"] = repre_id group_node["version"] = version_entity["version"] - # We check against `abs(version)` because we allow a hero version - # which is represented by a negative number to also count as - # latest version - # If a hero version for whatever reason does not match the latest - # positive version number, we also consider it outdated - group_node["isOutdated"] = ( - abs(version_entity["version"]) != - highest_version_by_product_id.get(version_entity["productId"]) - ) + # Check if the version is outdated. If the version is below 0 it + # is a hero version and will never be considered outdated + is_outdated = False + if version_entity["version"] >= 0: + last_version = highest_version_by_product_id.get( + version_entity["productId"]) + if last_version is not None: + is_outdated = version_entity["version"] != last_version + group_node["isOutdated"] = is_outdated group_node["productType"] = product_type or "" group_node["productTypeIcon"] = product_type_icon From ccb00be0b3428a25d91a88956136cc6f7756af2a Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 15:11:30 +0100 Subject: [PATCH 08/13] Update client/ayon_core/tools/sceneinventory/model.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/tools/sceneinventory/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index befd0f5ab5..14379664c6 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -295,7 +295,7 @@ class InventoryModel(TreeModel): product_ids={ group["version"]["productId"] for group in grouped.values() }, - fields=["productId", "version"] + fields={"productId", "version"} ) # Map value to `version` key highest_version_by_product_id = { From 5d9fe5d86f82556ee9aa7e2be01a4fb732590cb4 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 15:12:52 +0100 Subject: [PATCH 09/13] Use `HeroVersionType` instead of negative version number check --- client/ayon_core/tools/sceneinventory/model.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index befd0f5ab5..c7f20a974d 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -8,7 +8,10 @@ import ayon_api from qtpy import QtCore, QtGui import qtawesome -from ayon_core.pipeline import get_current_project_name +from ayon_core.pipeline import ( + get_current_project_name, + HeroVersionType, +) from ayon_core.style import get_default_entity_icon_color from ayon_core.tools.utils import get_qt_icon from ayon_core.tools.utils.models import TreeModel, Item @@ -320,12 +323,17 @@ class InventoryModel(TreeModel): repre_entity["name"] ) group_node["representation"] = repre_id - group_node["version"] = version_entity["version"] - # Check if the version is outdated. If the version is below 0 it - # is a hero version and will never be considered outdated + # Detect hero version type + version = version_entity["version"] + if version < 0: + version = HeroVersionType(version) + group_node["version"] = version + + # Check if the version is outdated. + # Hero versions are never considered to be outdated. is_outdated = False - if version_entity["version"] >= 0: + if not isinstance(version, HeroVersionType): last_version = highest_version_by_product_id.get( version_entity["productId"]) if last_version is not None: From 910c79f886274d66e616229ad88afd90d3f5aa90 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 15:18:28 +0100 Subject: [PATCH 10/13] Remove redundant logic --- client/ayon_core/tools/sceneinventory/model.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index df251ef69e..8de74b978a 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -519,14 +519,6 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel): if version is None: return True - # If either a version or highest is present but not the other - # consider the item invalid. - if not self._hierarchy_view: - # Skip this check if in hierarchy view, or the child item - # node will be hidden even it's actually outdated. - if version is None: - return False - return node.get("isOutdated", True) index = self.sourceModel().index(row, self.filterKeyColumn(), parent) From e735c5dc723bc127eba840a03569e7e0c3db05e9 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 15:20:12 +0100 Subject: [PATCH 11/13] Simplify further --- client/ayon_core/tools/sceneinventory/model.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index 8de74b978a..dd5f369fed 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -513,12 +513,6 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel): """ def outdated(node): - version = node.get("version", None) - - # Always allow indices that have no version data at all - if version is None: - return True - return node.get("isOutdated", True) index = self.sourceModel().index(row, self.filterKeyColumn(), parent) From 11f5d9d5717aab775f05149bbb1c1ea99d32b48e Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 15:24:57 +0100 Subject: [PATCH 12/13] Fix docstring --- client/ayon_core/tools/sceneinventory/model.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/ayon_core/tools/sceneinventory/model.py b/client/ayon_core/tools/sceneinventory/model.py index dd5f369fed..330b174218 100644 --- a/client/ayon_core/tools/sceneinventory/model.py +++ b/client/ayon_core/tools/sceneinventory/model.py @@ -508,8 +508,7 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel): def _is_outdated(self, row, parent): """Return whether row is outdated. - A row is considered outdated if it has no "version" or the "isOutdated" - value is True. + A row is considered outdated if `isOutdated` data is true or not set. """ def outdated(node): From 44641bc63071bca836bf1079254028df5326dddd Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 25 Mar 2024 15:37:22 +0100 Subject: [PATCH 13/13] Fix displaying HeroVersionType in version delegate --- client/ayon_core/tools/utils/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/client/ayon_core/tools/utils/lib.py b/client/ayon_core/tools/utils/lib.py index 8bcfe8b985..4b7ca5425e 100644 --- a/client/ayon_core/tools/utils/lib.py +++ b/client/ayon_core/tools/utils/lib.py @@ -123,6 +123,7 @@ def paint_image_with_color(image, color): def format_version(value): """Formats integer to displayable version name""" + value = int(value) # convert e.g. HeroVersionType to its version value label = "v{0:03d}".format(abs(value)) if value < 0: return "[{}]".format(label)