added version tags filter

This commit is contained in:
Jakub Trllo 2025-06-11 15:55:02 +02:00
parent fb6386cb8f
commit 715031a9b5
4 changed files with 109 additions and 7 deletions

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import numbers
import uuid
from typing import Dict
@ -18,14 +20,22 @@ from .products_model import (
SYNC_REMOTE_SITE_AVAILABILITY,
)
STATUS_NAME_ROLE = QtCore.Qt.UserRole + 1
VERSION_ID_ROLE = QtCore.Qt.UserRole + 1
TASK_ID_ROLE = QtCore.Qt.UserRole + 2
STATUS_NAME_ROLE = QtCore.Qt.UserRole + 3
class VersionsModel(QtGui.QStandardItemModel):
def __init__(self):
super().__init__()
self._items_by_id = {}
self._tags_by_version_id = {}
def get_version_tags(self, version_id: str) -> set[str]:
tags = self._tags_by_version_id.get(version_id)
if tags is None:
tags = set()
return tags
def update_versions(self, version_items):
version_ids = {
@ -39,6 +49,7 @@ class VersionsModel(QtGui.QStandardItemModel):
item = self._items_by_id.pop(item_id)
root_item.removeRow(item.row())
tags_by_version_id = {}
for idx, version_item in enumerate(version_items):
version_id = version_item.version_id
@ -48,11 +59,14 @@ class VersionsModel(QtGui.QStandardItemModel):
item = QtGui.QStandardItem(label)
item.setData(version_id, QtCore.Qt.UserRole)
self._items_by_id[version_id] = item
item.setData(version_id, VERSION_ID_ROLE)
item.setData(version_item.status, STATUS_NAME_ROLE)
item.setData(version_item.task_id, TASK_ID_ROLE)
tags_by_version_id[version_id] = set(version_item.tags)
if item.row() != idx:
root_item.insertRow(idx, item)
self._tags_by_version_id = tags_by_version_id
class VersionsFilterModel(QtCore.QSortFilterProxyModel):
@ -60,22 +74,39 @@ class VersionsFilterModel(QtCore.QSortFilterProxyModel):
super().__init__()
self._status_filter = None
self._task_ids_filter = None
self._tags_filter = None
def filterAcceptsRow(self, row, parent):
index = None
if self._status_filter is not None:
if not self._status_filter:
return False
index = self.sourceModel().index(row, 0, parent)
if index is None:
index = self.sourceModel().index(row, 0, parent)
status = index.data(STATUS_NAME_ROLE)
if status not in self._status_filter:
return False
if self._task_ids_filter:
index = self.sourceModel().index(row, 0, parent)
if index is None:
index = self.sourceModel().index(row, 0, parent)
task_id = index.data(TASK_ID_ROLE)
if task_id not in self._task_ids_filter:
return False
if self._tags_filter is not None:
if not self._tags_filter:
return False
if index is None:
index = self.sourceModel().index(row, 0, parent)
version_id = index.data(VERSION_ID_ROLE)
model = self.sourceModel()
tags = model.get_version_tags(version_id)
if not tags & self._tags_filter:
return False
return True
def set_tasks_filter(self, task_ids):
@ -90,6 +121,12 @@ class VersionsFilterModel(QtCore.QSortFilterProxyModel):
self._status_filter = status_names
self.invalidateFilter()
def set_tags_filter(self, tags):
if self._tags_filter == tags:
return
self._tags_filter = tags
self.invalidateFilter()
class VersionComboBox(QtWidgets.QComboBox):
value_changed = QtCore.Signal(str, str)
@ -130,6 +167,13 @@ class VersionComboBox(QtWidgets.QComboBox):
if self.currentIndex() != 0:
self.setCurrentIndex(0)
def set_tags_filter(self, tags):
self._proxy_model.set_tags_filter(tags)
if self.count() == 0:
return
if self.currentIndex() != 0:
self.setCurrentIndex(0)
def all_versions_filtered_out(self):
if self._items_by_id:
return self.count() == 0
@ -173,6 +217,7 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate):
self._editor_by_id: Dict[str, VersionComboBox] = {}
self._task_ids_filter = None
self._statuses_filter = None
self._tags_filter = None
def displayText(self, value, locale):
if not isinstance(value, numbers.Integral):
@ -191,6 +236,13 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate):
for widget in self._editor_by_id.values():
widget.set_statuses_filter(status_names)
def set_tags_filter(self, tags):
if tags is not None:
tags = set(tags)
self._tags_filter = tags
for widget in self._editor_by_id.values():
widget.set_tags_filter(tags)
def paint(self, painter, option, index):
fg_color = index.data(QtCore.Qt.ForegroundRole)
if fg_color:

View file

