Merge branch 'develop' into bugfix/AY_7222-fix_create_custom_dir

This commit is contained in:
robin@ynput.io 2024-12-11 11:02:12 -05:00
commit b4b3ec52eb
6 changed files with 175 additions and 37 deletions

View file

@ -2,6 +2,7 @@ import os
import re
import copy
import platform
from typing import Optional, Dict, Any
import ayon_api
@ -16,12 +17,12 @@ from ayon_core.pipeline.template_data import get_template_data
def get_workfile_template_key_from_context(
project_name,
folder_path,
task_name,
host_name,
project_settings=None
):
project_name: str,
folder_path: str,
task_name: str,
host_name: str,
project_settings: Optional[Dict[str, Any]] = None,
) -> str:
"""Helper function to get template key for workfile template.
Do the same as `get_workfile_template_key` but returns value for "session
@ -34,15 +35,23 @@ def get_workfile_template_key_from_context(
host_name (str): Host name.
project_settings (Dict[str, Any]): Project settings for passed
'project_name'. Not required at all but makes function faster.
"""
Returns:
str: Workfile template name.
"""
folder_entity = ayon_api.get_folder_by_path(
project_name, folder_path, fields={"id"}
project_name,
folder_path,
fields={"id"},
)
task_entity = ayon_api.get_task_by_name(
project_name, folder_entity["id"], task_name
project_name,
folder_entity["id"],
task_name,
fields={"taskType"},
)
task_type = task_entity.get("type")
task_type = task_entity.get("taskType")
return get_workfile_template_key(
project_name, task_type, host_name, project_settings

View file

@ -254,7 +254,7 @@ class FilesModel(QtGui.QStandardItemModel):
"""Make sure that removed items are removed from items mapping.
Connected with '_on_insert'. When user drag item and drop it to same
view the item is actually removed and creted again but it happens in
view the item is actually removed and created again but it happens in
inner calls of Qt.
"""
@ -841,7 +841,7 @@ class FilesWidget(QtWidgets.QFrame):
self._multivalue
)
widget.context_menu_requested.connect(
self._on_context_menu_requested
self._on_item_context_menu_request
)
self._files_view.setIndexWidget(index, widget)
self._files_proxy_model.setData(
@ -859,7 +859,7 @@ class FilesWidget(QtWidgets.QFrame):
for row in range(self._files_proxy_model.rowCount()):
index = self._files_proxy_model.index(row, 0)
item_id = index.data(ITEM_ID_ROLE)
available_item_ids.add(index.data(ITEM_ID_ROLE))
available_item_ids.add(item_id)
widget_ids = set(self._widgets_by_id.keys())
for item_id in available_item_ids:
@ -923,6 +923,9 @@ class FilesWidget(QtWidgets.QFrame):
if menu.actions():
menu.popup(pos)
def _on_item_context_menu_request(self, pos):
self._on_context_menu_requested(pos, True)
def dragEnterEvent(self, event):
if self._multivalue:
return

View file

@ -321,7 +321,7 @@ class PushToContextController:
return False
if (
not self._user_values.new_folder_name
self._user_values.new_folder_name is None
and not self._selection_model.get_selected_folder_id()
):
return False

View file

@ -26,7 +26,7 @@ from ayon_core.pipeline import Anatomy
from ayon_core.pipeline.version_start import get_versioning_start
from ayon_core.pipeline.template_data import get_template_data
from ayon_core.pipeline.publish import get_publish_template_name
from ayon_core.pipeline.create import get_product_name
from ayon_core.pipeline.create import get_product_name, TaskNotSetError
UNKNOWN = object()
@ -823,15 +823,25 @@ class ProjectPushItemProcess:
task_name = task_info["name"]
task_type = task_info["taskType"]
product_name = get_product_name(
self._item.dst_project_name,
task_name,
task_type,
self.host_name,
product_type,
self._item.variant,
project_settings=self._project_settings
)
try:
product_name = get_product_name(
self._item.dst_project_name,
task_name,
task_type,
self.host_name,
product_type,
self._item.variant,
project_settings=self._project_settings
)
except TaskNotSetError:
self._status.set_failed(
"Target product name template requires task name. To continue"
" you have to select target task or change settings"
" <b>ayon+settings://core/tools/creator/product_name_profiles"
f"?project={self._item.dst_project_name}</b>."
)
raise PushToProjectError(self._status.fail_reason)
self._log_info(
f"Push will be integrating to product with name '{product_name}'"
)

View file

@ -84,8 +84,11 @@ class UserPublishValuesModel:
return
self._new_folder_name = folder_name
is_valid = True
if folder_name:
if folder_name is None:
is_valid = True
elif not folder_name:
is_valid = False
else:
is_valid = (
self.folder_name_regex.match(folder_name) is not None
)

View file

@ -8,12 +8,69 @@ from ayon_core.tools.utils import (
ProjectsCombobox,
FoldersWidget,
TasksWidget,
NiceCheckbox,
)
from ayon_core.tools.push_to_project.control import (
PushToContextController,
)
class ErrorDetailDialog(QtWidgets.QDialog):
def __init__(self, parent):
super().__init__(parent)
self.setWindowTitle("Error detail")
self.setWindowIcon(QtGui.QIcon(get_app_icon_path()))
title_label = QtWidgets.QLabel(self)
sep_1 = SeparatorWidget(parent=self)
detail_widget = QtWidgets.QTextBrowser(self)
detail_widget.setReadOnly(True)
detail_widget.setTextInteractionFlags(
QtCore.Qt.TextBrowserInteraction
)
sep_2 = SeparatorWidget(parent=self)
btns_widget = QtWidgets.QWidget(self)
copy_btn = QtWidgets.QPushButton("Copy", btns_widget)
close_btn = QtWidgets.QPushButton("Close", btns_widget)
btns_layout = QtWidgets.QHBoxLayout(btns_widget)
btns_layout.setContentsMargins(0, 0, 0, 0)
btns_layout.addStretch(1)
btns_layout.addWidget(copy_btn, 0)
btns_layout.addWidget(close_btn, 0)
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setContentsMargins(10, 10, 10, 10)
main_layout.addWidget(title_label, 0)
main_layout.addWidget(sep_1, 0)
main_layout.addWidget(detail_widget, 1)
main_layout.addWidget(sep_2, 0)
main_layout.addWidget(btns_widget, 0)
copy_btn.clicked.connect(self._on_copy_click)
close_btn.clicked.connect(self._on_close_click)
self._title_label = title_label
self._detail_widget = detail_widget
def set_detail(self, title, detail):
self._title_label.setText(title)
self._detail_widget.setText(detail)
def _on_copy_click(self):
clipboard = QtWidgets.QApplication.clipboard()
clipboard.setText(self._detail_widget.toPlainText())
def _on_close_click(self):
self.close()
class PushToContextSelectWindow(QtWidgets.QWidget):
def __init__(self, controller=None):
super(PushToContextSelectWindow, self).__init__()
@ -66,9 +123,12 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
# --- Inputs widget ---
inputs_widget = QtWidgets.QWidget(main_splitter)
new_folder_checkbox = NiceCheckbox(True, parent=inputs_widget)
folder_name_input = PlaceholderLineEdit(inputs_widget)
folder_name_input.setPlaceholderText("< Name of new folder >")
folder_name_input.setObjectName("ValidatedLineEdit")
folder_name_input.setEnabled(new_folder_checkbox.isChecked())
variant_input = PlaceholderLineEdit(inputs_widget)
variant_input.setPlaceholderText("< Variant >")
@ -79,6 +139,7 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
inputs_layout = QtWidgets.QFormLayout(inputs_widget)
inputs_layout.setContentsMargins(0, 0, 0, 0)
inputs_layout.addRow("Create new folder", new_folder_checkbox)
inputs_layout.addRow("New folder name", folder_name_input)
inputs_layout.addRow("Variant", variant_input)
inputs_layout.addRow("Comment", comment_input)
@ -113,6 +174,10 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
overlay_label = QtWidgets.QLabel(overlay_widget)
overlay_label.setAlignment(QtCore.Qt.AlignCenter)
overlay_label.setWordWrap(True)
overlay_label.setTextInteractionFlags(
QtCore.Qt.TextBrowserInteraction
)
overlay_btns_widget = QtWidgets.QWidget(overlay_widget)
overlay_btns_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
@ -121,13 +186,28 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
overlay_try_btn = QtWidgets.QPushButton(
"Try again", overlay_btns_widget
)
overlay_try_btn.setToolTip(
"Hide overlay and modify submit information."
)
show_detail_btn = QtWidgets.QPushButton(
"Show error detail", overlay_btns_widget
)
show_detail_btn.setToolTip(
"Show error detail dialog to copy full error."
)
overlay_close_btn = QtWidgets.QPushButton(
"Close", overlay_btns_widget
)
overlay_close_btn.setToolTip("Discard changes and close window.")
overlay_btns_layout = QtWidgets.QHBoxLayout(overlay_btns_widget)
overlay_btns_layout.setContentsMargins(0, 0, 0, 0)
overlay_btns_layout.setSpacing(10)
overlay_btns_layout.addStretch(1)
overlay_btns_layout.addWidget(overlay_try_btn, 0)
overlay_btns_layout.addWidget(show_detail_btn, 0)
overlay_btns_layout.addWidget(overlay_close_btn, 0)
overlay_btns_layout.addStretch(1)
@ -156,12 +236,14 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
main_thread_timer.timeout.connect(self._on_main_thread_timer)
show_timer.timeout.connect(self._on_show_timer)
user_input_changed_timer.timeout.connect(self._on_user_input_timer)
new_folder_checkbox.stateChanged.connect(self._on_new_folder_check)
folder_name_input.textChanged.connect(self._on_new_folder_change)
variant_input.textChanged.connect(self._on_variant_change)
comment_input.textChanged.connect(self._on_comment_change)
publish_btn.clicked.connect(self._on_select_click)
cancel_btn.clicked.connect(self._on_close_click)
show_detail_btn.clicked.connect(self._on_show_detail_click)
overlay_close_btn.clicked.connect(self._on_close_click)
overlay_try_btn.clicked.connect(self._on_try_again_click)
@ -203,23 +285,28 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
self._tasks_widget = tasks_widget
self._variant_input = variant_input
self._new_folder_checkbox = new_folder_checkbox
self._folder_name_input = folder_name_input
self._comment_input = comment_input
self._publish_btn = publish_btn
self._overlay_widget = overlay_widget
self._show_detail_btn = show_detail_btn
self._overlay_close_btn = overlay_close_btn
self._overlay_try_btn = overlay_try_btn
self._overlay_label = overlay_label
self._error_detail_dialog = ErrorDetailDialog(self)
self._user_input_changed_timer = user_input_changed_timer
# Store current value on input text change
# The value is unset when is passed to controller
# The goal is to have controll over changes happened during user change
# in UI and controller auto-changes
self._variant_input_text = None
self._new_folder_name_enabled = None
self._new_folder_name_input_text = None
self._variant_input_text = None
self._comment_input_text = None
self._first_show = True
@ -235,6 +322,7 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
self._folder_is_valid = None
publish_btn.setEnabled(False)
show_detail_btn.setVisible(False)
overlay_close_btn.setVisible(False)
overlay_try_btn.setVisible(False)
@ -289,6 +377,11 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
self.refresh()
def _on_new_folder_check(self):
self._new_folder_name_enabled = self._new_folder_checkbox.isChecked()
self._folder_name_input.setEnabled(self._new_folder_name_enabled)
self._user_input_changed_timer.start()
def _on_new_folder_change(self, text):
self._new_folder_name_input_text = text
self._user_input_changed_timer.start()
@ -302,9 +395,15 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
self._user_input_changed_timer.start()
def _on_user_input_timer(self):
folder_name_enabled = self._new_folder_name_enabled
folder_name = self._new_folder_name_input_text
if folder_name is not None:
if folder_name is not None or folder_name_enabled is not None:
self._new_folder_name_input_text = None
self._new_folder_name_enabled = None
if not self._new_folder_checkbox.isChecked():
folder_name = None
elif folder_name is None:
folder_name = self._folder_name_input.text()
self._controller.set_user_value_folder_name(folder_name)
variant = self._variant_input_text
@ -350,16 +449,13 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
self._header_label.setText(self._controller.get_source_label())
def _invalidate_new_folder_name(self, folder_name, is_valid):
self._tasks_widget.setVisible(not folder_name)
self._tasks_widget.setVisible(folder_name is None)
if self._folder_is_valid is is_valid:
return
self._folder_is_valid = is_valid
state = ""
if folder_name:
if is_valid is True:
state = "valid"
elif is_valid is False:
state = "invalid"
if folder_name is not None:
state = "valid" if is_valid else "invalid"
set_style_property(
self._folder_name_input, "state", state
)
@ -374,6 +470,9 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
def _on_submission_change(self, event):
self._publish_btn.setEnabled(event["enabled"])
def _on_show_detail_click(self):
self._error_detail_dialog.show()
def _on_close_click(self):
self.close()
@ -384,8 +483,11 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
self._process_item_id = None
self._last_submit_message = None
self._error_detail_dialog.close()
self._overlay_close_btn.setVisible(False)
self._overlay_try_btn.setVisible(False)
self._show_detail_btn.setVisible(False)
self._main_layout.setCurrentWidget(self._main_context_widget)
def _on_main_thread_timer(self):
@ -401,13 +503,24 @@ class PushToContextSelectWindow(QtWidgets.QWidget):
if self._main_thread_timer_can_stop:
self._main_thread_timer.stop()
self._overlay_close_btn.setVisible(True)
if push_failed and not fail_traceback:
if push_failed:
self._overlay_try_btn.setVisible(True)
if fail_traceback:
self._show_detail_btn.setVisible(True)
if push_failed:
message = "Push Failed:\n{}".format(process_status["fail_reason"])
reason = process_status["fail_reason"]
if fail_traceback:
message += "\n{}".format(fail_traceback)
message = (
"Unhandled error happened."
" Check error detail for more information."
)
self._error_detail_dialog.set_detail(
reason, fail_traceback
)
else:
message = f"Push Failed:\n{reason}"
self._overlay_label.setText(message)
set_style_property(self._overlay_close_btn, "state", "error")