From 85a7d2e24e3f712eea225cb5baac4ea236cdedbe Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 15:27:45 +0200
Subject: [PATCH 01/20] added more information about plugin to report
---
client/ayon_core/tools/publisher/models/publish.py | 8 +++++++-
.../tools/publisher/publish_report_viewer/report_items.py | 6 ++++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/client/ayon_core/tools/publisher/models/publish.py b/client/ayon_core/tools/publisher/models/publish.py
index ef207bfb79..42dcca7bb3 100644
--- a/client/ayon_core/tools/publisher/models/publish.py
+++ b/client/ayon_core/tools/publisher/models/publish.py
@@ -172,7 +172,7 @@ def get_report(
"crashed_file_paths": crashed_file_paths,
"id": uuid.uuid4().hex,
"created_at": now.isoformat(),
- "report_version": "1.0.1",
+ "report_version": "1.1.0",
}
def _add_plugin_data_item(self, plugin: pyblish.api.Plugin):
@@ -194,11 +194,17 @@ def _create_plugin_data_item(
if hasattr(plugin, "label"):
label = plugin.label
+ plugin_type = "instance" if plugin.__instanceEnabled__ else "context"
+
return {
"id": plugin.id,
"name": plugin.__name__,
"label": label,
"order": plugin.order,
+ "filepath": inspect.getfile(plugin),
+ "docstring": inspect.getdoc(plugin),
+ "plugin_type": plugin_type,
+ "families": list(plugin.families),
"targets": list(plugin.targets),
"instances_data": [],
"actions_data": [],
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/report_items.py b/client/ayon_core/tools/publisher/publish_report_viewer/report_items.py
index 206f999bac..cfc2fbfd67 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/report_items.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/report_items.py
@@ -13,6 +13,12 @@ def __init__(self, plugin_data):
self.skipped = plugin_data["skipped"]
self.passed = plugin_data["passed"]
+ # Introduced in report '1.1.0'
+ self.docstring = plugin_data.get("docstring")
+ self.filepath = plugin_data.get("filepath")
+ self.plugin_type = plugin_data.get("plugin_type")
+ self.families = plugin_data.get("families")
+
errored = False
for instance_data in plugin_data["instances_data"]:
for log_item in instance_data["logs"]:
From d0ea1a31b1562a0803f62fc8c040eb7bb47bf941 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 15:30:25 +0200
Subject: [PATCH 02/20] mark tab widget as active to avoid long loading time
---
.../publish_report_viewer/widgets.py | 103 +++++++++++++++---
1 file changed, 87 insertions(+), 16 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 61a52533ba..3e2c6adc8a 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -23,32 +23,73 @@
class PluginLoadReportModel(QtGui.QStandardItemModel):
- def set_report(self, report):
- parent = self.invisibleRootItem()
- parent.removeRows(0, parent.rowCount())
+ def __init__(self):
+ super().__init__()
+ self._traceback_by_filepath = {}
+ self._items_by_filepath = {}
+ self._is_active = True
+ self._need_refresh = False
+
+ def set_active(self, is_active):
+ if self._is_active is is_active:
+ return
+ self._is_active = is_active
+ self._update_items()
+ def set_report(self, report):
+ self._need_refresh = True
if report is None:
+ self._traceback_by_filepath.clear()
+ self._update_items()
+ return
+
+ filepaths = set(report.crashed_plugin_paths.keys())
+ to_remove = set(self._traceback_by_filepath) - filepaths
+ for filepath in filepaths:
+ self._traceback_by_filepath[filepath] = (
+ report.crashed_plugin_paths[filepath]
+ )
+
+ for filepath in to_remove:
+ self._traceback_by_filepath.pop(filepath)
+ self._update_items()
+
+ def _update_items(self):
+ if not self._is_active or not self._need_refresh:
+ return
+ parent = self.invisibleRootItem()
+ if not self._traceback_by_filepath:
+ parent.removeRows(0, parent.rowCount())
return
new_items = []
new_items_by_filepath = {}
- for filepath in report.crashed_plugin_paths.keys():
+ to_remove = (
+ set(self._items_by_filepath) - set(self._traceback_by_filepath)
+ )
+ for filepath in self._traceback_by_filepath:
+ if filepath in self._items_by_filepath:
+ continue
item = QtGui.QStandardItem(filepath)
new_items.append(item)
new_items_by_filepath[filepath] = item
+ self._items_by_filepath[filepath] = item
- if not new_items:
- return
+ if new_items:
+ parent.appendRows(new_items)
- parent.appendRows(new_items)
for filepath, item in new_items_by_filepath.items():
- traceback_txt = report.crashed_plugin_paths[filepath]
+ traceback_txt = self._traceback_by_filepath[filepath]
detail_item = QtGui.QStandardItem()
detail_item.setData(filepath, FILEPATH_ROLE)
detail_item.setData(traceback_txt, TRACEBACK_ROLE)
detail_item.setData(True, IS_DETAIL_ITEM_ROLE)
item.appendRow(detail_item)
+ for filepath in to_remove:
+ item = self._items_by_filepath.pop(filepath)
+ parent.removeRow(item.row())
+
class DetailWidget(QtWidgets.QTextEdit):
def __init__(self, text, *args, **kwargs):
@@ -95,10 +136,12 @@ def __init__(self, parent):
self._model = model
self._widgets_by_filepath = {}
- def _on_expand(self, index):
- for row in range(self._model.rowCount(index)):
- child_index = self._model.index(row, index.column(), index)
- self._create_widget(child_index)
+ def set_active(self, is_active):
+ self._model.set_active(is_active)
+
+ def set_report(self, report):
+ self._widgets_by_filepath = {}
+ self._model.set_report(report)
def showEvent(self, event):
super().showEvent(event)
@@ -108,6 +151,11 @@ def resizeEvent(self, event):
super().resizeEvent(event)
self._update_widgets_size_hints()
+ def _on_expand(self, index):
+ for row in range(self._model.rowCount(index)):
+ child_index = self._model.index(row, index.column(), index)
+ self._create_widget(child_index)
+
def _update_widgets_size_hints(self):
for item in self._widgets_by_filepath.values():
widget, index = item
@@ -136,10 +184,6 @@ def _create_widget(self, index):
self._view.setIndexWidget(index, widget)
self._widgets_by_filepath[filepath] = (widget, index)
- def set_report(self, report):
- self._widgets_by_filepath = {}
- self._model.set_report(report)
-
class ZoomPlainText(QtWidgets.QPlainTextEdit):
min_point_size = 1.0
@@ -229,6 +273,8 @@ def __init__(self, parent):
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(output_widget)
+ self._is_active = True
+ self._need_refresh = False
self._output_widget = output_widget
self._report_item = None
self._instance_filter = set()
@@ -237,21 +283,33 @@ def __init__(self, parent):
def clear(self):
self._output_widget.setPlainText("")
+ def set_active(self, is_active):
+ if self._is_active is is_active:
+ return
+ self._is_active = is_active
+ self._update_logs()
+
def set_report(self, report):
self._report_item = report
self._plugin_filter = set()
self._instance_filter = set()
+ self._need_refresh = True
self._update_logs()
def set_plugin_filter(self, plugin_filter):
self._plugin_filter = plugin_filter
+ self._need_refresh = True
self._update_logs()
def set_instance_filter(self, instance_filter):
self._instance_filter = instance_filter
+ self._need_refresh = True
self._update_logs()
def _update_logs(self):
+ if not self._is_active or not self._need_refresh:
+ return
+
if not self._report_item:
self._output_widget.setPlainText("")
return
@@ -422,6 +480,8 @@ def __init__(self, parent=None):
logs_text_widget = DetailsWidget(details_tab_widget)
plugin_load_report_widget = PluginLoadReportWidget(details_tab_widget)
+ plugin_load_report_widget.set_active(False)
+
details_tab_widget.addTab(logs_text_widget, "Logs")
details_tab_widget.addTab(plugin_load_report_widget, "Crashed plugins")
@@ -440,6 +500,7 @@ def __init__(self, parent=None):
layout.addWidget(middle_widget, 0)
layout.addWidget(details_widget, 1)
+ details_tab_widget.currentChanged.connect(self._on_tab_change)
instances_view.selectionModel().selectionChanged.connect(
self._on_instance_change
)
@@ -458,6 +519,7 @@ def __init__(self, parent=None):
details_popup_btn.clicked.connect(self._on_details_popup)
details_popup.closed.connect(self._on_popup_close)
+ self._current_tab_idx = 0
self._ignore_selection_changes = False
self._report_item = None
self._logs_text_widget = logs_text_widget
@@ -517,6 +579,15 @@ def set_report(self, report):
self._instances_view.expandAll()
self._plugins_view.expandAll()
+ def _on_tab_change(self, new_idx):
+ if self._current_tab_idx == new_idx:
+ return
+ old_widget = self._details_tab_widget.widget(self._current_tab_idx)
+ new_widget = self._details_tab_widget.widget(new_idx)
+ self._current_tab_idx = new_idx
+ old_widget.set_active(False)
+ new_widget.set_active(True)
+
def _on_instance_change(self, *_args):
if self._ignore_selection_changes:
return
From d073f15a7a8dbd8e9271459e210384c52963898b Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 15:30:43 +0200
Subject: [PATCH 03/20] added helper 'ElideLabel' widget to elide long text
---
client/ayon_core/tools/utils/__init__.py | 2 +
client/ayon_core/tools/utils/widgets.py | 64 ++++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/client/ayon_core/tools/utils/__init__.py b/client/ayon_core/tools/utils/__init__.py
index 4b5fbeaf67..1eada0c67a 100644
--- a/client/ayon_core/tools/utils/__init__.py
+++ b/client/ayon_core/tools/utils/__init__.py
@@ -5,6 +5,7 @@
ComboBox,
CustomTextComboBox,
PlaceholderLineEdit,
+ ElideLabel,
ExpandingTextEdit,
BaseClickableFrame,
ClickableFrame,
@@ -88,6 +89,7 @@
"ComboBox",
"CustomTextComboBox",
"PlaceholderLineEdit",
+ "ElideLabel",
"ExpandingTextEdit",
"BaseClickableFrame",
"ClickableFrame",
diff --git a/client/ayon_core/tools/utils/widgets.py b/client/ayon_core/tools/utils/widgets.py
index 28331fbc35..af85fc915e 100644
--- a/client/ayon_core/tools/utils/widgets.py
+++ b/client/ayon_core/tools/utils/widgets.py
@@ -104,6 +104,70 @@ def __init__(self, *args, **kwargs):
self.setPalette(filter_palette)
+class ElideLabel(QtWidgets.QLabel):
+ """Label which elide text.
+
+ By default, elide happens in middle. Can be changed with
+ 'set_elide_mode' method.
+ """
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.setSizePolicy(
+ QtWidgets.QSizePolicy.Expanding,
+ QtWidgets.QSizePolicy.Preferred
+ )
+ # Store text set during init
+ self._text = self.text()
+ # Define initial elide mode
+ self._elide_mode = QtCore.Qt.ElideMiddle
+ # Make sure that text of QLabel is empty
+ super().setText("")
+
+ def setText(self, text):
+ # Update private text attribute and force update
+ self._text = text
+ self.update()
+
+ def setWordWrap(self, word_wrap):
+ # Word wrap is not supported in 'ElideLabel'
+ if word_wrap:
+ raise ValueError("Word wrap is not supported in 'ElideLabel'.")
+
+ def set_set(self, text):
+ self.setText(text)
+
+ def set_elide_mode(self, elide_mode):
+ """Change elide type.
+
+ Args:
+ elide_mode: Possible elide type. Available in 'QtCore.Qt'
+ 'ElideLeft', 'ElideRight' and 'ElideMiddle'.
+
+ """
+ if elide_mode == QtCore.Qt.ElideNone:
+ raise ValueError(
+ "Invalid elide type. 'ElideNone' is not supported."
+ )
+
+ if elide_mode not in (
+ QtCore.Qt.ElideLeft,
+ QtCore.Qt.ElideRight,
+ QtCore.Qt.ElideMiddle,
+ ):
+ raise ValueError(f"Unknown value '{elide_mode}'")
+ self._elide_mode = elide_mode
+
+ def paintEvent(self, event):
+ super().paintEvent(event)
+
+ painter = QtGui.QPainter(self)
+ fm = painter.fontMetrics()
+ elided_line = fm.elidedText(
+ self._text, self._elide_mode, self.width()
+ )
+ painter.drawText(QtCore.QPoint(0, fm.ascent()), elided_line)
+
+
class ExpandingTextEdit(QtWidgets.QTextEdit):
"""QTextEdit which does not have sroll area but expands height."""
From 2a0208a49406537aad756f7305b1cdc9a235e0eb Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 15:48:37 +0200
Subject: [PATCH 04/20] added plugin details widget
---
.../publish_report_viewer/widgets.py | 161 +++++++++++++++++-
1 file changed, 159 insertions(+), 2 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 3e2c6adc8a..1dc4eccce8 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -1,7 +1,7 @@
from math import ceil
from qtpy import QtWidgets, QtCore, QtGui
-from ayon_core.tools.utils import NiceCheckbox
+from ayon_core.tools.utils import NiceCheckbox, ElideLabel
# from ayon_core.tools.utils import DeselectableTreeView
from .constants import (
@@ -352,6 +352,155 @@ def _set_logs(self, logs):
self._output_widget.setPlainText(text)
+class PluginDetailsWidget(QtWidgets.QWidget):
+ def __init__(self, plugin_item, parent):
+ super().__init__(parent)
+
+ content_widget = QtWidgets.QWidget(self)
+
+ plugin_label_widget = QtWidgets.QLabel(content_widget)
+
+ plugin_type_label = QtWidgets.QLabel("Plugin type:")
+ plugin_type_widget = QtWidgets.QLabel(content_widget)
+
+ plugin_path_label = QtWidgets.QLabel("File Path:")
+ plugin_path_widget = ElideLabel(content_widget)
+
+ plugin_doc_widget = QtWidgets.QLabel(content_widget)
+ plugin_doc_widget.setWordWrap(True)
+
+ plugin_families_label = QtWidgets.QLabel("Families:")
+ plugin_families_widget = QtWidgets.QLabel(content_widget)
+ plugin_families_widget.setWordWrap(True)
+
+ plugin_label_widget.setText(plugin_item.label or plugin_item.name)
+ plugin_doc_widget.setText(plugin_item.docstring or "N/A")
+ plugin_type_widget.setText(plugin_item.plugin_type or "N/A")
+ plugin_path_widget.setText(plugin_item.filepath or "N/A")
+ plugin_path_widget.setToolTip(plugin_item.filepath or None)
+ plugin_families_widget.setText(str(plugin_item.families or "N/A"))
+
+ row = 0
+
+ content_layout = QtWidgets.QGridLayout(content_widget)
+ content_layout.setContentsMargins(0, 0, 0, 0)
+ content_layout.setColumnStretch(0, 0)
+ content_layout.setColumnStretch(1, 1)
+
+ content_layout.addWidget(plugin_label_widget, row, 0, 1, 2)
+ row += 1
+
+ content_layout.addWidget(plugin_doc_widget, row, 0, 1, 2)
+ row += 1
+
+ content_layout.addWidget(plugin_type_label, row, 0)
+ content_layout.addWidget(plugin_type_widget, row, 1)
+ row += 1
+
+ content_layout.addWidget(plugin_path_label, row, 0)
+ content_layout.addWidget(plugin_path_widget, row, 1)
+ row += 1
+
+ content_layout.addWidget(plugin_families_label, row, 0)
+ content_layout.addWidget(plugin_families_widget, row, 1)
+ row += 1
+
+ main_layout = QtWidgets.QVBoxLayout(self)
+ main_layout.setContentsMargins(0, 0, 0, 0)
+ main_layout.addWidget(content_widget, 0)
+
+
+class PluginsDetailsWidget(QtWidgets.QWidget):
+ def __init__(self, parent):
+ super().__init__(parent)
+
+ scroll_area = QtWidgets.QScrollArea(self)
+ scroll_area.setWidgetResizable(True)
+
+ content_widget = QtWidgets.QWidget(scroll_area)
+
+ scroll_area.setWidget(content_widget)
+
+ content_layout = QtWidgets.QVBoxLayout(content_widget)
+ content_layout.addStretch(1)
+
+ main_layout = QtWidgets.QVBoxLayout(self)
+ main_layout.setContentsMargins(0, 0, 0, 0)
+ main_layout.addWidget(scroll_area, 1)
+
+ self._scroll_area = scroll_area
+ self._content_layout = content_layout
+ self._content_widget = content_widget
+
+ self._widgets_by_plugin_id = {}
+
+ self._is_active = True
+ self._need_refresh = False
+
+ self._report_item = None
+ self._plugin_filter = set()
+ self._plugin_ids = None
+
+ def set_active(self, is_active):
+ if self._is_active is is_active:
+ return
+ self._is_active = is_active
+ self._update_widgets()
+
+ def set_plugin_filter(self, plugin_filter):
+ self._plugin_filter = plugin_filter
+ self._need_refresh = True
+ self._update_widgets()
+
+ def set_report(self, report):
+ self._report_item = report
+ self._plugin_ids = None
+ self._plugin_filter = set()
+ self._need_refresh = True
+ self._update_widgets()
+
+ def _get_plugin_ids(self):
+ if self._plugin_ids is not None:
+ return self._plugin_ids
+
+ # Clear layout and clear widgets
+ while self._content_layout.count():
+ self._content_layout.takeAt(0)
+
+ self._widgets_by_plugin_id.clear()
+
+ plugin_ids = []
+ if self._report_item is not None:
+ plugin_ids = list(self._report_item.plugins_id_order)
+ self._plugin_ids = plugin_ids
+ return plugin_ids
+
+ def _update_widgets(self):
+ if not self._is_active or not self._need_refresh:
+ return
+
+ self._need_refresh = False
+
+ is_new = len(self._widgets_by_plugin_id) == 0
+ for plugin_id in self._get_plugin_ids():
+ widget = self._widgets_by_plugin_id.get(plugin_id)
+ if is_new:
+ plugin_item = self._report_item.plugins_items_by_id[plugin_id]
+ widget = PluginDetailsWidget(plugin_item, self._content_widget)
+ self._widgets_by_plugin_id[plugin_id] = widget
+
+ widget.setVisible(
+ not self._plugin_filter
+ or plugin_id in self._plugin_filter
+ )
+
+ if is_new:
+ self._content_layout.addWidget(widget, 0)
+
+ if is_new:
+ self._content_layout.addStretch(1)
+
+
class DeselectableTreeView(QtWidgets.QTreeView):
"""A tree view that deselects on clicking on an empty area in the view"""
@@ -479,11 +628,16 @@ def __init__(self, parent=None):
logs_text_widget = DetailsWidget(details_tab_widget)
plugin_load_report_widget = PluginLoadReportWidget(details_tab_widget)
+ plugins_details_widget = PluginsDetailsWidget(details_tab_widget)
plugin_load_report_widget.set_active(False)
+ plugins_details_widget.set_active(False)
details_tab_widget.addTab(logs_text_widget, "Logs")
- details_tab_widget.addTab(plugin_load_report_widget, "Crashed plugins")
+ details_tab_widget.addTab(plugins_details_widget, "Plugins Details")
+ details_tab_widget.addTab(
+ plugin_load_report_widget, "Crashed plugins"
+ )
middle_widget = QtWidgets.QWidget(self)
middle_layout = QtWidgets.QGridLayout(middle_widget)
@@ -524,6 +678,7 @@ def __init__(self, parent=None):
self._report_item = None
self._logs_text_widget = logs_text_widget
self._plugin_load_report_widget = plugin_load_report_widget
+ self._plugins_details_widget = plugins_details_widget
self._removed_instances_check = removed_instances_check
self._instances_view = instances_view
@@ -573,6 +728,7 @@ def set_report(self, report):
self._plugins_model.set_report(report)
self._logs_text_widget.set_report(report)
self._plugin_load_report_widget.set_report(report)
+ self._plugins_details_widget.set_report(report)
self._ignore_selection_changes = False
@@ -609,6 +765,7 @@ def _on_plugin_change(self, *_args):
plugin_ids.add(index.data(ITEM_ID_ROLE))
self._logs_text_widget.set_plugin_filter(plugin_ids)
+ self._plugins_details_widget.set_plugin_filter(plugin_ids)
def _on_skipped_plugin_check(self):
self._plugins_proxy.set_ignore_skipped(
From f65cf0325bc62f53147074c8206a6a71a5fdf5d9 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 17:04:54 +0200
Subject: [PATCH 05/20] overall fixes of details widget
---
client/ayon_core/style/style.css | 12 +++
.../publish_report_viewer/widgets.py | 88 ++++++++++++-------
2 files changed, 69 insertions(+), 31 deletions(-)
diff --git a/client/ayon_core/style/style.css b/client/ayon_core/style/style.css
index 607fd1fa31..c8ba2ba8f2 100644
--- a/client/ayon_core/style/style.css
+++ b/client/ayon_core/style/style.css
@@ -1231,6 +1231,18 @@ ValidationArtistMessage QLabel {
background: transparent;
}
+#PluginDetailsContent {
+ background: {color:bg-inputs};
+ border-radius: 0.2em;
+}
+#PluginDetailsContent #PluginLabel {
+ font-size: 14pt;
+ font-weight: bold;
+}
+#PluginDetailsContent #PluginFormLabel {
+ font-weight: bold;
+}
+
CreateNextPageOverlay {
font-size: 32pt;
}
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 1dc4eccce8..263ca0464a 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -356,46 +356,66 @@ class PluginDetailsWidget(QtWidgets.QWidget):
def __init__(self, plugin_item, parent):
super().__init__(parent)
- content_widget = QtWidgets.QWidget(self)
+ content_widget = QtWidgets.QFrame(self)
+ content_widget.setObjectName("PluginDetailsContent")
plugin_label_widget = QtWidgets.QLabel(content_widget)
-
- plugin_type_label = QtWidgets.QLabel("Plugin type:")
- plugin_type_widget = QtWidgets.QLabel(content_widget)
+ plugin_label_widget.setObjectName("PluginLabel")
+ plugin_label_widget.setTextInteractionFlags(
+ QtCore.Qt.TextBrowserInteraction
+ )
plugin_path_label = QtWidgets.QLabel("File Path:")
plugin_path_widget = ElideLabel(content_widget)
-
- plugin_doc_widget = QtWidgets.QLabel(content_widget)
- plugin_doc_widget.setWordWrap(True)
+ plugin_path_widget.set_elide_mode(QtCore.Qt.ElideLeft)
plugin_families_label = QtWidgets.QLabel("Families:")
plugin_families_widget = QtWidgets.QLabel(content_widget)
+ plugin_families_widget.setTextInteractionFlags(
+ QtCore.Qt.TextBrowserInteraction
+ )
plugin_families_widget.setWordWrap(True)
- plugin_label_widget.setText(plugin_item.label or plugin_item.name)
- plugin_doc_widget.setText(plugin_item.docstring or "N/A")
- plugin_type_widget.setText(plugin_item.plugin_type or "N/A")
+ for label_widget in (
+ plugin_path_label,
+ plugin_families_label,
+ ):
+ label_widget.setObjectName("PluginFormLabel")
+
+ plugin_doc_widget = QtWidgets.QLabel(content_widget)
+ plugin_doc_widget.setWordWrap(True)
+ plugin_doc_widget.setTextInteractionFlags(
+ QtCore.Qt.TextBrowserInteraction
+ )
+
+ plugin_label = plugin_item.label or plugin_item.name
+ if plugin_item.plugin_type:
+ plugin_label += " ({})".format(
+ plugin_item.plugin_type.capitalize()
+ )
+ plugin_label_widget.setText(plugin_label)
+ # plugin_type_widget.setText(plugin_item.plugin_type or "N/A")
plugin_path_widget.setText(plugin_item.filepath or "N/A")
plugin_path_widget.setToolTip(plugin_item.filepath or None)
plugin_families_widget.setText(str(plugin_item.families or "N/A"))
+ plugin_doc_widget.setText(plugin_item.docstring or "N/A")
row = 0
content_layout = QtWidgets.QGridLayout(content_widget)
- content_layout.setContentsMargins(0, 0, 0, 0)
+ content_layout.setContentsMargins(8, 8, 8, 8)
content_layout.setColumnStretch(0, 0)
content_layout.setColumnStretch(1, 1)
content_layout.addWidget(plugin_label_widget, row, 0, 1, 2)
row += 1
- content_layout.addWidget(plugin_doc_widget, row, 0, 1, 2)
- row += 1
-
- content_layout.addWidget(plugin_type_label, row, 0)
- content_layout.addWidget(plugin_type_widget, row, 1)
- row += 1
+ # Hide docstring if it is empty
+ if plugin_item.docstring:
+ content_layout.addWidget(plugin_doc_widget, row, 0, 1, 2)
+ row += 1
+ else:
+ plugin_doc_widget.setVisible(False)
content_layout.addWidget(plugin_path_label, row, 0)
content_layout.addWidget(plugin_path_widget, row, 1)
@@ -417,12 +437,19 @@ def __init__(self, parent):
scroll_area = QtWidgets.QScrollArea(self)
scroll_area.setWidgetResizable(True)
- content_widget = QtWidgets.QWidget(scroll_area)
+ scroll_content_widget = QtWidgets.QWidget(scroll_area)
- scroll_area.setWidget(content_widget)
+ scroll_area.setWidget(scroll_content_widget)
+
+ content_widget = QtWidgets.QWidget(scroll_content_widget)
content_layout = QtWidgets.QVBoxLayout(content_widget)
- content_layout.addStretch(1)
+ content_layout.setContentsMargins(0, 0, 0, 0)
+
+ scroll_content_layout = QtWidgets.QVBoxLayout(scroll_content_widget)
+ scroll_content_layout.setContentsMargins(0, 0, 0, 0)
+ scroll_content_layout.addWidget(content_widget, 0)
+ scroll_content_layout.addStretch(1)
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
@@ -433,6 +460,7 @@ def __init__(self, parent):
self._content_widget = content_widget
self._widgets_by_plugin_id = {}
+ self._stretch_item_index = 0
self._is_active = True
self._need_refresh = False
@@ -448,15 +476,15 @@ def set_active(self, is_active):
self._update_widgets()
def set_plugin_filter(self, plugin_filter):
- self._plugin_filter = plugin_filter
self._need_refresh = True
+ self._plugin_filter = plugin_filter
self._update_widgets()
def set_report(self, report):
- self._report_item = report
self._plugin_ids = None
self._plugin_filter = set()
self._need_refresh = True
+ self._report_item = report
self._update_widgets()
def _get_plugin_ids(self):
@@ -465,7 +493,11 @@ def _get_plugin_ids(self):
# Clear layout and clear widgets
while self._content_layout.count():
- self._content_layout.takeAt(0)
+ item = self._content_layout.takeAt(0)
+ widget = item.widget()
+ if widget:
+ widget.setVisible(False)
+ widget.deleteLater()
self._widgets_by_plugin_id.clear()
@@ -481,25 +513,19 @@ def _update_widgets(self):
self._need_refresh = False
- is_new = len(self._widgets_by_plugin_id) == 0
for plugin_id in self._get_plugin_ids():
widget = self._widgets_by_plugin_id.get(plugin_id)
- if is_new:
+ if widget is None:
plugin_item = self._report_item.plugins_items_by_id[plugin_id]
widget = PluginDetailsWidget(plugin_item, self._content_widget)
self._widgets_by_plugin_id[plugin_id] = widget
+ self._content_layout.addWidget(widget, 0)
widget.setVisible(
not self._plugin_filter
or plugin_id in self._plugin_filter
)
- if is_new:
- self._content_layout.addWidget(widget, 0)
-
- if is_new:
- self._content_layout.addStretch(1)
-
class DeselectableTreeView(QtWidgets.QTreeView):
"""A tree view that deselects on clicking on an empty area in the view"""
From f16cb1f4e137fa0b20fd18e06472bbf74b2735b7 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 17:05:09 +0200
Subject: [PATCH 06/20] added option to copy text from ElideLabel
---
client/ayon_core/tools/utils/widgets.py | 36 +++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/client/ayon_core/tools/utils/widgets.py b/client/ayon_core/tools/utils/widgets.py
index af85fc915e..e58333a07d 100644
--- a/client/ayon_core/tools/utils/widgets.py
+++ b/client/ayon_core/tools/utils/widgets.py
@@ -107,8 +107,11 @@ def __init__(self, *args, **kwargs):
class ElideLabel(QtWidgets.QLabel):
"""Label which elide text.
- By default, elide happens in middle. Can be changed with
+ By default, elide happens on right side. Can be changed with
'set_elide_mode' method.
+
+ It is not possible to use other features of QLabel like word wrap or
+ interactive text. This is a simple label which elide text.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -119,7 +122,7 @@ def __init__(self, *args, **kwargs):
# Store text set during init
self._text = self.text()
# Define initial elide mode
- self._elide_mode = QtCore.Qt.ElideMiddle
+ self._elide_mode = QtCore.Qt.ElideRight
# Make sure that text of QLabel is empty
super().setText("")
@@ -133,6 +136,30 @@ def setWordWrap(self, word_wrap):
if word_wrap:
raise ValueError("Word wrap is not supported in 'ElideLabel'.")
+ def contextMenuEvent(self, event):
+ menu = self.create_context_menu(event.pos())
+ if menu is None:
+ event.ignore()
+ return
+ event.accept()
+ menu.setAttribute(QtCore.Qt.WA_DeleteOnClose)
+ menu.popup(event.globalPos())
+
+ def create_context_menu(self, pos):
+ if not self._text:
+ return None
+ menu = QtWidgets.QMenu(self)
+
+ # Copy text action
+ copy_action = menu.addAction("Copy")
+ copy_action.setObjectName("edit-copy")
+ icon = QtGui.QIcon.fromTheme("edit-copy")
+ if not icon.isNull():
+ copy_action.setIcon(icon)
+
+ copy_action.triggered.connect(self._on_copy_text)
+ return menu
+
def set_set(self, text):
self.setText(text)
@@ -156,6 +183,7 @@ def set_elide_mode(self, elide_mode):
):
raise ValueError(f"Unknown value '{elide_mode}'")
self._elide_mode = elide_mode
+ self.update()
def paintEvent(self, event):
super().paintEvent(event)
@@ -167,6 +195,10 @@ def paintEvent(self, event):
)
painter.drawText(QtCore.QPoint(0, fm.ascent()), elided_line)
+ def _on_copy_text(self):
+ clipboard = QtWidgets.QApplication.clipboard()
+ clipboard.setText(self._text)
+
class ExpandingTextEdit(QtWidgets.QTextEdit):
"""QTextEdit which does not have sroll area but expands height."""
From 3977a21820d0d6e5d8f547e95a0567b0f8e1450e Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 17:33:59 +0200
Subject: [PATCH 07/20] use only plugin's docstring
---
client/ayon_core/tools/publisher/models/publish.py | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/client/ayon_core/tools/publisher/models/publish.py b/client/ayon_core/tools/publisher/models/publish.py
index 42dcca7bb3..a973d47a11 100644
--- a/client/ayon_core/tools/publisher/models/publish.py
+++ b/client/ayon_core/tools/publisher/models/publish.py
@@ -195,14 +195,20 @@ def _create_plugin_data_item(
label = plugin.label
plugin_type = "instance" if plugin.__instanceEnabled__ else "context"
-
+ # Get docstring
+ # NOTE we do care only about docstring from the plugin so we can't
+ # use 'inspect.getdoc' which also looks for docstring in parent
+ # classes.
+ docstring = getattr(plugin, "__doc__", None)
+ if docstring:
+ docstring = inspect.cleandoc(docstring)
return {
"id": plugin.id,
"name": plugin.__name__,
"label": label,
"order": plugin.order,
"filepath": inspect.getfile(plugin),
- "docstring": inspect.getdoc(plugin),
+ "docstring": docstring,
"plugin_type": plugin_type,
"families": list(plugin.families),
"targets": list(plugin.targets),
From cf68742129e89f929793c22255a72ee2f84d2105 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 17:34:20 +0200
Subject: [PATCH 08/20] added class name and order
---
.../publish_report_viewer/widgets.py | 74 ++++++++++++-------
1 file changed, 47 insertions(+), 27 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 263ca0464a..a403bd06fc 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -1,7 +1,7 @@
from math import ceil
from qtpy import QtWidgets, QtCore, QtGui
-from ayon_core.tools.utils import NiceCheckbox, ElideLabel
+from ayon_core.tools.utils import NiceCheckbox, ElideLabel, SeparatorWidget
# from ayon_core.tools.utils import DeselectableTreeView
from .constants import (
@@ -361,51 +361,66 @@ def __init__(self, plugin_item, parent):
plugin_label_widget = QtWidgets.QLabel(content_widget)
plugin_label_widget.setObjectName("PluginLabel")
- plugin_label_widget.setTextInteractionFlags(
- QtCore.Qt.TextBrowserInteraction
- )
- plugin_path_label = QtWidgets.QLabel("File Path:")
- plugin_path_widget = ElideLabel(content_widget)
- plugin_path_widget.set_elide_mode(QtCore.Qt.ElideLeft)
+ plugin_doc_widget = QtWidgets.QLabel(content_widget)
+ plugin_doc_widget.setWordWrap(True)
+
+ form_separator = SeparatorWidget(parent=content_widget)
plugin_families_label = QtWidgets.QLabel("Families:")
plugin_families_widget = QtWidgets.QLabel(content_widget)
- plugin_families_widget.setTextInteractionFlags(
- QtCore.Qt.TextBrowserInteraction
- )
plugin_families_widget.setWordWrap(True)
+ plugin_order_label = QtWidgets.QLabel("Order:")
+ plugin_order_widget = QtWidgets.QLabel(content_widget)
+
+ plugin_class_label = QtWidgets.QLabel("Class:")
+ plugin_class_widget = QtWidgets.QLabel(content_widget)
+
+ plugin_path_label = QtWidgets.QLabel("File Path:")
+ plugin_path_widget = ElideLabel(content_widget)
+ plugin_path_widget.set_elide_mode(QtCore.Qt.ElideLeft)
+
+ # Set interaction flags
+ for label_widget in (
+ plugin_label_widget,
+ plugin_families_widget,
+ plugin_order_widget,
+ plugin_class_widget,
+ plugin_doc_widget,
+ ):
+ label_widget.setTextInteractionFlags(
+ QtCore.Qt.TextBrowserInteraction
+ )
+
+ # Change style of form labels
for label_widget in (
- plugin_path_label,
plugin_families_label,
+ plugin_order_label,
+ plugin_class_label,
+ plugin_path_label,
):
label_widget.setObjectName("PluginFormLabel")
- plugin_doc_widget = QtWidgets.QLabel(content_widget)
- plugin_doc_widget.setWordWrap(True)
- plugin_doc_widget.setTextInteractionFlags(
- QtCore.Qt.TextBrowserInteraction
- )
-
plugin_label = plugin_item.label or plugin_item.name
if plugin_item.plugin_type:
plugin_label += " ({})".format(
plugin_item.plugin_type.capitalize()
)
plugin_label_widget.setText(plugin_label)
- # plugin_type_widget.setText(plugin_item.plugin_type or "N/A")
+ plugin_doc_widget.setText(plugin_item.docstring or "N/A")
+ plugin_families_widget.setText(str(plugin_item.families or "N/A"))
+ plugin_order_widget.setText(str(plugin_item.order or "N/A"))
+ plugin_class_widget.setText(plugin_item.name or "N/A")
plugin_path_widget.setText(plugin_item.filepath or "N/A")
+ # Show full path in tooltip
plugin_path_widget.setToolTip(plugin_item.filepath or None)
- plugin_families_widget.setText(str(plugin_item.families or "N/A"))
- plugin_doc_widget.setText(plugin_item.docstring or "N/A")
-
- row = 0
content_layout = QtWidgets.QGridLayout(content_widget)
content_layout.setContentsMargins(8, 8, 8, 8)
content_layout.setColumnStretch(0, 0)
content_layout.setColumnStretch(1, 1)
+ row = 0
content_layout.addWidget(plugin_label_widget, row, 0, 1, 2)
row += 1
@@ -417,13 +432,18 @@ def __init__(self, plugin_item, parent):
else:
plugin_doc_widget.setVisible(False)
- content_layout.addWidget(plugin_path_label, row, 0)
- content_layout.addWidget(plugin_path_widget, row, 1)
+ content_layout.addWidget(form_separator, row, 0, 1, 2)
row += 1
- content_layout.addWidget(plugin_families_label, row, 0)
- content_layout.addWidget(plugin_families_widget, row, 1)
- row += 1
+ for label_widget, value_widget in (
+ (plugin_families_label, plugin_families_widget),
+ (plugin_class_label, plugin_class_widget),
+ (plugin_order_label, plugin_order_widget),
+ (plugin_path_label, plugin_path_widget),
+ ):
+ content_layout.addWidget(label_widget, row, 0)
+ content_layout.addWidget(value_widget, row, 1)
+ row += 1
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
From 3bda6370e3049a163b8f642d45d4e71e32b0b51f Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 17:34:29 +0200
Subject: [PATCH 09/20] added spacing to widgets
---
.../ayon_core/tools/publisher/publish_report_viewer/widgets.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index a403bd06fc..de24e1f653 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -465,6 +465,7 @@ def __init__(self, parent):
content_layout = QtWidgets.QVBoxLayout(content_widget)
content_layout.setContentsMargins(0, 0, 0, 0)
+ content_layout.setSpacing(10)
scroll_content_layout = QtWidgets.QVBoxLayout(scroll_content_widget)
scroll_content_layout.setContentsMargins(0, 0, 0, 0)
From 08e0eb03b631dbea795ccc8745a6564ea63ab803 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 17:34:44 +0200
Subject: [PATCH 10/20] remove bold style from labels
---
client/ayon_core/style/style.css | 3 ---
1 file changed, 3 deletions(-)
diff --git a/client/ayon_core/style/style.css b/client/ayon_core/style/style.css
index c8ba2ba8f2..2e3ea53fb3 100644
--- a/client/ayon_core/style/style.css
+++ b/client/ayon_core/style/style.css
@@ -1239,9 +1239,6 @@ ValidationArtistMessage QLabel {
font-size: 14pt;
font-weight: bold;
}
-#PluginDetailsContent #PluginFormLabel {
- font-weight: bold;
-}
CreateNextPageOverlay {
font-size: 32pt;
From c50badd51df6dac2987c46111900f7b07d620b70 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Thu, 8 Aug 2024 18:34:18 +0200
Subject: [PATCH 11/20] added process time
---
.../publish_report_viewer/report_items.py | 3 ++
.../publish_report_viewer/widgets.py | 51 ++++++++++++++-----
2 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/report_items.py b/client/ayon_core/tools/publisher/publish_report_viewer/report_items.py
index cfc2fbfd67..a3c5a7a2fd 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/report_items.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/report_items.py
@@ -20,7 +20,9 @@ def __init__(self, plugin_data):
self.families = plugin_data.get("families")
errored = False
+ process_time = 0.0
for instance_data in plugin_data["instances_data"]:
+ process_time += instance_data["process_time"]
for log_item in instance_data["logs"]:
errored = log_item["type"] == "error"
if errored:
@@ -28,6 +30,7 @@ def __init__(self, plugin_data):
if errored:
break
+ self.process_time = process_time
self.errored = errored
@property
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index de24e1f653..c58fae5c87 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -22,6 +22,21 @@
IS_DETAIL_ITEM_ROLE = QtCore.Qt.UserRole + 3
+def get_pretty_milliseconds(value):
+ if value < 1000:
+ return f"{value:.3f}ms"
+ value /= 1000
+ if value < 60:
+ return f"{value:.2f}s"
+ seconds = int(value % 60)
+ value /= 60
+ if value < 60:
+ return f"{value:.2f}m {seconds:.2f}s"
+ minutes = int(value % 60)
+ value /= 60
+ return f"{value:.2f}h {minutes:.2f}m"
+
+
class PluginLoadReportModel(QtGui.QStandardItemModel):
def __init__(self):
super().__init__()
@@ -367,27 +382,31 @@ def __init__(self, plugin_item, parent):
form_separator = SeparatorWidget(parent=content_widget)
- plugin_families_label = QtWidgets.QLabel("Families:")
- plugin_families_widget = QtWidgets.QLabel(content_widget)
- plugin_families_widget.setWordWrap(True)
+ plugin_class_label = QtWidgets.QLabel("Class:")
+ plugin_class_widget = QtWidgets.QLabel(content_widget)
plugin_order_label = QtWidgets.QLabel("Order:")
plugin_order_widget = QtWidgets.QLabel(content_widget)
- plugin_class_label = QtWidgets.QLabel("Class:")
- plugin_class_widget = QtWidgets.QLabel(content_widget)
+ plugin_families_label = QtWidgets.QLabel("Families:")
+ plugin_families_widget = QtWidgets.QLabel(content_widget)
+ plugin_families_widget.setWordWrap(True)
plugin_path_label = QtWidgets.QLabel("File Path:")
plugin_path_widget = ElideLabel(content_widget)
plugin_path_widget.set_elide_mode(QtCore.Qt.ElideLeft)
+ plugin_time_label = QtWidgets.QLabel("Time:")
+ plugin_time_widget = QtWidgets.QLabel(content_widget)
+
# Set interaction flags
for label_widget in (
plugin_label_widget,
- plugin_families_widget,
- plugin_order_widget,
- plugin_class_widget,
plugin_doc_widget,
+ plugin_class_widget,
+ plugin_order_widget,
+ plugin_families_widget,
+ plugin_time_widget,
):
label_widget.setTextInteractionFlags(
QtCore.Qt.TextBrowserInteraction
@@ -395,10 +414,11 @@ def __init__(self, plugin_item, parent):
# Change style of form labels
for label_widget in (
- plugin_families_label,
- plugin_order_label,
plugin_class_label,
+ plugin_order_label,
+ plugin_families_label,
plugin_path_label,
+ plugin_time_label,
):
label_widget.setObjectName("PluginFormLabel")
@@ -409,12 +429,14 @@ def __init__(self, plugin_item, parent):
)
plugin_label_widget.setText(plugin_label)
plugin_doc_widget.setText(plugin_item.docstring or "N/A")
- plugin_families_widget.setText(str(plugin_item.families or "N/A"))
- plugin_order_widget.setText(str(plugin_item.order or "N/A"))
plugin_class_widget.setText(plugin_item.name or "N/A")
+ plugin_order_widget.setText(str(plugin_item.order or "N/A"))
+ plugin_families_widget.setText(str(plugin_item.families or "N/A"))
plugin_path_widget.setText(plugin_item.filepath or "N/A")
- # Show full path in tooltip
plugin_path_widget.setToolTip(plugin_item.filepath or None)
+ plugin_time_widget.setText(
+ get_pretty_milliseconds(plugin_item.process_time)
+ )
content_layout = QtWidgets.QGridLayout(content_widget)
content_layout.setContentsMargins(8, 8, 8, 8)
@@ -436,10 +458,11 @@ def __init__(self, plugin_item, parent):
row += 1
for label_widget, value_widget in (
- (plugin_families_label, plugin_families_widget),
(plugin_class_label, plugin_class_widget),
(plugin_order_label, plugin_order_widget),
+ (plugin_families_label, plugin_families_widget),
(plugin_path_label, plugin_path_widget),
+ (plugin_time_label, plugin_time_widget),
):
content_layout.addWidget(label_widget, row, 0)
content_layout.addWidget(value_widget, row, 1)
From e54e639b9dd7473d590488fc9506ce3de2f21e45 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 14:39:23 +0200
Subject: [PATCH 12/20] don't show spent time if did not run yet
---
.../tools/publisher/publish_report_viewer/widgets.py | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 029ce300a8..8227008ff3 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -442,9 +442,14 @@ def __init__(self, plugin_item, parent):
plugin_families_widget.setText(str(plugin_item.families or "N/A"))
plugin_path_widget.setText(plugin_item.filepath or "N/A")
plugin_path_widget.setToolTip(plugin_item.filepath or None)
- plugin_time_widget.setText(
- get_pretty_milliseconds(plugin_item.process_time)
- )
+ if plugin_item.passed:
+ time_label = get_pretty_milliseconds(plugin_item.process_time)
+ elif plugin_item.skipped:
+ time_label = "Skipped plugin"
+ else:
+ time_label = "Not started"
+
+ plugin_time_widget.setText(time_label)
content_layout = QtWidgets.QGridLayout(content_widget)
content_layout.setContentsMargins(8, 8, 8, 8)
From fd6c6eade49636dbb4604d25c02f235b3711512c Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 14:42:01 +0200
Subject: [PATCH 13/20] details widget is acknowledged about being active
---
.../tools/publisher/publish_report_viewer/widgets.py | 8 ++++++++
client/ayon_core/tools/publisher/window.py | 3 ++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 8227008ff3..af1a7e5281 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -817,6 +817,14 @@ def _on_plugin_view_clicked(self, index):
else:
self._plugins_view.expand(index)
+ def set_active(self, active):
+ for idx in range(self._details_tab_widget.count()):
+ widget = self._details_tab_widget.widget(idx)
+ widget.set_active(active and idx == self._current_tab_idx)
+
+ if not active:
+ self.close_details_popup()
+
def set_report_data(self, report_data):
report = PublishReport(report_data)
self.set_report(report)
diff --git a/client/ayon_core/tools/publisher/window.py b/client/ayon_core/tools/publisher/window.py
index 1218221420..0c6087b41d 100644
--- a/client/ayon_core/tools/publisher/window.py
+++ b/client/ayon_core/tools/publisher/window.py
@@ -687,13 +687,14 @@ def _on_create_overlay_button_click(self):
def _on_tab_change(self, old_tab, new_tab):
if old_tab == "details":
- self._publish_details_widget.close_details_popup()
+ self._publish_details_widget.set_active(False)
if new_tab == "details":
self._content_stacked_layout.setCurrentWidget(
self._publish_details_widget
)
self._update_publish_details_widget()
+ self._publish_details_widget.set_active(True)
elif new_tab == "report":
self._content_stacked_layout.setCurrentWidget(
From cf6cf0bf14eba836e575428e476baf99dda38dd1 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 14:54:55 +0200
Subject: [PATCH 14/20] move time label calculation above value changes
---
.../publisher/publish_report_viewer/widgets.py | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index af1a7e5281..b8ddb0ef54 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -435,6 +435,12 @@ def __init__(self, plugin_item, parent):
plugin_label += " ({})".format(
plugin_item.plugin_type.capitalize()
)
+
+ time_label = "Not started"
+ if plugin_item.passed:
+ time_label = get_pretty_milliseconds(plugin_item.process_time)
+ elif plugin_item.skipped:
+ time_label = "Skipped plugin"
plugin_label_widget.setText(plugin_label)
plugin_doc_widget.setText(plugin_item.docstring or "N/A")
plugin_class_widget.setText(plugin_item.name or "N/A")
@@ -442,13 +448,6 @@ def __init__(self, plugin_item, parent):
plugin_families_widget.setText(str(plugin_item.families or "N/A"))
plugin_path_widget.setText(plugin_item.filepath or "N/A")
plugin_path_widget.setToolTip(plugin_item.filepath or None)
- if plugin_item.passed:
- time_label = get_pretty_milliseconds(plugin_item.process_time)
- elif plugin_item.skipped:
- time_label = "Skipped plugin"
- else:
- time_label = "Not started"
-
plugin_time_widget.setText(time_label)
content_layout = QtWidgets.QGridLayout(content_widget)
From f2232f0af15dd6b87323a9d1f5c45fa78f5c7c0c Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 14:55:46 +0200
Subject: [PATCH 15/20] '0' order is not resolved as N/A
---
.../tools/publisher/publish_report_viewer/widgets.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index b8ddb0ef54..5e854ae945 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -441,10 +441,14 @@ def __init__(self, plugin_item, parent):
time_label = get_pretty_milliseconds(plugin_item.process_time)
elif plugin_item.skipped:
time_label = "Skipped plugin"
+ order = plugin_item.order
+ if order is None:
+ order = "N/A"
+
plugin_label_widget.setText(plugin_label)
plugin_doc_widget.setText(plugin_item.docstring or "N/A")
plugin_class_widget.setText(plugin_item.name or "N/A")
- plugin_order_widget.setText(str(plugin_item.order or "N/A"))
+ plugin_order_widget.setText(order)
plugin_families_widget.setText(str(plugin_item.families or "N/A"))
plugin_path_widget.setText(plugin_item.filepath or "N/A")
plugin_path_widget.setToolTip(plugin_item.filepath or None)
From 9fce774a7e545641ab0282e2f71e3e7512d3765d Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 14:56:08 +0200
Subject: [PATCH 16/20] families are joined with comma
---
.../tools/publisher/publish_report_viewer/widgets.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 5e854ae945..925547bc1a 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -441,6 +441,11 @@ def __init__(self, plugin_item, parent):
time_label = get_pretty_milliseconds(plugin_item.process_time)
elif plugin_item.skipped:
time_label = "Skipped plugin"
+
+ families = "N/A"
+ if plugin_item.families:
+ families = ", ".join(plugin_item.families)
+
order = plugin_item.order
if order is None:
order = "N/A"
@@ -449,7 +454,7 @@ def __init__(self, plugin_item, parent):
plugin_doc_widget.setText(plugin_item.docstring or "N/A")
plugin_class_widget.setText(plugin_item.name or "N/A")
plugin_order_widget.setText(order)
- plugin_families_widget.setText(str(plugin_item.families or "N/A"))
+ plugin_families_widget.setText(families)
plugin_path_widget.setText(plugin_item.filepath or "N/A")
plugin_path_widget.setToolTip(plugin_item.filepath or None)
plugin_time_widget.setText(time_label)
From 4eef7ecadd22185585e4cdb1e7107a69329c455a Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 14:57:18 +0200
Subject: [PATCH 17/20] hide content widget before adding widgets to it's
layout
---
.../tools/publisher/publish_report_viewer/widgets.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 925547bc1a..6441667264 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -578,6 +578,11 @@ def _update_widgets(self):
self._need_refresh = False
+ # Hide content widget before updating
+ # - add widgets to layout can happen without recalculating
+ # the layout and widget size hints
+ self._content_widget.setVisible(False)
+
for plugin_id in self._get_plugin_ids():
widget = self._widgets_by_plugin_id.get(plugin_id)
if widget is None:
@@ -591,6 +596,7 @@ def _update_widgets(self):
or plugin_id in self._plugin_filter
)
+ self._content_widget.setVisible(True)
class DeselectableTreeView(QtWidgets.QTreeView):
"""A tree view that deselects on clicking on an empty area in the view"""
From a819797f21a6a1f287fd7dde789eab457a7b7f05 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 14:58:25 +0200
Subject: [PATCH 18/20] don't show all details if nothing is selected
---
.../tools/publisher/publish_report_viewer/widgets.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index 6441667264..df6cd4b168 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -591,10 +591,7 @@ def _update_widgets(self):
self._widgets_by_plugin_id[plugin_id] = widget
self._content_layout.addWidget(widget, 0)
- widget.setVisible(
- not self._plugin_filter
- or plugin_id in self._plugin_filter
- )
+ widget.setVisible(plugin_id in self._plugin_filter)
self._content_widget.setVisible(True)
From 1e7be786eb69f2c0b265b4e7833aa2e5c097a72e Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 14:58:47 +0200
Subject: [PATCH 19/20] added label shown if nothing is selected
---
.../publish_report_viewer/widgets.py | 20 +++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index df6cd4b168..fa4127fe8b 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -505,6 +505,12 @@ def __init__(self, parent):
scroll_area.setWidget(scroll_content_widget)
+ empty_label = QtWidgets.QLabel(
+ "
Select plugins to view more information...",
+ scroll_content_widget
+ )
+ empty_label.setAlignment(QtCore.Qt.AlignCenter)
+
content_widget = QtWidgets.QWidget(scroll_content_widget)
content_layout = QtWidgets.QVBoxLayout(content_widget)
@@ -513,6 +519,7 @@ def __init__(self, parent):
scroll_content_layout = QtWidgets.QVBoxLayout(scroll_content_widget)
scroll_content_layout.setContentsMargins(0, 0, 0, 0)
+ scroll_content_layout.addWidget(empty_label, 0)
scroll_content_layout.addWidget(content_widget, 0)
scroll_content_layout.addStretch(1)
@@ -520,7 +527,10 @@ def __init__(self, parent):
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.addWidget(scroll_area, 1)
+ content_widget.setVisible(False)
+
self._scroll_area = scroll_area
+ self._empty_label = empty_label
self._content_layout = content_layout
self._content_widget = content_widget
@@ -583,6 +593,7 @@ def _update_widgets(self):
# the layout and widget size hints
self._content_widget.setVisible(False)
+ any_visible = False
for plugin_id in self._get_plugin_ids():
widget = self._widgets_by_plugin_id.get(plugin_id)
if widget is None:
@@ -591,9 +602,14 @@ def _update_widgets(self):
self._widgets_by_plugin_id[plugin_id] = widget
self._content_layout.addWidget(widget, 0)
- widget.setVisible(plugin_id in self._plugin_filter)
+ is_visible = plugin_id in self._plugin_filter
+ widget.setVisible(is_visible)
+ if is_visible:
+ any_visible = True
+
+ self._content_widget.setVisible(any_visible)
+ self._empty_label.setVisible(not any_visible)
- self._content_widget.setVisible(True)
class DeselectableTreeView(QtWidgets.QTreeView):
"""A tree view that deselects on clicking on an empty area in the view"""
From 7e4da0761d558bd42c9f0dcadbdb679d605f1699 Mon Sep 17 00:00:00 2001
From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
Date: Wed, 21 Aug 2024 15:00:07 +0200
Subject: [PATCH 20/20] order is converted to string
---
.../tools/publisher/publish_report_viewer/widgets.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
index fa4127fe8b..5fa1c04dc0 100644
--- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
+++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py
@@ -446,9 +446,9 @@ def __init__(self, plugin_item, parent):
if plugin_item.families:
families = ", ".join(plugin_item.families)
- order = plugin_item.order
- if order is None:
- order = "N/A"
+ order = "N/A"
+ if plugin_item.order is not None:
+ order = str(plugin_item.order)
plugin_label_widget.setText(plugin_label)
plugin_doc_widget.setText(plugin_item.docstring or "N/A")