@ -41,6 +41,7 @@ SYNC_ACTIVE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 30
SYNC_REMOTE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 31
STATUS_NAME_FILTER_ROLE = QtCore.Qt.UserRole + 32
VERSION_TAGS_FILTER_ROLE = QtCore.Qt.UserRole + 33
class ProductsModel(QtGui.QStandardItemModel):
@ -422,6 +423,10 @@ class ProductsModel(QtGui.QStandardItemModel):
version_item.status
for version_item in product_item.version_items.values()
}
tags = set()
for version_item in product_item.version_items.values():
tags |= set(version_item.tags)
if model_item is None:
product_id = product_item.product_id
model_item = QtGui.QStandardItem(product_item.product_name)
@ -440,6 +445,7 @@ class ProductsModel(QtGui.QStandardItemModel):
self._items_by_id[product_id] = model_item
model_item.setData("|".join(statuses), STATUS_NAME_FILTER_ROLE)
model_item.setData("|".join(tags), VERSION_TAGS_FILTER_ROLE)
model_item.setData(product_item.folder_label, FOLDER_LABEL_ROLE)
in_scene = 1 if product_item.product_in_scene else 0
model_item.setData(in_scene, PRODUCT_IN_SCENE_ROLE)

View file

@ -26,6 +26,7 @@ from .products_model import (
VERSION_STATUS_ICON_ROLE,
VERSION_THUMBNAIL_ID_ROLE,
STATUS_NAME_FILTER_ROLE,
VERSION_TAGS_FILTER_ROLE,
)
from .products_delegates import (
VersionDelegate,
@ -41,6 +42,7 @@ class ProductsProxyModel(RecursiveSortFilterProxyModel):
self._product_type_filters = None
self._statuses_filter = None
self._tags_filter = None
self._task_ids_filter = None
self._ascending_sort = True
@ -67,6 +69,12 @@ class ProductsProxyModel(RecursiveSortFilterProxyModel):
self._statuses_filter = statuses_filter
self.invalidateFilter()
def set_version_tags_filter(self, tags):
if self._tags_filter == tags:
return
self._tags_filter = tags
self.invalidateFilter()
def filterAcceptsRow(self, source_row, source_parent):
source_model = self.sourceModel()
index = source_model.index(source_row, 0, source_parent)
@ -83,6 +91,11 @@ class ProductsProxyModel(RecursiveSortFilterProxyModel):
):
return False
if not self._accept_row_by_role_value(
index, self._tags_filter, VERSION_TAGS_FILTER_ROLE
):
return False
return super().filterAcceptsRow(source_row, source_parent)
def _accept_task_ids_filter(self, index):
@ -102,9 +115,9 @@ class ProductsProxyModel(RecursiveSortFilterProxyModel):
if not filter_value:
return False
status_s = index.data(role)
for status in status_s.split("|"):
if status in filter_value:
value_s = index.data(role)
for value in value_s.split("|"):
if value in filter_value:
return True
return False
@ -290,6 +303,10 @@ class ProductsWidget(QtWidgets.QWidget):
self._version_delegate.set_statuses_filter(status_names)
self._products_proxy_model.set_statuses_filter(status_names)
def set_version_tags_filter(self, tags):
self._version_delegate.set_tags_filter(tags)
self._products_proxy_model.set_version_tags_filter(tags)
def set_product_type_filter(self, product_type_filters):
"""

View file

@ -424,6 +424,10 @@ class LoaderWindow(QtWidgets.QWidget):
status_names = self._search_bar.get_filter_value("statuses")
self._products_widget.set_statuses_filter(status_names)
elif filter_name == "version_tags":
version_tags = self._search_bar.get_filter_value("version_tags")
self._products_widget.set_version_tags_filter(version_tags)
def _on_tasks_selection_change(self, event):
self._products_widget.set_tasks_filter(event["task_ids"])
@ -483,6 +487,14 @@ class LoaderWindow(QtWidgets.QWidget):
status_items: list[StatusItem] = (
self._controller.get_project_status_items(project_name)
)
tags_by_entity_type = (
self._controller.get_available_tags_by_entity_type(project_name)
)
tag_items = self._controller.get_project_anatomy_tags(project_name)
tag_color_by_name = {
tag_item.name: tag_item.color
for tag_item in tag_items
}
filter_product_type_items = [
{
@ -503,6 +515,14 @@ class LoaderWindow(QtWidgets.QWidget):
}
for status_item in status_items
]
version_tags = [
{
"value": tag_name,
"color": tag_color_by_name.get(tag_name),
}
for tag_name in tags_by_entity_type.get("versions") or []
]
self._search_bar.set_search_items([
FilterDefinition(
@ -527,6 +547,13 @@ class LoaderWindow(QtWidgets.QWidget):
icon=None,
items=filter_status_items,
),
FilterDefinition(
name="version_tags",
title="Version tags",
filter_type="list",
icon=None,
items=version_tags,
),
])
def _on_folders_selection_changed(self, event):