Merge branch 'develop' into bugfix/houdini_refactor_get_output_parameter

This commit is contained in:
MustafaJafar 2023-12-13 15:26:29 +02:00
commit 7e6e367d5a
56 changed files with 1390 additions and 161 deletions

View file

@ -606,7 +606,7 @@ def convert_v4_version_to_v3(version):
output_data[dst_key] = version[src_key]
if "createdAt" in version:
created_at = arrow.get(version["createdAt"])
created_at = arrow.get(version["createdAt"]).to("local")
output_data["time"] = created_at.strftime("%Y%m%dT%H%M%SZ")
output["data"] = output_data

View file

@ -1,6 +1,6 @@
# AfterEffects Integration
Requirements: This extension requires use of Javascript engine, which is
Requirements: This extension requires use of Javascript engine, which is
available since CC 16.0.
Please check your File>Project Settings>Expressions>Expressions Engine
@ -13,26 +13,28 @@ The After Effects integration requires two components to work; `extension` and `
To install the extension download [Extension Manager Command Line tool (ExManCmd)](https://github.com/Adobe-CEP/Getting-Started-guides/tree/master/Package%20Distribute%20Install#option-2---exmancmd).
```
ExManCmd /install {path to avalon-core}\avalon\photoshop\extension.zxp
ExManCmd /install {path to addon}/api/extension.zxp
```
OR
download [Anastasiys Extension Manager](https://install.anastasiy.com/)
`{path to addon}` will be most likely in your AppData (on Windows, in your user data folder in Linux and MacOS.)
### Server
The easiest way to get the server and After Effects launch is with:
```
python -c ^"import avalon.photoshop;avalon.aftereffects.launch(""c:\Program Files\Adobe\Adobe After Effects 2020\Support Files\AfterFX.exe"")^"
python -c ^"import openpype.hosts.photoshop;openpype.hosts..aftereffects.launch(""c:\Program Files\Adobe\Adobe After Effects 2020\Support Files\AfterFX.exe"")^"
```
`avalon.aftereffects.launch` launches the application and server, and also closes the server when After Effects exists.
## Usage
The After Effects extension can be found under `Window > Extensions > OpenPype`. Once launched you should be presented with a panel like this:
The After Effects extension can be found under `Window > Extensions > AYON`. Once launched you should be presented with a panel like this:
![Avalon Panel](panel.PNG "Avalon Panel")
![Ayon Panel](panel.png "Ayon Panel")
## Developing
@ -43,8 +45,8 @@ When developing the extension you can load it [unsigned](https://github.com/Adob
When signing the extension you can use this [guide](https://github.com/Adobe-CEP/Getting-Started-guides/tree/master/Package%20Distribute%20Install#package-distribute-install-guide).
```
ZXPSignCmd -selfSignedCert NA NA Avalon Avalon-After-Effects avalon extension.p12
ZXPSignCmd -sign {path to avalon-core}\avalon\aftereffects\extension {path to avalon-core}\avalon\aftereffects\extension.zxp extension.p12 avalon
ZXPSignCmd -selfSignedCert NA NA Ayon Avalon-After-Effects Ayon extension.p12
ZXPSignCmd -sign {path to addon}/api/extension {path to addon}/api/extension.zxp extension.p12 Ayon
```
### Plugin Examples
@ -52,14 +54,14 @@ ZXPSignCmd -sign {path to avalon-core}\avalon\aftereffects\extension {path to av
These plugins were made with the [polly config](https://github.com/mindbender-studio/config). To fully integrate and load, you will have to use this config and add `image` to the [integration plugin](https://github.com/mindbender-studio/config/blob/master/polly/plugins/publish/integrate_asset.py).
Expected deployed extension location on default Windows:
`c:\Program Files (x86)\Common Files\Adobe\CEP\extensions\com.openpype.AE.panel`
`c:\Program Files (x86)\Common Files\Adobe\CEP\extensions\io.ynput.AE.panel`
For easier debugging of Javascript:
https://community.adobe.com/t5/download-install/adobe-extension-debuger-problem/td-p/10911704?page=1
Add (optional) --enable-blink-features=ShadowDOMV0,CustomElementsV0 when starting Chrome
then localhost:8092
Or use Visual Studio Code https://medium.com/adobetech/extendscript-debugger-for-visual-studio-code-public-release-a2ff6161fa01
Or use Visual Studio Code https://medium.com/adobetech/extendscript-debugger-for-visual-studio-code-public-release-a2ff6161fa01
## Resources
- https://javascript-tools-guide.readthedocs.io/introduction/index.html
- https://github.com/Adobe-CEP/Getting-Started-guides

View file

@ -1,32 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<ExtensionList>
<Extension Id="com.openpype.AE.panel">
<Extension Id="io.ynput.AE.panel">
<HostList>
<!-- Comment Host tags according to the apps you want your panel to support -->
<!-- Photoshop -->
<Host Name="PHXS" Port="8088"/>
<!-- Illustrator -->
<Host Name="ILST" Port="8089"/>
<!-- InDesign -->
<Host Name="IDSN" Port="8090" />
<!-- Premiere -->
<Host Name="PPRO" Port="8091" />
<!-- AfterEffects -->
<Host Name="AEFT" Port="8092" />
<!-- PRELUDE -->
<Host Name="PRLD" Port="8093" />
<!-- FLASH Pro -->
<Host Name="FLPR" Port="8094" />
</HostList>
</Extension>
</ExtensionList>

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<ExtensionManifest Version="8.0" ExtensionBundleId="com.openpype.AE.panel" ExtensionBundleVersion="1.0.27"
ExtensionBundleName="com.openpype.AE.panel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ExtensionManifest Version="8.0" ExtensionBundleId="io.ynput.AE.panel" ExtensionBundleVersion="1.1.0"
ExtensionBundleName="io.ynput.AE.panel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ExtensionList>
<Extension Id="com.openpype.AE.panel" Version="1.0" />
<Extension Id="io.ynput.AE.panel" Version="1.0" />
</ExtensionList>
<ExecutionEnvironment>
<HostList>
@ -38,7 +38,7 @@
</RequiredRuntimeList>
</ExecutionEnvironment>
<DispatchInfoList>
<Extension Id="com.openpype.AE.panel">
<Extension Id="io.ynput.AE.panel">
<DispatchInfo >
<Resources>
<MainPath>./index.html</MainPath>
@ -49,7 +49,7 @@
</Lifecycle>
<UI>
<Type>Panel</Type>
<Menu>OpenPype</Menu>
<Menu>AYON</Menu>
<Geometry>
<Size>
<Height>200</Height>
@ -66,7 +66,7 @@
</Geometry>
<Icons>
<Icon Type="Normal">./icons/iconNormal.png</Icon>
<Icon Type="Normal">./icons/ayon_logo.png</Icon>
<Icon Type="RollOver">./icons/iconRollover.png</Icon>
<Icon Type="Disabled">./icons/iconDisabled.png</Icon>
<Icon Type="DarkNormal">./icons/iconDarkNormal.png</Icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -60,8 +60,9 @@ class ExtractLocalRender(publish.Extractor):
first_repre = not representations
if instance.data["review"] and first_repre:
repre_data["tags"] = ["review"]
thumbnail_path = os.path.join(staging_dir, files[0])
instance.data["thumbnailSource"] = thumbnail_path
# TODO return back when Extract from source same as regular
# thumbnail_path = os.path.join(staging_dir, files[0])
# instance.data["thumbnailSource"] = thumbnail_path
representations.append(repre_data)

View file

@ -14,18 +14,13 @@ class CollectChunkSize(pyblish.api.InstancePlugin,
hosts = ["houdini"]
targets = ["local", "remote"]
label = "Collect Chunk Size"
chunkSize = 999999
chunk_size = 999999
def process(self, instance):
# need to get the chunk size info from the setting
attr_values = self.get_attr_values_from_data(instance.data)
instance.data["chunkSize"] = attr_values.get("chunkSize")
@classmethod
def apply_settings(cls, project_settings):
project_setting = project_settings["houdini"]["publish"]["CollectChunkSize"] # noqa
cls.chunkSize = project_setting["chunk_size"]
@classmethod
def get_attribute_defs(cls):
return [
@ -33,7 +28,6 @@ class CollectChunkSize(pyblish.api.InstancePlugin,
minimum=1,
maximum=999999,
decimals=0,
default=cls.chunkSize,
default=cls.chunk_size,
label="Frame Per Task")
]

View file

@ -198,8 +198,8 @@ def _render_preview_animation_max_pre_2024(
res_width, res_height, filename=filepath
)
dib = rt.gw.getViewportDib()
dib_width = rt.renderWidth
dib_height = rt.renderHeight
dib_width = float(dib.width)
dib_height = float(dib.height)
# aspect ratio
viewportRatio = dib_width / dib_height
renderRatio = float(res_width / res_height)

View file

@ -1,9 +1,12 @@
import pyblish.api
from pymxs import runtime as rt
from openpype.pipeline import (
PublishValidationError,
OptionalPyblishPluginMixin
)
from pymxs import runtime as rt
from openpype.pipeline.publish import (
RepairAction,
PublishValidationError
)
from openpype.hosts.max.api.lib import reset_scene_resolution
@ -16,6 +19,7 @@ class ValidateResolutionSetting(pyblish.api.InstancePlugin,
hosts = ["max"]
label = "Validate Resolution Setting"
optional = True
actions = [RepairAction]
def process(self, instance):
if not self.is_active(instance.data):

View file

@ -9,7 +9,7 @@ The Photoshop integration requires two components to work; `extension` and `serv
To install the extension download [Extension Manager Command Line tool (ExManCmd)](https://github.com/Adobe-CEP/Getting-Started-guides/tree/master/Package%20Distribute%20Install#option-2---exmancmd).
```
ExManCmd /install {path to avalon-core}\avalon\photoshop\extension.zxp
ExManCmd /install {path to addon}/api/extension.zxp
```
### Server
@ -17,16 +17,16 @@ ExManCmd /install {path to avalon-core}\avalon\photoshop\extension.zxp
The easiest way to get the server and Photoshop launch is with:
```
python -c ^"import avalon.photoshop;avalon.photoshop.launch(""C:\Program Files\Adobe\Adobe Photoshop 2020\Photoshop.exe"")^"
python -c ^"import openpype.hosts.photoshop;openpype.hosts.photoshop.launch(""C:\Program Files\Adobe\Adobe Photoshop 2020\Photoshop.exe"")^"
```
`avalon.photoshop.launch` launches the application and server, and also closes the server when Photoshop exists.
## Usage
The Photoshop extension can be found under `Window > Extensions > Avalon`. Once launched you should be presented with a panel like this:
The Photoshop extension can be found under `Window > Extensions > Ayon`. Once launched you should be presented with a panel like this:
![Avalon Panel](panel.PNG "Avalon Panel")
![Ayon Panel](panel.png "AYON Panel")
## Developing
@ -37,7 +37,7 @@ When developing the extension you can load it [unsigned](https://github.com/Adob
When signing the extension you can use this [guide](https://github.com/Adobe-CEP/Getting-Started-guides/tree/master/Package%20Distribute%20Install#package-distribute-install-guide).
```
ZXPSignCmd -selfSignedCert NA NA Avalon Avalon-Photoshop avalon extension.p12
ZXPSignCmd -selfSignedCert NA NA Ayon Ayon-Photoshop Ayon extension.p12
ZXPSignCmd -sign {path to avalon-core}\avalon\photoshop\extension {path to avalon-core}\avalon\photoshop\extension.zxp extension.p12 avalon
```

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<ExtensionList>
<Extension Id="com.openpype.PS.panel">
<Extension Id="io.ynput.PS.panel">
<HostList>
<Host Name="PHXS" Port="8078"/>
<Host Name="FLPR" Port="8078"/>
</HostList>
</Extension>
</ExtensionList>
</ExtensionList>

View file

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<ExtensionManifest ExtensionBundleId="com.openpype.PS.panel" ExtensionBundleVersion="1.0.12" Version="7.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ExtensionManifest ExtensionBundleId="io.ynput.PS.panel" ExtensionBundleVersion="1.1.0" Version="7.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ExtensionList>
<Extension Id="com.openpype.PS.panel" Version="1.0.1" />
<Extension Id="io.ynput.PS.panel" Version="1.0.1" />
</ExtensionList>
<ExecutionEnvironment>
<HostList>
@ -16,7 +16,7 @@
</RequiredRuntimeList>
</ExecutionEnvironment>
<DispatchInfoList>
<Extension Id="com.openpype.PS.panel">
<Extension Id="io.ynput.PS.panel">
<DispatchInfo>
<Resources>
<MainPath>./index.html</MainPath>
@ -32,7 +32,7 @@
</Lifecycle>
<UI>
<Type>Panel</Type>
<Menu>OpenPype</Menu>
<Menu>AYON</Menu>
<Geometry>
<Size>
<Width>300</Width>
@ -44,7 +44,7 @@
</MaxSize>
</Geometry>
<Icons>
<Icon Type="Normal">./icons/avalon-logo-48.png</Icon>
<Icon Type="Normal">./icons/ayon_logo.png</Icon>
</Icons>
</UI>
</DispatchInfo>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View file

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -257,8 +257,6 @@ class CollectHierarchyContext(pyblish.api.ContextPlugin):
if 'shot' not in instance.data.get('family', ''):
continue
name = instance.data["asset"]
# get handles
handle_start = int(instance.data["handleStart"])
handle_end = int(instance.data["handleEnd"])
@ -286,6 +284,8 @@ class CollectHierarchyContext(pyblish.api.ContextPlugin):
parents = instance.data.get('parents', [])
self.log.debug(f"parents: {pformat(parents)}")
# Split by '/' for AYON where asset is a path
name = instance.data["asset"].split("/")[-1]
actual = {name: in_info}
for parent in reversed(parents):

View file

@ -583,18 +583,9 @@ def prompt_new_file_with_mesh(mesh_filepath):
file_dialog.setDirectory(os.path.dirname(mesh_filepath))
url = QtCore.QUrl.fromLocalFile(os.path.basename(mesh_filepath))
file_dialog.selectUrl(url)
# Give the explorer window time to refresh to the folder and select
# the file
while not file_dialog.selectedFiles():
app.processEvents(QtCore.QEventLoop.ExcludeUserInputEvents, 1000)
print(f"Selected: {file_dialog.selectedFiles()}")
# Set it again now we know the path is refreshed - without this
# accepting the dialog will often not trigger the correct filepath
file_dialog.setDirectory(os.path.dirname(mesh_filepath))
url = QtCore.QUrl.fromLocalFile(os.path.basename(mesh_filepath))
file_dialog.selectUrl(url)
# TODO: find a way to improve the process event to
# load more complicated mesh
app.processEvents(QtCore.QEventLoop.ExcludeUserInputEvents, 3000)
file_dialog.done(file_dialog.Accepted)
app.processEvents(QtCore.QEventLoop.AllEvents)
@ -628,7 +619,12 @@ def prompt_new_file_with_mesh(mesh_filepath):
mesh_filename_label = mesh_filename.findChild(QtWidgets.QLabel)
if not mesh_filename_label.text():
dialog.close()
raise RuntimeError(f"Failed to set mesh path: {mesh_filepath}")
substance_painter.logging.warning(
"Failed to set mesh path with the prompt dialog:"
f"{mesh_filepath}\n\n"
"Creating new project directly with the mesh path instead.")
else:
dialog.done(dialog.Accepted)
new_action = _get_new_project_action()
if not new_action:

View file

@ -44,14 +44,22 @@ class SubstanceLoadProjectMesh(load.LoaderPlugin):
# Get user inputs
import_cameras = data.get("import_cameras", True)
preserve_strokes = data.get("preserve_strokes", True)
sp_settings = substance_painter.project.Settings(
import_cameras=import_cameras
)
if not substance_painter.project.is_open():
# Allow to 'initialize' a new project
path = self.filepath_from_context(context)
# TODO: improve the prompt dialog function to not
# only works for simple polygon scene
result = prompt_new_file_with_mesh(mesh_filepath=path)
if not result:
self.log.info("User cancelled new project prompt.")
return
self.log.info("User cancelled new project prompt."
"Creating new project directly from"
" Substance Painter API Instead.")
settings = substance_painter.project.create(
mesh_file_path=path, settings=sp_settings
)
else:
# Reload the mesh

View file

@ -663,7 +663,7 @@ or updating already created. Publishing will create OTIO file.
variant_name = instance_data["variant"]
# basic unique asset name
clip_name = os.path.splitext(otio_clip.name)[0].lower()
clip_name = os.path.splitext(otio_clip.name)[0]
project_doc = get_project(self.project_name)
shot_name, shot_metadata = self._shot_metadata_solver.generate_data(

View file

@ -155,8 +155,6 @@ class CollectShotInstance(pyblish.api.InstancePlugin):
else {}
)
asset_name = instance.data["asset"]
# get handles
handle_start = int(instance.data["handleStart"])
handle_end = int(instance.data["handleEnd"])
@ -177,6 +175,8 @@ class CollectShotInstance(pyblish.api.InstancePlugin):
parents = instance.data.get('parents', [])
# Split by '/' for AYON where asset is a path
asset_name = instance.data["asset"].split("/")[-1]
actual = {asset_name: in_info}
for parent in reversed(parents):

View file

@ -140,7 +140,7 @@ def is_running_staging():
latest_version = get_latest_version(local=False, remote=True)
staging_version = latest_version
if current_version == production_version:
if current_version == staging_version:
return True
return is_staging_enabled()

View file

@ -61,8 +61,9 @@ class CollectHierarchy(pyblish.api.ContextPlugin):
"resolutionHeight": instance.data["resolutionHeight"],
"pixelAspect": instance.data["pixelAspect"]
}
actual = {instance.data["asset"]: shot_data}
# Split by '/' for AYON where asset is a path
name = instance.data["asset"].split("/")[-1]
actual = {name: shot_data}
for parent in reversed(instance.data["parents"]):
next_dict = {}

View file

@ -68,7 +68,6 @@ class CollectResourcesPath(pyblish.api.InstancePlugin):
]
def process(self, instance):
anatomy = instance.context.data["anatomy"]
template_data = copy.deepcopy(instance.data["anatomyData"])
@ -80,11 +79,18 @@ class CollectResourcesPath(pyblish.api.InstancePlugin):
"representation": "TEMP"
})
# For the first time publish
if instance.data.get("hierarchy"):
template_data.update({
"hierarchy": instance.data["hierarchy"]
})
# Add fill keys for editorial publishing creating new entity
# TODO handle in editorial plugin
if instance.data.get("newAssetPublishing"):
if "hierarchy" not in template_data:
template_data["hierarchy"] = instance.data["hierarchy"]
if "asset" not in template_data:
asset_name = instance.data["asset"].split("/")[-1]
template_data["asset"] = asset_name
template_data["folder"] = {
"name": asset_name
}
publish_templates = anatomy.templates_obj["publish"]
if "folder" in publish_templates:

