diff --git a/client/ayon_core/cli.py b/client/ayon_core/cli.py index 6f89a6d17d..dc794c41c2 100644 --- a/client/ayon_core/cli.py +++ b/client/ayon_core/cli.py @@ -24,7 +24,6 @@ ) - @click.group(invoke_without_command=True) @click.pass_context @click.option("--use-staging", is_flag=True, @@ -237,6 +236,30 @@ def version(build): print(os.environ["AYON_VERSION"]) +@main_cli.command() +@click.option( + "--project", + type=str, + help="Project name", + required=True) +def create_project_structure( + project, +): + """Create project folder structure as defined in setting + `ayon+settings://core/project_folder_structure` + + Args: + project (str): The name of the project for which you + want to create its additional folder structure. + + """ + + from ayon_core.pipeline.project_folders import create_project_folders + + print(f">>> Creating project folder structure for project '{project}'.") + create_project_folders(project) + + def _set_global_environments() -> None: """Set global AYON environments.""" # First resolve general environment diff --git a/pyproject.toml b/pyproject.toml index 3da97e6b2a..4834be06d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ mdx-gh-links = "^0.4" pymdown-extensions = "^10.14.3" mike = "^2.1.3" mkdocstrings-shell = "^1.0.2" +nxtools = "^1.6" [tool.ruff] diff --git a/server/__init__.py b/server/__init__.py index d60f50f471..aafd8d6fa5 100644 --- a/server/__init__.py +++ b/server/__init__.py @@ -1,6 +1,15 @@ from typing import Any from ayon_server.addons import BaseServerAddon +from ayon_server.actions import ( + ActionExecutor, + ExecuteResponseModel, + SimpleActionManifest, +) +try: + from ayon_server.logging import logger +except ImportError: + from nxtools import logging as logger from .settings import ( CoreSettings, @@ -9,6 +18,9 @@ ) +IDENTIFIER_PREFIX = "core" + + class CoreAddon(BaseServerAddon): settings_model = CoreSettings @@ -26,3 +38,57 @@ async def convert_settings_overrides( return await super().convert_settings_overrides( source_version, overrides ) + + async def get_simple_actions( + self, + project_name: str | None = None, + variant: str = "production", + ) -> list[SimpleActionManifest]: + """Return a list of simple actions provided by the addon""" + output = [] + + if project_name: + # Add 'Create Project Folder Structure' action to folders. + output.append( + SimpleActionManifest( + identifier=f"{IDENTIFIER_PREFIX}.createprojectstructure", + label="Create Project Folder Structure", + icon={ + "type": "material-symbols", + "name": "create_new_folder", + }, + order=100, + entity_type="folder", + entity_subtypes=None, + allow_multiselection=False, + ) + ) + + return output + + async def execute_action( + self, + executor: ActionExecutor, + ) -> ExecuteResponseModel: + """Execute webactions.""" + + project_name = executor.context.project_name + + if executor.identifier == \ + f"{IDENTIFIER_PREFIX}.create_project_structure": + + if not project_name: + logger.error( + f"Can't execute {executor.identifier} because" + " of missing project name." + ) + return + + return await executor.get_launcher_action_response( + args=[ + "create-project-structure", + "--project", project_name, + ] + ) + + logger.debug(f"Unknown action: {executor.identifier}") diff --git a/server/settings/main.py b/server/settings/main.py index 249bab85fd..a5129e69af 100644 --- a/server/settings/main.py +++ b/server/settings/main.py @@ -301,6 +301,15 @@ class CoreSettings(BaseSettingsModel): "{}", widget="textarea", title="Project folder structure", + description=( + "Defines project folders to create on 'Create project folders'." + "\n\n" + "- In the launcher, this only creates the folders on disk and " + " when the setting is empty it will be hidden from users in the" + " launcher.\n" + "- In `ayon-ftrack` this will create the folders on disk **and**" + " will also create ftrack entities. It is never hidden there." + ), section="---" ) project_environments: str = SettingsField(