From 8a20416e492a8301c8bcdb264b9f6b1bd3d00dc6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:10:21 +0200 Subject: [PATCH 1/8] don't validate extension of dropped file --- .../ayon_core/tools/publisher/publish_report_viewer/window.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/window.py b/client/ayon_core/tools/publisher/publish_report_viewer/window.py index aedc3b9e31..d5742d73e0 100644 --- a/client/ayon_core/tools/publisher/publish_report_viewer/window.py +++ b/client/ayon_core/tools/publisher/publish_report_viewer/window.py @@ -576,8 +576,7 @@ class LoadedFilesWidget(QtWidgets.QWidget): filepaths = [] for url in mime_data.urls(): filepath = url.toLocalFile() - ext = os.path.splitext(filepath)[-1] - if os.path.exists(filepath) and ext == ".json": + if os.path.exists(filepath): filepaths.append(filepath) self._add_filepaths(filepaths) event.accept() From 9ff4ec856b0ce9f78fe15bedabbca731b36fd837 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:00:10 +0200 Subject: [PATCH 2/8] introduced new function to get launcher storage and local dir --- client/ayon_core/lib/__init__.py | 4 +++ client/ayon_core/lib/local_settings.py | 49 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/client/ayon_core/lib/__init__.py b/client/ayon_core/lib/__init__.py index 12c391d867..d4b161031e 100644 --- a/client/ayon_core/lib/__init__.py +++ b/client/ayon_core/lib/__init__.py @@ -9,6 +9,8 @@ from .local_settings import ( AYONSettingsRegistry, OpenPypeSecureRegistry, OpenPypeSettingsRegistry, + get_launcher_local_dir, + get_launcher_storage_dir, get_local_site_id, get_ayon_username, get_openpype_username, @@ -144,6 +146,8 @@ __all__ = [ "AYONSettingsRegistry", "OpenPypeSecureRegistry", "OpenPypeSettingsRegistry", + "get_launcher_local_dir", + "get_launcher_storage_dir", "get_local_site_id", "get_ayon_username", "get_openpype_username", diff --git a/client/ayon_core/lib/local_settings.py b/client/ayon_core/lib/local_settings.py index 54432265d9..68ec48695f 100644 --- a/client/ayon_core/lib/local_settings.py +++ b/client/ayon_core/lib/local_settings.py @@ -30,6 +30,55 @@ import ayon_api _PLACEHOLDER = object() +def get_launcher_storage_dir(*subdirs: str) -> str: + """Get storage directory for launcher. + + Storage directory is used for storing shims, addons, dependencies, etc. + + It is not recommended, but the location can be shared across + multiple machines. + + Note: + This function should be called at least once on bootstrap. + + Args: + *subdirs (str): Subdirectories relative to storage dir. + + Returns: + str: Path to storage directory. + + """ + storage_dir = os.getenv("AYON_LAUNCHER_STORAGE_DIR") + if not storage_dir: + storage_dir = get_ayon_appdirs() + + return os.path.join(storage_dir, *subdirs) + + +def get_launcher_local_dir(*subdirs: str) -> str: + """Get local directory for launcher. + + Local directory is used for storing machine or user specific data. + + The location is user specific. + + Note: + This function should be called at least once on bootstrap. + + Args: + *subdirs (str): Subdirectories relative to local dir. + + Returns: + str: Path to local directory. + + """ + storage_dir = os.getenv("AYON_LAUNCHER_LOCAL_DIR") + if not storage_dir: + storage_dir = get_ayon_appdirs() + + return os.path.join(storage_dir, *subdirs) + + class AYONSecureRegistry: """Store information using keyring. From 0e95019995d6d5b077a9487692934a2ac5afe34d Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:03:17 +0200 Subject: [PATCH 3/8] use new functions in codebase --- client/ayon_core/addon/base.py | 11 ++++++----- client/ayon_core/lib/local_settings.py | 10 ++-------- client/ayon_core/pipeline/thumbnails.py | 4 ++-- .../tools/publisher/publish_report_viewer/window.py | 10 +++------- client/ayon_core/tools/tray/lib.py | 4 ++-- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index 001ec5d534..0dbbe19942 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -17,7 +17,11 @@ import ayon_api from semver import VersionInfo from ayon_core import AYON_CORE_ROOT -from ayon_core.lib import Logger, is_dev_mode_enabled +from ayon_core.lib import ( + Logger, + is_dev_mode_enabled, + get_launcher_storage_dir, +) from ayon_core.settings import get_studio_settings from .interfaces import ( @@ -327,10 +331,7 @@ def _load_ayon_addons(openpype_modules, modules_key, log): addons_dir = os.environ.get("AYON_ADDONS_DIR") if not addons_dir: - addons_dir = os.path.join( - appdirs.user_data_dir("AYON", "Ynput"), - "addons" - ) + addons_dir = get_launcher_storage_dir("addons") dev_mode_enabled = is_dev_mode_enabled() dev_addons_info = {} diff --git a/client/ayon_core/lib/local_settings.py b/client/ayon_core/lib/local_settings.py index 68ec48695f..a4ffdb8e39 100644 --- a/client/ayon_core/lib/local_settings.py +++ b/client/ayon_core/lib/local_settings.py @@ -519,20 +519,14 @@ class JSONSettingRegistry(ASettingRegistry): class AYONSettingsRegistry(JSONSettingRegistry): """Class handling AYON general settings registry. - Attributes: - vendor (str): Name used for path construction. - product (str): Additional name used for path construction. - Args: name (Optional[str]): Name of the registry. """ def __init__(self, name=None): - self.vendor = "Ynput" - self.product = "AYON" if not name: name = "AYON_settings" - path = appdirs.user_data_dir(self.product, self.vendor) + path = get_launcher_storage_dir() super(AYONSettingsRegistry, self).__init__(name, path) @@ -578,7 +572,7 @@ def get_local_site_id(): if site_id: return site_id - site_id_path = get_ayon_appdirs("site_id") + site_id_path = get_launcher_local_dir("site_id") if os.path.exists(site_id_path): with open(site_id_path, "r") as stream: site_id = stream.read() diff --git a/client/ayon_core/pipeline/thumbnails.py b/client/ayon_core/pipeline/thumbnails.py index dbb38615d8..401d95f273 100644 --- a/client/ayon_core/pipeline/thumbnails.py +++ b/client/ayon_core/pipeline/thumbnails.py @@ -4,7 +4,7 @@ import collections import ayon_api -from ayon_core.lib.local_settings import get_ayon_appdirs +from ayon_core.lib.local_settings import get_launcher_local_dir FileInfo = collections.namedtuple( @@ -54,7 +54,7 @@ class ThumbnailsCache: """ if self._thumbnails_dir is None: - self._thumbnails_dir = get_ayon_appdirs("thumbnails") + self._thumbnails_dir = get_launcher_local_dir("thumbnails") return self._thumbnails_dir thumbnails_dir = property(get_thumbnails_dir) diff --git a/client/ayon_core/tools/publisher/publish_report_viewer/window.py b/client/ayon_core/tools/publisher/publish_report_viewer/window.py index aedc3b9e31..9d1ed86a2b 100644 --- a/client/ayon_core/tools/publisher/publish_report_viewer/window.py +++ b/client/ayon_core/tools/publisher/publish_report_viewer/window.py @@ -2,11 +2,11 @@ import os import json import uuid -import appdirs import arrow from qtpy import QtWidgets, QtCore, QtGui from ayon_core import style +from ayon_core.lib import get_launcher_local_dir from ayon_core.resources import get_ayon_icon_filepath from ayon_core.tools import resources from ayon_core.tools.utils import ( @@ -35,12 +35,8 @@ def get_reports_dir(): str: Path to directory where reports are stored. """ - report_dir = os.path.join( - appdirs.user_data_dir("AYON", "Ynput"), - "publish_report_viewer" - ) - if not os.path.exists(report_dir): - os.makedirs(report_dir) + report_dir = get_launcher_local_dir("publish_report_viewer") + os.makedirs(report_dir, exist_ok=True) return report_dir diff --git a/client/ayon_core/tools/tray/lib.py b/client/ayon_core/tools/tray/lib.py index fd84a9bd10..5f92e8a04f 100644 --- a/client/ayon_core/tools/tray/lib.py +++ b/client/ayon_core/tools/tray/lib.py @@ -19,7 +19,7 @@ from ayon_core.lib import ( run_detached_process, get_ayon_username, ) -from ayon_core.lib.local_settings import get_ayon_appdirs +from ayon_core.lib.local_settings import get_launcher_local_dir class TrayState: @@ -146,7 +146,7 @@ def get_tray_storage_dir() -> str: str: Tray storage directory where metadata files are stored. """ - return get_ayon_appdirs("tray") + return get_launcher_local_dir("tray") def _get_tray_info_filepath( From 9d2ff9637fb67ba2e1af479caee9b41d80712d73 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:05:20 +0200 Subject: [PATCH 4/8] marked 'get_ayon_appdirs' as deprecated --- client/ayon_core/lib/local_settings.py | 53 +++++++++++++++++--------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/client/ayon_core/lib/local_settings.py b/client/ayon_core/lib/local_settings.py index a4ffdb8e39..a6814f8b2f 100644 --- a/client/ayon_core/lib/local_settings.py +++ b/client/ayon_core/lib/local_settings.py @@ -3,6 +3,7 @@ import os import json import platform +import warnings from datetime import datetime from abc import ABC, abstractmethod @@ -30,6 +31,38 @@ import ayon_api _PLACEHOLDER = object() +def _get_ayon_appdirs(*args): + return os.path.join( + appdirs.user_data_dir("AYON", "Ynput"), + *args + ) + + +def get_ayon_appdirs(*args): + """Local app data directory of AYON client. + + Deprecated: + Use 'get_launcher_local_dir' or 'get_launcher_storage_dir' based on + use-case. Deprecation added 24/08/09 (0.4.4-dev.1). + + Args: + *args (Iterable[str]): Subdirectories/files in local app data dir. + + Returns: + str: Path to directory/file in local app data dir. + + """ + warnings.warn( + ( + "Function 'get_ayon_appdirs' is deprecated. Should be replaced" + " with 'get_launcher_local_dir' or 'get_launcher_storage_dir'" + " based on use-case." + ), + DeprecationWarning + ) + return _get_ayon_appdirs(*args) + + def get_launcher_storage_dir(*subdirs: str) -> str: """Get storage directory for launcher. @@ -50,7 +83,7 @@ def get_launcher_storage_dir(*subdirs: str) -> str: """ storage_dir = os.getenv("AYON_LAUNCHER_STORAGE_DIR") if not storage_dir: - storage_dir = get_ayon_appdirs() + storage_dir = _get_ayon_appdirs() return os.path.join(storage_dir, *subdirs) @@ -74,7 +107,7 @@ def get_launcher_local_dir(*subdirs: str) -> str: """ storage_dir = os.getenv("AYON_LAUNCHER_LOCAL_DIR") if not storage_dir: - storage_dir = get_ayon_appdirs() + storage_dir = _get_ayon_appdirs() return os.path.join(storage_dir, *subdirs) @@ -546,22 +579,6 @@ def _create_local_site_id(registry=None): return new_id -def get_ayon_appdirs(*args): - """Local app data directory of AYON client. - - Args: - *args (Iterable[str]): Subdirectories/files in local app data dir. - - Returns: - str: Path to directory/file in local app data dir. - """ - - return os.path.join( - appdirs.user_data_dir("AYON", "Ynput"), - *args - ) - - def get_local_site_id(): """Get local site identifier. From f3c9ffac1a5fde32cabe419d12025bb0c1e7165d Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:05:32 +0200 Subject: [PATCH 5/8] removed unused function '_create_local_site_id' --- client/ayon_core/lib/local_settings.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/client/ayon_core/lib/local_settings.py b/client/ayon_core/lib/local_settings.py index a6814f8b2f..256e7bcd28 100644 --- a/client/ayon_core/lib/local_settings.py +++ b/client/ayon_core/lib/local_settings.py @@ -563,22 +563,6 @@ class AYONSettingsRegistry(JSONSettingRegistry): super(AYONSettingsRegistry, self).__init__(name, path) -def _create_local_site_id(registry=None): - """Create a local site identifier.""" - from coolname import generate_slug - - if registry is None: - registry = AYONSettingsRegistry() - - new_id = generate_slug(3) - - print("Created local site id \"{}\"".format(new_id)) - - registry.set_item("localId", new_id) - - return new_id - - def get_local_site_id(): """Get local site identifier. From c9a2022d0c87227be96123a3074fedbfd8614baa Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:19:27 +0200 Subject: [PATCH 6/8] remove unused import --- client/ayon_core/addon/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index 0dbbe19942..383703e2bc 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -12,7 +12,6 @@ from uuid import uuid4 from abc import ABC, abstractmethod from typing import Optional -import appdirs import ayon_api from semver import VersionInfo From 6e21bc4779c1ff1124ede43e55088a409bdafddc Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:12:07 +0200 Subject: [PATCH 7/8] change popup text to popup icon --- client/ayon_core/resources/images/popout.png | Bin 0 -> 4224 bytes .../publish_report_viewer/widgets.py | 27 ++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 client/ayon_core/resources/images/popout.png diff --git a/client/ayon_core/resources/images/popout.png b/client/ayon_core/resources/images/popout.png new file mode 100644 index 0000000000000000000000000000000000000000..838c29483ec9309603e8bbe6b300f5a780cea681 GIT binary patch literal 4224 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 S%EFcbzzqtUaV9Ww&p!bC9@&Hd literal 0 HcmV?d00001 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..96663a4c4a 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,13 @@ from math import ceil from qtpy import QtWidgets, QtCore, QtGui -from ayon_core.tools.utils import NiceCheckbox +from ayon_core.tools.utils import ( + NiceCheckbox, + IconButton, + paint_image_with_color, +) +from ayon_core.resources import get_image_path +from ayon_core.style import get_objected_colors # from ayon_core.tools.utils import DeselectableTreeView from .constants import ( @@ -410,12 +416,27 @@ class PublishReportViewerWidget(QtWidgets.QFrame): details_widget = QtWidgets.QWidget(self) details_tab_widget = QtWidgets.QTabWidget(details_widget) - details_popup_btn = QtWidgets.QPushButton("PopUp", details_widget) + + btns_widget = QtWidgets.QWidget(details_widget) + + popout_image = QtGui.QImage(get_image_path("popout.png")) + popout_color = get_objected_colors("font") + popout_icon = QtGui.QIcon( + paint_image_with_color(popout_image, popout_color.get_qcolor()) + ) + details_popup_btn = IconButton(btns_widget) + details_popup_btn.setIcon(popout_icon) + details_popup_btn.setToolTip("Pop Out") + + btns_layout = QtWidgets.QHBoxLayout(btns_widget) + btns_layout.setContentsMargins(0, 0, 0, 0) + btns_layout.addStretch(1) + btns_layout.addWidget(details_popup_btn, 0) details_layout = QtWidgets.QVBoxLayout(details_widget) details_layout.setContentsMargins(0, 0, 0, 0) details_layout.addWidget(details_tab_widget, 1) - details_layout.addWidget(details_popup_btn, 0) + details_layout.addWidget(btns_widget, 0) details_popup = DetailsPopup(self, details_tab_widget) From c02f90d5d3a3b99eb602bbff5aefff2ccf78355c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:12:54 +0200 Subject: [PATCH 8/8] change default size of window based on center widget --- .../tools/publisher/publish_report_viewer/widgets.py | 8 ++++++-- 1 file changed, 6 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 96663a4c4a..24c26baa70 100644 --- a/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py +++ b/client/ayon_core/tools/publisher/publish_report_viewer/widgets.py @@ -343,11 +343,15 @@ class DetailsPopup(QtWidgets.QDialog): def showEvent(self, event): layout = self.layout() + cw_size = self._center_widget.size() layout.insertWidget(0, self._center_widget) - super().showEvent(event) if self._first_show: self._first_show = False - self.resize(700, 400) + self.resize( + max(cw_size.width(), 700), + max(cw_size.height(), 400) + ) + super().showEvent(event) def closeEvent(self, event): super().closeEvent(event)