View file

@ -204,7 +204,8 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
project_item = None
project_children_context = None
for key, value in context.data["hierarchyContext"].items():
hierarchy_context = copy.deepcopy(context.data["hierarchyContext"])
for key, value in hierarchy_context.items():
project_item = copy.deepcopy(value)
project_children_context = project_item.pop("childs", None)
project_item["name"] = key
@ -223,23 +224,24 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
valid_ids = set()
hierarchy_queue = collections.deque()
hierarchy_queue.append((project_id, project_children_context))
hierarchy_queue.append((project_id, "", project_children_context))
while hierarchy_queue:
queue_item = hierarchy_queue.popleft()
parent_id, children_context = queue_item
parent_id, parent_path, children_context = queue_item
if not children_context:
continue
for asset, asset_info in children_context.items():
for folder_name, folder_info in children_context.items():
folder_path = "{}/{}".format(parent_path, folder_name)
if (
asset not in active_folder_paths
and not asset_info.get("childs")
folder_path not in active_folder_paths
and not folder_info.get("childs")
):
continue
asset_name = asset.split("/")[-1]
item_id = uuid.uuid4().hex
new_item = copy.deepcopy(asset_info)
new_item["name"] = asset_name
new_item = copy.deepcopy(folder_info)
new_item["name"] = folder_name
new_item["children"] = []
new_children_context = new_item.pop("childs", None)
tasks = new_item.pop("tasks", {})
@ -253,9 +255,11 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin):
items_by_id[item_id] = new_item
parent_id_by_item_id[item_id] = parent_id
if asset in active_folder_paths:
if folder_path in active_folder_paths:
valid_ids.add(item_id)
hierarchy_queue.append((item_id, new_children_context))
hierarchy_queue.append(
(item_id, folder_path, new_children_context)
)
if not valid_ids:
return None

View file

@ -1,6 +1,6 @@
import os
from openpype import AYON_SERVER_ENABLED
from openpype.lib.openpype_version import is_running_staging
from openpype.lib.openpype_version import is_staging_enabled
RESOURCES_DIR = os.path.dirname(os.path.abspath(__file__))
@ -59,7 +59,7 @@ def get_openpype_icon_filepath(staging=None):
return get_resource("icons", "AYON_icon_dev.png")
if staging is None:
staging = is_running_staging()
staging = is_staging_enabled()
if staging:
return get_openpype_staging_icon_filepath()
@ -68,7 +68,7 @@ def get_openpype_icon_filepath(staging=None):
def get_openpype_splash_filepath(staging=None):
if staging is None:
staging = is_running_staging()
staging = is_staging_enabled()
if AYON_SERVER_ENABLED:
if os.getenv("AYON_USE_DEV") == "1":

View file

@ -62,6 +62,12 @@
"Main"
]
},
"CreateMantraIFD": {
"enabled": true,
"default_variants": [
"Main"
]
},
"CreateMantraROP": {
"enabled": true,
"default_variants": [
@ -137,14 +143,14 @@
}
},
"publish": {
"CollectAssetHandles": {
"use_asset_handles": true
},
"CollectChunkSize": {
"enabled": true,
"optional": true,
"chunk_size": 999999
},
"CollectAssetHandles": {
"use_asset_handles": true
},
"ValidateContainers": {
"enabled": true,
"optional": true,

View file

@ -69,6 +69,10 @@
"key": "CreateKarmaROP",
"label": "Create Karma ROP"
},
{
"key": "CreateMantraIFD",
"label": "Create Mantra IFD"
},
{
"key": "CreateMantraROP",
"label": "Create Mantra ROP"

View file

@ -25,6 +25,31 @@
}
]
},
{
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "CollectChunkSize",
"label": "Collect Chunk Size",
"is_group": true,
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "boolean",
"key": "optional",
"label": "Optional"
},
{
"type": "number",
"key": "chunk_size",
"label": "Frames Per Task"
}
]
},
{
"type": "label",
"label": "Validators"
@ -55,31 +80,6 @@
}
]
},
{
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "CollectChunkSize",
"label": "Collect Chunk Size",
"is_group": true,
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "boolean",
"key": "optional",
"label": "Optional"
},
{
"type": "number",
"key": "chunk_size",
"label": "Frames Per Task"
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -512,52 +512,58 @@ QAbstractItemView::item:selected:hover {
}
/* Row colors (alternate colors) are from left - right */
QAbstractItemView:branch {
background: transparent;
QTreeView::branch {
background: {color:bg-view};
}
QTreeView::branch:hover {
background: {color:bg-view};
}
QTreeView::branch:selected {
background: {color:bg-view};
}
QAbstractItemView::branch:open:has-children:!has-siblings,
QAbstractItemView::branch:open:has-children:has-siblings {
border-image: none;
image: url(:/openpype/images/branch_open.png);
background: transparent;
background: {color:bg-view};
}
QAbstractItemView::branch:open:has-children:!has-siblings:hover,
QAbstractItemView::branch:open:has-children:has-siblings:hover {
border-image: none;
image: url(:/openpype/images/branch_open_on.png);
background: transparent;
background: {color:bg-view};
}
QAbstractItemView::branch:has-children:!has-siblings:closed,
QAbstractItemView::branch:closed:has-children:has-siblings {
border-image: none;
image: url(:/openpype/images/branch_closed.png);
background: transparent;
background: {color:bg-view};
}
QAbstractItemView::branch:has-children:!has-siblings:closed:hover,
QAbstractItemView::branch:closed:has-children:has-siblings:hover {
border-image: none;
image: url(:/openpype/images/branch_closed_on.png);
background: transparent;
background: {color:bg-view};
}
QAbstractItemView::branch:has-siblings:!adjoins-item {
border-image: none;
image: url(:/openpype/images/transparent.png);
background: transparent;
background: {color:bg-view};
}
QAbstractItemView::branch:has-siblings:adjoins-item {
border-image: none;
image: url(:/openpype/images/transparent.png);
background: transparent;
background: {color:bg-view};
}
QAbstractItemView::branch:!has-children:!has-siblings:adjoins-item {
border-image: none;
image: url(:/openpype/images/transparent.png);
background: transparent;
background: {color:bg-view};
}
CompleterView {

View file

@ -44,7 +44,7 @@ def version_item_from_entity(version):
# NOTE There is also 'updatedAt', should be used that instead?
# TODO skip conversion - converting to '%Y%m%dT%H%M%SZ' is because
# 'PrettyTimeDelegate' expects it
created_at = arrow.get(version["createdAt"])
created_at = arrow.get(version["createdAt"]).to("local")
published_time = created_at.strftime("%Y%m%dT%H%M%SZ")
author = version["author"]
version_num = version["version"]

View file

@ -606,7 +606,7 @@ class PublishWorkfilesModel:
print("Failed to format workfile path: {}".format(exc))
dirpath, filename = os.path.split(workfile_path)
created_at = arrow.get(repre_entity["createdAt"])
created_at = arrow.get(repre_entity["createdAt"].to("local"))
return FileItem(
dirpath,
filename,

View file

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring Pype version."""
__version__ = "3.17.7-nightly.6"
__version__ = "3.18.1-nightly.1"