added upload folder location for all document creation nodes
This commit is contained in:
parent
eeb9a4a161
commit
6e3da0d0d8
8 changed files with 110 additions and 12 deletions
|
|
@ -30,9 +30,6 @@ AI_NODES = [
|
||||||
{"name": "context", "type": "Any", "required": False, "frontendType": "contextBuilder",
|
{"name": "context", "type": "Any", "required": False, "frontendType": "contextBuilder",
|
||||||
"description": t("Daten aus vorherigen Schritten"), "default": "",
|
"description": t("Daten aus vorherigen Schritten"), "default": "",
|
||||||
"graphInherit": {"port": 0, "kind": "primaryTextRef"}},
|
"graphInherit": {"port": 0, "kind": "primaryTextRef"}},
|
||||||
{"name": "documentTheme", "type": "str", "required": False, "frontendType": "select",
|
|
||||||
"frontendOptions": {"options": ["general", "finance", "legal", "technical", "hr"]},
|
|
||||||
"description": t("Dokument-Thema (Style-Hinweis fuer den Renderer)"), "default": "general"},
|
|
||||||
{"name": "simpleMode", "type": "bool", "required": False, "frontendType": "checkbox",
|
{"name": "simpleMode", "type": "bool", "required": False, "frontendType": "checkbox",
|
||||||
"description": t("Einfacher Modus"), "default": True},
|
"description": t("Einfacher Modus"), "default": True},
|
||||||
] + _AI_COMMON_PARAMS,
|
] + _AI_COMMON_PARAMS,
|
||||||
|
|
@ -80,9 +77,15 @@ AI_NODES = [
|
||||||
{"name": "documentList", "type": "DocumentList", "required": True, "frontendType": "dataRef",
|
{"name": "documentList", "type": "DocumentList", "required": True, "frontendType": "dataRef",
|
||||||
"description": t("Dokumente aus vorherigen Schritten"),
|
"description": t("Dokumente aus vorherigen Schritten"),
|
||||||
"graphInherit": {"port": 0, "kind": "documentListWire"}},
|
"graphInherit": {"port": 0, "kind": "documentListWire"}},
|
||||||
|
{"name": "resultType", "type": "str", "required": False, "frontendType": "select",
|
||||||
|
"frontendOptions": {"options": ["txt", "json", "md", "csv", "xml", "html", "pdf", "docx", "xlsx", "pptx", "png", "jpg"]},
|
||||||
|
"description": t("Ausgabeformat"), "default": "txt"},
|
||||||
{"name": "summaryLength", "type": "str", "required": False, "frontendType": "select",
|
{"name": "summaryLength", "type": "str", "required": False, "frontendType": "select",
|
||||||
"frontendOptions": {"options": ["brief", "medium", "detailed"]},
|
"frontendOptions": {"options": ["brief", "medium", "detailed"]},
|
||||||
"description": t("Kurz, mittel oder ausführlich"), "default": "medium"},
|
"description": t("Kurz, mittel oder ausführlich"), "default": "medium"},
|
||||||
|
{"name": "folderId", "type": "str", "required": False, "frontendType": "userFileFolder",
|
||||||
|
"description": t("Zielordner in Meine Dateien"),
|
||||||
|
"default": ""},
|
||||||
] + _AI_COMMON_PARAMS,
|
] + _AI_COMMON_PARAMS,
|
||||||
"inputs": 1,
|
"inputs": 1,
|
||||||
"outputs": 1,
|
"outputs": 1,
|
||||||
|
|
@ -101,8 +104,14 @@ AI_NODES = [
|
||||||
{"name": "documentList", "type": "DocumentList", "required": True, "frontendType": "dataRef",
|
{"name": "documentList", "type": "DocumentList", "required": True, "frontendType": "dataRef",
|
||||||
"description": t("Dokumente aus vorherigen Schritten"),
|
"description": t("Dokumente aus vorherigen Schritten"),
|
||||||
"graphInherit": {"port": 0, "kind": "documentListWire"}},
|
"graphInherit": {"port": 0, "kind": "documentListWire"}},
|
||||||
|
{"name": "resultType", "type": "str", "required": False, "frontendType": "select",
|
||||||
|
"frontendOptions": {"options": ["txt", "json", "md", "csv", "xml", "html", "pdf", "docx", "xlsx", "pptx", "png", "jpg"]},
|
||||||
|
"description": t("Ausgabeformat"), "default": "txt"},
|
||||||
{"name": "targetLanguage", "type": "str", "required": True, "frontendType": "text",
|
{"name": "targetLanguage", "type": "str", "required": True, "frontendType": "text",
|
||||||
"description": t("Zielsprache (z.B. de, en, French)")},
|
"description": t("Zielsprache (z.B. de, en, French)")},
|
||||||
|
{"name": "folderId", "type": "str", "required": False, "frontendType": "userFileFolder",
|
||||||
|
"description": t("Zielordner in Meine Dateien"),
|
||||||
|
"default": ""},
|
||||||
] + _AI_COMMON_PARAMS,
|
] + _AI_COMMON_PARAMS,
|
||||||
"inputs": 1,
|
"inputs": 1,
|
||||||
"outputs": 1,
|
"outputs": 1,
|
||||||
|
|
@ -124,6 +133,9 @@ AI_NODES = [
|
||||||
{"name": "targetFormat", "type": "str", "required": True, "frontendType": "select",
|
{"name": "targetFormat", "type": "str", "required": True, "frontendType": "select",
|
||||||
"frontendOptions": {"options": ["docx", "pdf", "xlsx", "csv", "txt", "html", "json", "md"]},
|
"frontendOptions": {"options": ["docx", "pdf", "xlsx", "csv", "txt", "html", "json", "md"]},
|
||||||
"description": t("Zielformat")},
|
"description": t("Zielformat")},
|
||||||
|
{"name": "folderId", "type": "str", "required": False, "frontendType": "userFileFolder",
|
||||||
|
"description": t("Zielordner in Meine Dateien"),
|
||||||
|
"default": ""},
|
||||||
] + _AI_COMMON_PARAMS,
|
] + _AI_COMMON_PARAMS,
|
||||||
"inputs": 1,
|
"inputs": 1,
|
||||||
"outputs": 1,
|
"outputs": 1,
|
||||||
|
|
@ -149,6 +161,9 @@ AI_NODES = [
|
||||||
{"name": "documentType", "type": "str", "required": False, "frontendType": "select",
|
{"name": "documentType", "type": "str", "required": False, "frontendType": "select",
|
||||||
"frontendOptions": {"options": ["letter", "memo", "proposal", "contract", "report", "email"]},
|
"frontendOptions": {"options": ["letter", "memo", "proposal", "contract", "report", "email"]},
|
||||||
"description": t("Dokumentart (Inhaltshinweis fuer die KI)"), "default": "proposal"},
|
"description": t("Dokumentart (Inhaltshinweis fuer die KI)"), "default": "proposal"},
|
||||||
|
{"name": "folderId", "type": "str", "required": False, "frontendType": "userFileFolder",
|
||||||
|
"description": t("Zielordner in Meine Dateien"),
|
||||||
|
"default": ""},
|
||||||
{"name": "context", "type": "Any", "required": False, "frontendType": "contextBuilder",
|
{"name": "context", "type": "Any", "required": False, "frontendType": "contextBuilder",
|
||||||
"description": t("Daten aus vorherigen Schritten"), "default": "",
|
"description": t("Daten aus vorherigen Schritten"), "default": "",
|
||||||
"graphInherit": {"port": 0, "kind": "primaryTextRef"}},
|
"graphInherit": {"port": 0, "kind": "primaryTextRef"}},
|
||||||
|
|
@ -177,6 +192,9 @@ AI_NODES = [
|
||||||
{"name": "resultType", "type": "str", "required": False, "frontendType": "select",
|
{"name": "resultType", "type": "str", "required": False, "frontendType": "select",
|
||||||
"frontendOptions": {"options": ["py", "js", "ts", "html", "java", "cpp", "txt", "json", "csv", "xml"]},
|
"frontendOptions": {"options": ["py", "js", "ts", "html", "java", "cpp", "txt", "json", "csv", "xml"]},
|
||||||
"description": t("Datei-Endung der erzeugten Code-Datei"), "default": "py"},
|
"description": t("Datei-Endung der erzeugten Code-Datei"), "default": "py"},
|
||||||
|
{"name": "folderId", "type": "str", "required": False, "frontendType": "userFileFolder",
|
||||||
|
"description": t("Zielordner in Meine Dateien"),
|
||||||
|
"default": ""},
|
||||||
{"name": "context", "type": "Any", "required": False, "frontendType": "contextBuilder",
|
{"name": "context", "type": "Any", "required": False, "frontendType": "contextBuilder",
|
||||||
"description": t("Daten aus vorherigen Schritten"), "default": "",
|
"description": t("Daten aus vorherigen Schritten"), "default": "",
|
||||||
"graphInherit": {"port": 0, "kind": "primaryTextRef"}},
|
"graphInherit": {"port": 0, "kind": "primaryTextRef"}},
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ FILE_NODES = [
|
||||||
"description": t("Ausgabeformat"), "default": "docx"},
|
"description": t("Ausgabeformat"), "default": "docx"},
|
||||||
{"name": "title", "type": "str", "required": False, "frontendType": "text",
|
{"name": "title", "type": "str", "required": False, "frontendType": "text",
|
||||||
"description": t("Dokumenttitel")},
|
"description": t("Dokumenttitel")},
|
||||||
|
{"name": "folderId", "type": "str", "required": False, "frontendType": "userFileFolder",
|
||||||
|
"description": t("Zielordner in Meine Dateien"),
|
||||||
|
"default": ""},
|
||||||
{"name": "context", "type": "Any", "required": False, "frontendType": "contextBuilder",
|
{"name": "context", "type": "Any", "required": False, "frontendType": "contextBuilder",
|
||||||
"description": t("Daten aus vorherigen Schritten"), "default": "",
|
"description": t("Daten aus vorherigen Schritten"), "default": "",
|
||||||
"graphInherit": {"port": 0, "kind": "primaryTextRef"}},
|
"graphInherit": {"port": 0, "kind": "primaryTextRef"}},
|
||||||
|
|
|
||||||
|
|
@ -1345,16 +1345,34 @@ class ComponentObjects:
|
||||||
return newfileName
|
return newfileName
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
def createFile(self, name: str, mimeType: str, content: bytes) -> FileItem:
|
def createFile(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
mimeType: str,
|
||||||
|
content: bytes,
|
||||||
|
folderId: Optional[str] = None,
|
||||||
|
) -> FileItem:
|
||||||
"""Creates a new file entry if user has permission. Computes fileHash and fileSize from content.
|
"""Creates a new file entry if user has permission. Computes fileHash and fileSize from content.
|
||||||
|
|
||||||
Duplicate check: if a file with the same user + fileHash + fileName already exists,
|
Duplicate check: if a file with the same user + fileHash + fileName already exists,
|
||||||
the existing file is returned instead of creating a new one.
|
the existing file is returned instead of creating a new one.
|
||||||
Same hash with different name is allowed (intentional copy by user).
|
Same hash with different name is allowed (intentional copy by user).
|
||||||
|
|
||||||
|
When ``folderId`` is set, the folder must exist and the user must be allowed to modify it.
|
||||||
"""
|
"""
|
||||||
if not self.checkRbacPermission(FileItem, "create"):
|
if not self.checkRbacPermission(FileItem, "create"):
|
||||||
raise PermissionError("No permission to create files")
|
raise PermissionError("No permission to create files")
|
||||||
|
|
||||||
|
resolved_folder_id: Optional[str] = None
|
||||||
|
if folderId is not None:
|
||||||
|
raw = str(folderId).strip()
|
||||||
|
if raw:
|
||||||
|
folder = self.getFolder(raw)
|
||||||
|
if not folder:
|
||||||
|
raise FileNotFoundError(f"Folder {raw} not found")
|
||||||
|
self._requireFolderWriteAccess(folder, raw, "update")
|
||||||
|
resolved_folder_id = raw
|
||||||
|
|
||||||
# Compute file size and hash
|
# Compute file size and hash
|
||||||
fileSize = len(content)
|
fileSize = len(content)
|
||||||
fileHash = hashlib.sha256(content).hexdigest()
|
fileHash = hashlib.sha256(content).hexdigest()
|
||||||
|
|
@ -1386,6 +1404,7 @@ class ComponentObjects:
|
||||||
mimeType=mimeType,
|
mimeType=mimeType,
|
||||||
fileSize=fileSize,
|
fileSize=fileSize,
|
||||||
fileHash=fileHash,
|
fileHash=fileHash,
|
||||||
|
folderId=resolved_folder_id,
|
||||||
)
|
)
|
||||||
# Ensure audit user is always stored: workflow/singleton contexts sometimes leave
|
# Ensure audit user is always stored: workflow/singleton contexts sometimes leave
|
||||||
# the connector without _current_user_id, so _saveRecord skips sysCreatedBy →
|
# the connector without _current_user_id, so _saveRecord skips sysCreatedBy →
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,9 @@ class FrontendType(str, Enum):
|
||||||
FILTER_EXPRESSION = "filterExpression"
|
FILTER_EXPRESSION = "filterExpression"
|
||||||
"""Filter expression builder for data.filter"""
|
"""Filter expression builder for data.filter"""
|
||||||
|
|
||||||
|
USER_FILE_FOLDER = "userFileFolder"
|
||||||
|
"""User file storage folder (graph editor): browse My Files tree or create folders."""
|
||||||
|
|
||||||
|
|
||||||
# Mapping of custom types to their API endpoint for dynamic options
|
# Mapping of custom types to their API endpoint for dynamic options
|
||||||
CUSTOM_TYPE_OPTIONS_API: Dict[FrontendType, str] = {
|
CUSTOM_TYPE_OPTIONS_API: Dict[FrontendType, str] = {
|
||||||
|
|
|
||||||
|
|
@ -393,6 +393,13 @@ class ActionNodeExecutor:
|
||||||
return _normalizeError(e, outputSchema)
|
return _normalizeError(e, outputSchema)
|
||||||
|
|
||||||
# 9. Persist generated documents as files and build JSON-safe output
|
# 9. Persist generated documents as files and build JSON-safe output
|
||||||
|
_raw_folder_id = resolvedParams.get("folderId")
|
||||||
|
persist_folder_id: Optional[str] = None
|
||||||
|
if _raw_folder_id is not None:
|
||||||
|
_s = str(_raw_folder_id).strip()
|
||||||
|
if _s:
|
||||||
|
persist_folder_id = _s
|
||||||
|
|
||||||
docsList = []
|
docsList = []
|
||||||
for d in (result.documents or []):
|
for d in (result.documents or []):
|
||||||
dumped = d.model_dump() if hasattr(d, "model_dump") else dict(d) if isinstance(d, dict) else d
|
dumped = d.model_dump() if hasattr(d, "model_dump") else dict(d) if isinstance(d, dict) else d
|
||||||
|
|
@ -432,7 +439,7 @@ class ActionNodeExecutor:
|
||||||
_mgmt = _getMgmtInterface(_owner, mandateId=_mandateId, featureInstanceId=_instanceId)
|
_mgmt = _getMgmtInterface(_owner, mandateId=_mandateId, featureInstanceId=_instanceId)
|
||||||
_docName = dumped.get("documentName") or f"workflow-result-{nodeId}.bin"
|
_docName = dumped.get("documentName") or f"workflow-result-{nodeId}.bin"
|
||||||
_mimeType = dumped.get("mimeType") or "application/octet-stream"
|
_mimeType = dumped.get("mimeType") or "application/octet-stream"
|
||||||
_fileItem = _mgmt.createFile(_docName, _mimeType, rawBytes)
|
_fileItem = _mgmt.createFile(_docName, _mimeType, rawBytes, folderId=persist_folder_id)
|
||||||
_mgmt.createFileData(_fileItem.id, rawBytes)
|
_mgmt.createFileData(_fileItem.id, rawBytes)
|
||||||
dumped["fileId"] = _fileItem.id
|
dumped["fileId"] = _fileItem.id
|
||||||
dumped["id"] = _fileItem.id
|
dumped["id"] = _fileItem.id
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,14 @@ class MethodAi(MethodBase):
|
||||||
required=False,
|
required=False,
|
||||||
default="txt",
|
default="txt",
|
||||||
description="Output file extension"
|
description="Output file extension"
|
||||||
)
|
),
|
||||||
|
"folderId": WorkflowActionParameter(
|
||||||
|
name="folderId",
|
||||||
|
type="str",
|
||||||
|
frontendType=FrontendType.USER_FILE_FOLDER,
|
||||||
|
required=False,
|
||||||
|
description="Target folder in My Files when persisting workflow output",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
execute=summarizeDocument.__get__(self, self.__class__)
|
execute=summarizeDocument.__get__(self, self.__class__)
|
||||||
),
|
),
|
||||||
|
|
@ -239,7 +246,14 @@ class MethodAi(MethodBase):
|
||||||
frontendType=FrontendType.TEXT,
|
frontendType=FrontendType.TEXT,
|
||||||
required=False,
|
required=False,
|
||||||
description="Output file extension. If not specified, uses same format as input"
|
description="Output file extension. If not specified, uses same format as input"
|
||||||
)
|
),
|
||||||
|
"folderId": WorkflowActionParameter(
|
||||||
|
name="folderId",
|
||||||
|
type="str",
|
||||||
|
frontendType=FrontendType.USER_FILE_FOLDER,
|
||||||
|
required=False,
|
||||||
|
description="Target folder in My Files when persisting workflow output",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
execute=translateDocument.__get__(self, self.__class__)
|
execute=translateDocument.__get__(self, self.__class__)
|
||||||
),
|
),
|
||||||
|
|
@ -271,7 +285,14 @@ class MethodAi(MethodBase):
|
||||||
required=False,
|
required=False,
|
||||||
default=True,
|
default=True,
|
||||||
description="Whether to preserve document structure (headings, tables, etc.)"
|
description="Whether to preserve document structure (headings, tables, etc.)"
|
||||||
)
|
),
|
||||||
|
"folderId": WorkflowActionParameter(
|
||||||
|
name="folderId",
|
||||||
|
type="str",
|
||||||
|
frontendType=FrontendType.USER_FILE_FOLDER,
|
||||||
|
required=False,
|
||||||
|
description="Target folder in My Files when persisting workflow output",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
execute=convertDocument.__get__(self, self.__class__)
|
execute=convertDocument.__get__(self, self.__class__)
|
||||||
),
|
),
|
||||||
|
|
@ -335,6 +356,13 @@ class MethodAi(MethodBase):
|
||||||
required=False,
|
required=False,
|
||||||
description="Legacy/API output format extension (e.g. txt, docx). Ignored when outputFormat is set."
|
description="Legacy/API output format extension (e.g. txt, docx). Ignored when outputFormat is set."
|
||||||
),
|
),
|
||||||
|
"folderId": WorkflowActionParameter(
|
||||||
|
name="folderId",
|
||||||
|
type="str",
|
||||||
|
frontendType=FrontendType.USER_FILE_FOLDER,
|
||||||
|
required=False,
|
||||||
|
description="Target folder in My Files when persisting workflow output",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
execute=generateDocument.__get__(self, self.__class__)
|
execute=generateDocument.__get__(self, self.__class__)
|
||||||
),
|
),
|
||||||
|
|
@ -366,7 +394,14 @@ class MethodAi(MethodBase):
|
||||||
frontendOptions=["py", "js", "ts", "html", "java", "cpp", "txt", "json", "csv", "xml"],
|
frontendOptions=["py", "js", "ts", "html", "java", "cpp", "txt", "json", "csv", "xml"],
|
||||||
required=False,
|
required=False,
|
||||||
description="Output format (html, js, py, json, csv, xml, etc.). Optional: if omitted, formats are determined from prompt by AI. This action can return MULTIPLE files in a single call when the prompt requests multiple files. With per-document format determination, AI can determine different formats for different files based on prompt. When multiple files are requested, the action will return multiple documents (one per file)."
|
description="Output format (html, js, py, json, csv, xml, etc.). Optional: if omitted, formats are determined from prompt by AI. This action can return MULTIPLE files in a single call when the prompt requests multiple files. With per-document format determination, AI can determine different formats for different files based on prompt. When multiple files are requested, the action will return multiple documents (one per file)."
|
||||||
)
|
),
|
||||||
|
"folderId": WorkflowActionParameter(
|
||||||
|
name="folderId",
|
||||||
|
type="str",
|
||||||
|
frontendType=FrontendType.USER_FILE_FOLDER,
|
||||||
|
required=False,
|
||||||
|
description="Target folder in My Files when persisting workflow output",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
execute=generateCode.__get__(self, self.__class__)
|
execute=generateCode.__get__(self, self.__class__)
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright (c) 2025 Patrick Motsch
|
# Copyright (c) 2025 Patrick Motsch
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import binascii
|
import binascii
|
||||||
|
|
@ -17,6 +17,7 @@ logger = logging.getLogger(__name__)
|
||||||
def _persistDocumentsToUserFiles(
|
def _persistDocumentsToUserFiles(
|
||||||
action_documents: list,
|
action_documents: list,
|
||||||
services,
|
services,
|
||||||
|
folder_id: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Persist file.create output documents to user's file storage (like upload).
|
"""Persist file.create output documents to user's file storage (like upload).
|
||||||
Adds fileId to each document's validationMetadata for download links in UI."""
|
Adds fileId to each document's validationMetadata for download links in UI."""
|
||||||
|
|
@ -70,7 +71,7 @@ def _persistDocumentsToUserFiles(
|
||||||
doc_name,
|
doc_name,
|
||||||
len(content),
|
len(content),
|
||||||
)
|
)
|
||||||
file_item = mgmt.createFile(doc_name, mime, content)
|
file_item = mgmt.createFile(doc_name, mime, content, folderId=folder_id)
|
||||||
logger.info("file.create persist: createFile returned id=%s", file_item.id)
|
logger.info("file.create persist: createFile returned id=%s", file_item.id)
|
||||||
ok = mgmt.createFileData(file_item.id, content)
|
ok = mgmt.createFileData(file_item.id, content)
|
||||||
logger.info("file.create persist: createFileData returned %s for id=%s", ok, file_item.id)
|
logger.info("file.create persist: createFileData returned %s for id=%s", ok, file_item.id)
|
||||||
|
|
@ -111,6 +112,11 @@ async def create(self, parameters: Dict[str, Any]) -> ActionResult:
|
||||||
"de",
|
"de",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
folder_id: Optional[str] = None
|
||||||
|
raw_folder = parameters.get("folderId")
|
||||||
|
if raw_folder is not None and str(raw_folder).strip():
|
||||||
|
folder_id = str(raw_folder).strip()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
structured_content = markdownToDocumentJson(context, title, language)
|
structured_content = markdownToDocumentJson(context, title, language)
|
||||||
if templateName:
|
if templateName:
|
||||||
|
|
@ -164,7 +170,7 @@ async def create(self, parameters: Dict[str, Any]) -> ActionResult:
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|
||||||
_persistDocumentsToUserFiles(action_documents, self.services)
|
_persistDocumentsToUserFiles(action_documents, self.services, folder_id=folder_id)
|
||||||
return ActionResult.isSuccess(documents=action_documents)
|
return ActionResult.isSuccess(documents=action_documents)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,13 @@ class MethodFile(MethodBase):
|
||||||
default="de",
|
default="de",
|
||||||
description="Language code",
|
description="Language code",
|
||||||
),
|
),
|
||||||
|
"folderId": WorkflowActionParameter(
|
||||||
|
name="folderId",
|
||||||
|
type="str",
|
||||||
|
frontendType=FrontendType.USER_FILE_FOLDER,
|
||||||
|
required=False,
|
||||||
|
description="Optional My Files folder to store created documents",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
execute=create.__get__(self, self.__class__),
|
execute=create.__get__(self, self.__class__),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue