mirror of
https://github.com/langgenius/dify.git
synced 2026-07-21 02:28:30 +08:00
refactor(web): migrate snippet console contracts (#38258)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
37bcb60c26
commit
8540ca9242
@ -1,11 +1,13 @@
|
||||
import logging
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from urllib.parse import quote
|
||||
|
||||
from flask import Response, request
|
||||
from flask_restx import Resource, marshal
|
||||
from pydantic import RootModel
|
||||
from pydantic import Field as PydanticField
|
||||
from pydantic import field_validator
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
from werkzeug.datastructures import MultiDict
|
||||
from werkzeug.exceptions import NotFound
|
||||
@ -30,27 +32,34 @@ from controllers.console.wraps import (
|
||||
with_current_tenant_id,
|
||||
with_current_user,
|
||||
)
|
||||
from core.plugin.entities.plugin import PluginDependency
|
||||
from extensions.ext_database import db
|
||||
from fields.base import ResponseModel
|
||||
from fields.snippet_fields import snippet_fields, snippet_list_fields, snippet_pagination_fields
|
||||
from fields.snippet_fields import snippet_fields, snippet_list_fields
|
||||
from libs.helper import to_timestamp
|
||||
from libs.login import login_required
|
||||
from models import Account
|
||||
from models.snippet import SnippetType
|
||||
from services.app_dsl_service import ImportStatus
|
||||
from services.snippet_dsl_service import SnippetDslService
|
||||
from services.snippet_dsl_service import ImportStatus, SnippetDslService
|
||||
from services.snippet_service import SnippetService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_TAG_IDS_BRACKET_PATTERN = re.compile(r"^tag_ids\[(\d+)\]$")
|
||||
_CREATOR_IDS_BRACKET_PATTERN = re.compile(r"^creator_ids\[(\d+)\]$")
|
||||
_CREATORS_BRACKET_PATTERN = re.compile(r"^creators\[(\d+)\]$")
|
||||
|
||||
|
||||
class SnippetImportResponse(RootModel[dict[str, Any]]):
|
||||
root: dict[str, Any]
|
||||
class SnippetImportResponse(ResponseModel):
|
||||
id: str
|
||||
status: ImportStatus
|
||||
snippet_id: str | None
|
||||
current_dsl_version: str
|
||||
imported_dsl_version: str
|
||||
error: str
|
||||
|
||||
|
||||
class SnippetDependencyCheckResponse(RootModel[dict[str, Any]]):
|
||||
root: dict[str, Any]
|
||||
class SnippetDependencyCheckResponse(ResponseModel):
|
||||
leaked_dependencies: list[PluginDependency]
|
||||
|
||||
|
||||
class SnippetUseCountResponse(ResponseModel):
|
||||
@ -58,6 +67,77 @@ class SnippetUseCountResponse(ResponseModel):
|
||||
use_count: int
|
||||
|
||||
|
||||
class SnippetTagResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
|
||||
|
||||
class SnippetAccountResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
email: str
|
||||
|
||||
|
||||
class SnippetListItemResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str | None
|
||||
type: SnippetType
|
||||
version: int
|
||||
use_count: int
|
||||
is_published: bool
|
||||
icon_info: dict[str, Any] | None
|
||||
tags: list[SnippetTagResponse]
|
||||
created_by: str | None
|
||||
author_name: str | None
|
||||
created_at: int
|
||||
updated_by: str | None
|
||||
updated_at: int
|
||||
|
||||
@field_validator("created_at", "updated_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_timestamp(cls, value: datetime | int | None) -> int:
|
||||
timestamp = to_timestamp(value)
|
||||
if timestamp is None:
|
||||
raise ValueError("timestamp is required")
|
||||
return timestamp
|
||||
|
||||
|
||||
class SnippetResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str | None
|
||||
type: SnippetType
|
||||
version: int
|
||||
use_count: int
|
||||
is_published: bool
|
||||
icon_info: dict[str, Any] | None
|
||||
graph: dict[str, Any] = PydanticField(validation_alias="graph_dict")
|
||||
input_fields: list[dict[str, Any]] = PydanticField(validation_alias="input_fields_list")
|
||||
tags: list[SnippetTagResponse]
|
||||
created_by: SnippetAccountResponse | None = PydanticField(validation_alias="created_by_account")
|
||||
created_at: int
|
||||
updated_by: SnippetAccountResponse | None = PydanticField(validation_alias="updated_by_account")
|
||||
updated_at: int
|
||||
|
||||
@field_validator("created_at", "updated_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_timestamp(cls, value: datetime | int | None) -> int:
|
||||
timestamp = to_timestamp(value)
|
||||
if timestamp is None:
|
||||
raise ValueError("timestamp is required")
|
||||
return timestamp
|
||||
|
||||
|
||||
class SnippetPaginationResponse(ResponseModel):
|
||||
data: list[SnippetListItemResponse]
|
||||
page: int
|
||||
limit: int
|
||||
total: int
|
||||
has_more: bool
|
||||
|
||||
|
||||
def _snippet_service() -> SnippetService:
|
||||
return SnippetService(sessionmaker(bind=db.engine, expire_on_commit=False))
|
||||
|
||||
@ -73,11 +153,19 @@ def _normalize_snippet_list_query_args(query_args: MultiDict[str, str]) -> dict[
|
||||
indexed_tag_ids.extend((int(match.group(1)), value) for value in query_args.getlist(key))
|
||||
continue
|
||||
|
||||
match = _CREATOR_IDS_BRACKET_PATTERN.fullmatch(key)
|
||||
match = _CREATOR_IDS_BRACKET_PATTERN.fullmatch(key) or _CREATORS_BRACKET_PATTERN.fullmatch(key)
|
||||
if match:
|
||||
indexed_creator_ids.extend((int(match.group(1)), value) for value in query_args.getlist(key))
|
||||
continue
|
||||
|
||||
if key in {"tag_ids", "creators", "creator_ids"}:
|
||||
values = query_args.getlist(key)
|
||||
if values:
|
||||
normalized["creators" if key in {"creators", "creator_ids"} else key] = (
|
||||
values if len(values) > 1 else values[0]
|
||||
)
|
||||
continue
|
||||
|
||||
value = query_args.get(key)
|
||||
if value is not None:
|
||||
normalized[key] = value
|
||||
@ -105,19 +193,17 @@ register_response_schema_models(
|
||||
SnippetImportResponse,
|
||||
SnippetDependencyCheckResponse,
|
||||
SnippetUseCountResponse,
|
||||
SnippetListItemResponse,
|
||||
SnippetResponse,
|
||||
SnippetPaginationResponse,
|
||||
)
|
||||
|
||||
# Create namespace models for marshaling
|
||||
snippet_model = console_ns.model("Snippet", snippet_fields)
|
||||
snippet_list_model = console_ns.model("SnippetList", snippet_list_fields)
|
||||
snippet_pagination_model = console_ns.model("SnippetPagination", snippet_pagination_fields)
|
||||
|
||||
|
||||
@console_ns.route("/workspaces/current/customized-snippets")
|
||||
class CustomizedSnippetsApi(Resource):
|
||||
@console_ns.doc("list_customized_snippets")
|
||||
@console_ns.doc(params=query_params_from_model(SnippetListQuery))
|
||||
@console_ns.response(200, "Snippets retrieved successfully", snippet_pagination_model)
|
||||
@console_ns.response(200, "Snippets retrieved successfully", console_ns.models[SnippetPaginationResponse.__name__])
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@ -148,7 +234,7 @@ class CustomizedSnippetsApi(Resource):
|
||||
|
||||
@console_ns.doc("create_customized_snippet")
|
||||
@console_ns.expect(console_ns.models.get(CreateSnippetPayload.__name__))
|
||||
@console_ns.response(201, "Snippet created successfully", snippet_model)
|
||||
@console_ns.response(201, "Snippet created successfully", console_ns.models[SnippetResponse.__name__])
|
||||
@console_ns.response(400, "Invalid request")
|
||||
@setup_required
|
||||
@login_required
|
||||
@ -191,7 +277,7 @@ class CustomizedSnippetsApi(Resource):
|
||||
@console_ns.route("/workspaces/current/customized-snippets/<uuid:snippet_id>")
|
||||
class CustomizedSnippetDetailApi(Resource):
|
||||
@console_ns.doc("get_customized_snippet")
|
||||
@console_ns.response(200, "Snippet retrieved successfully", snippet_model)
|
||||
@console_ns.response(200, "Snippet retrieved successfully", console_ns.models[SnippetResponse.__name__])
|
||||
@console_ns.response(404, "Snippet not found")
|
||||
@setup_required
|
||||
@login_required
|
||||
@ -212,7 +298,7 @@ class CustomizedSnippetDetailApi(Resource):
|
||||
|
||||
@console_ns.doc("update_customized_snippet")
|
||||
@console_ns.expect(console_ns.models.get(UpdateSnippetPayload.__name__))
|
||||
@console_ns.response(200, "Snippet updated successfully", snippet_model)
|
||||
@console_ns.response(200, "Snippet updated successfully", console_ns.models[SnippetResponse.__name__])
|
||||
@console_ns.response(400, "Invalid request")
|
||||
@console_ns.response(404, "Snippet not found")
|
||||
@setup_required
|
||||
|
||||
@ -9761,7 +9761,7 @@ Get list of available agent providers
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Snippets retrieved successfully | **application/json**: [SnippetPagination](#snippetpagination)<br> |
|
||||
| 200 | Snippets retrieved successfully | **application/json**: [SnippetPaginationResponse](#snippetpaginationresponse)<br> |
|
||||
|
||||
### [POST] /workspaces/current/customized-snippets
|
||||
**Create a new customized snippet**
|
||||
@ -9776,7 +9776,7 @@ Get list of available agent providers
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 201 | Snippet created successfully | **application/json**: [Snippet](#snippet)<br> |
|
||||
| 201 | Snippet created successfully | **application/json**: [SnippetResponse](#snippetresponse)<br> |
|
||||
| 400 | Invalid request | |
|
||||
|
||||
### [POST] /workspaces/current/customized-snippets/imports
|
||||
@ -9841,7 +9841,7 @@ Get list of available agent providers
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Snippet retrieved successfully | **application/json**: [Snippet](#snippet)<br> |
|
||||
| 200 | Snippet retrieved successfully | **application/json**: [SnippetResponse](#snippetresponse)<br> |
|
||||
| 404 | Snippet not found | |
|
||||
|
||||
### [PATCH] /workspaces/current/customized-snippets/{snippet_id}
|
||||
@ -9863,7 +9863,7 @@ Get list of available agent providers
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Snippet updated successfully | **application/json**: [Snippet](#snippet)<br> |
|
||||
| 200 | Snippet updated successfully | **application/json**: [SnippetResponse](#snippetresponse)<br> |
|
||||
| 400 | Invalid request | |
|
||||
| 404 | Snippet not found | |
|
||||
|
||||
@ -20667,31 +20667,19 @@ Validated metadata extracted from a Skill package.
|
||||
| inferable | boolean | | Yes |
|
||||
| reason | string | | No |
|
||||
|
||||
#### Snippet
|
||||
#### SnippetAccountResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | long | | No |
|
||||
| created_by | [_AnonymousInlineModel_b0fd3f86d9d5](#_anonymousinlinemodel_b0fd3f86d9d5) | | No |
|
||||
| description | string | | No |
|
||||
| graph | object | | No |
|
||||
| icon_info | object | | No |
|
||||
| id | string | | No |
|
||||
| input_fields | object | | No |
|
||||
| is_published | boolean | | No |
|
||||
| name | string | | No |
|
||||
| tags | [ [_AnonymousInlineModel_7b8b49ca164e](#_anonymousinlinemodel_7b8b49ca164e) ] | | No |
|
||||
| type | string | | No |
|
||||
| updated_at | long | | No |
|
||||
| updated_by | [_AnonymousInlineModel_b0fd3f86d9d5](#_anonymousinlinemodel_b0fd3f86d9d5) | | No |
|
||||
| use_count | integer | | No |
|
||||
| version | integer | | No |
|
||||
| email | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| name | string | | Yes |
|
||||
|
||||
#### SnippetDependencyCheckResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| SnippetDependencyCheckResponse | object | | |
|
||||
| leaked_dependencies | [ [PluginDependency](#plugindependency) ] | | Yes |
|
||||
|
||||
#### SnippetDraftConfigResponse
|
||||
|
||||
@ -20746,7 +20734,12 @@ Payload for importing snippet from DSL.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| SnippetImportResponse | object | | |
|
||||
| current_dsl_version | string | | Yes |
|
||||
| error | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| imported_dsl_version | string | | Yes |
|
||||
| snippet_id | string | | Yes |
|
||||
| status | [ImportStatus](#importstatus) | | Yes |
|
||||
|
||||
#### SnippetIterationNodeRunPayload
|
||||
|
||||
@ -20756,24 +20749,24 @@ Payload for running an iteration node in snippet draft workflow.
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| inputs | object | | No |
|
||||
|
||||
#### SnippetList
|
||||
#### SnippetListItemResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| author_name | string | | No |
|
||||
| created_at | long | | No |
|
||||
| created_by | string | | No |
|
||||
| description | string | | No |
|
||||
| icon_info | object | | No |
|
||||
| id | string | | No |
|
||||
| is_published | boolean | | No |
|
||||
| name | string | | No |
|
||||
| tags | [ [_AnonymousInlineModel_7b8b49ca164e](#_anonymousinlinemodel_7b8b49ca164e) ] | | No |
|
||||
| type | string | | No |
|
||||
| updated_at | long | | No |
|
||||
| updated_by | string | | No |
|
||||
| use_count | integer | | No |
|
||||
| version | integer | | No |
|
||||
| author_name | string | | Yes |
|
||||
| created_at | integer | | Yes |
|
||||
| created_by | string | | Yes |
|
||||
| description | string | | Yes |
|
||||
| icon_info | object | | Yes |
|
||||
| id | string | | Yes |
|
||||
| is_published | boolean | | Yes |
|
||||
| name | string | | Yes |
|
||||
| tags | [ [SnippetTagResponse](#snippettagresponse) ] | | Yes |
|
||||
| type | [SnippetType](#snippettype) | | Yes |
|
||||
| updated_at | integer | | Yes |
|
||||
| updated_by | string | | Yes |
|
||||
| use_count | integer | | Yes |
|
||||
| version | integer | | Yes |
|
||||
|
||||
#### SnippetListQuery
|
||||
|
||||
@ -20796,15 +20789,51 @@ Payload for running a loop node in snippet draft workflow.
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| inputs | object | | No |
|
||||
|
||||
#### SnippetPagination
|
||||
#### SnippetPaginationResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| data | [ [_AnonymousInlineModel_744ff9cc03e6](#_anonymousinlinemodel_744ff9cc03e6) ] | | No |
|
||||
| has_more | boolean | | No |
|
||||
| limit | integer | | No |
|
||||
| page | integer | | No |
|
||||
| total | integer | | No |
|
||||
| data | [ [SnippetListItemResponse](#snippetlistitemresponse) ] | | Yes |
|
||||
| has_more | boolean | | Yes |
|
||||
| limit | integer | | Yes |
|
||||
| page | integer | | Yes |
|
||||
| total | integer | | Yes |
|
||||
|
||||
#### SnippetResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | Yes |
|
||||
| created_by | [SnippetAccountResponse](#snippetaccountresponse) | | Yes |
|
||||
| description | string | | Yes |
|
||||
| graph | object | | Yes |
|
||||
| icon_info | object | | Yes |
|
||||
| id | string | | Yes |
|
||||
| input_fields | [ object ] | | Yes |
|
||||
| is_published | boolean | | Yes |
|
||||
| name | string | | Yes |
|
||||
| tags | [ [SnippetTagResponse](#snippettagresponse) ] | | Yes |
|
||||
| type | [SnippetType](#snippettype) | | Yes |
|
||||
| updated_at | integer | | Yes |
|
||||
| updated_by | [SnippetAccountResponse](#snippetaccountresponse) | | Yes |
|
||||
| use_count | integer | | Yes |
|
||||
| version | integer | | Yes |
|
||||
|
||||
#### SnippetTagResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| id | string | | Yes |
|
||||
| name | string | | Yes |
|
||||
| type | string | | Yes |
|
||||
|
||||
#### SnippetType
|
||||
|
||||
Snippet Type Enum
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| SnippetType | string | Snippet Type Enum | |
|
||||
|
||||
#### SnippetUseCountResponse
|
||||
|
||||
@ -22862,41 +22891,6 @@ Workflow tool configuration
|
||||
| data | [ [AccessPolicy](#accesspolicy) ] | | No |
|
||||
| pagination | [Pagination](#pagination) | | No |
|
||||
|
||||
#### _AnonymousInlineModel_744ff9cc03e6
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| author_name | string | | No |
|
||||
| created_at | long | | No |
|
||||
| created_by | string | | No |
|
||||
| description | string | | No |
|
||||
| icon_info | object | | No |
|
||||
| id | string | | No |
|
||||
| is_published | boolean | | No |
|
||||
| name | string | | No |
|
||||
| tags | [ [_AnonymousInlineModel_7b8b49ca164e](#_anonymousinlinemodel_7b8b49ca164e) ] | | No |
|
||||
| type | string | | No |
|
||||
| updated_at | long | | No |
|
||||
| updated_by | string | | No |
|
||||
| use_count | integer | | No |
|
||||
| version | integer | | No |
|
||||
|
||||
#### _AnonymousInlineModel_7b8b49ca164e
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| id | string | | No |
|
||||
| name | string | | No |
|
||||
| type | string | | No |
|
||||
|
||||
#### _AnonymousInlineModel_b0fd3f86d9d5
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| email | string | | No |
|
||||
| id | string | | No |
|
||||
| name | string | | No |
|
||||
|
||||
#### _AnonymousInlineModel_b1954337d565
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
from datetime import UTC, datetime
|
||||
from inspect import unwrap
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import ANY, Mock
|
||||
@ -8,7 +9,6 @@ from werkzeug.exceptions import NotFound
|
||||
|
||||
from controllers.console.workspace import snippets as snippets_module
|
||||
from models.account import Account, TenantAccountRole
|
||||
from models.snippet import CustomizedSnippet
|
||||
from services.snippet_dsl_service import ImportStatus, SnippetImportInfo
|
||||
|
||||
|
||||
@ -39,17 +39,30 @@ def _account(account_id: str = "account-1") -> Account:
|
||||
return account
|
||||
|
||||
|
||||
def _snippet(**overrides) -> CustomizedSnippet:
|
||||
def _snippet(**overrides) -> SimpleNamespace:
|
||||
data = {
|
||||
"id": "snippet-1",
|
||||
"tenant_id": "tenant-1",
|
||||
"name": "Snippet",
|
||||
"description": "Description",
|
||||
"type": snippets_module.SnippetType.NODE,
|
||||
"created_by": "account-1",
|
||||
"version": 1,
|
||||
"use_count": 0,
|
||||
"is_published": False,
|
||||
"icon_info": None,
|
||||
"graph_dict": {},
|
||||
"input_fields_list": [],
|
||||
"tags": [],
|
||||
"created_by": None,
|
||||
"author_name": None,
|
||||
"created_by_account": None,
|
||||
"created_at": datetime.fromtimestamp(1_704_067_200, UTC),
|
||||
"updated_by": None,
|
||||
"updated_by_account": None,
|
||||
"updated_at": datetime.fromtimestamp(1_704_153_600, UTC),
|
||||
}
|
||||
data.update(overrides)
|
||||
return CustomizedSnippet(**data)
|
||||
return SimpleNamespace(**data)
|
||||
|
||||
|
||||
def test_normalize_snippet_list_query_args_sorts_indexed_values():
|
||||
@ -70,24 +83,66 @@ def test_normalize_snippet_list_query_args_sorts_indexed_values():
|
||||
}
|
||||
|
||||
|
||||
def test_normalize_snippet_list_query_args_accepts_generated_creator_keys():
|
||||
query_args = snippets_module.MultiDict(
|
||||
[
|
||||
("creators[1]", "account-b"),
|
||||
("creators[0]", "account-a"),
|
||||
]
|
||||
)
|
||||
|
||||
assert snippets_module._normalize_snippet_list_query_args(query_args) == {
|
||||
"creators": ["account-a", "account-b"],
|
||||
}
|
||||
|
||||
|
||||
def test_normalize_snippet_list_query_args_accepts_repeated_creator_keys():
|
||||
query_args = snippets_module.MultiDict(
|
||||
[
|
||||
("creators", "account-a"),
|
||||
("creators", "account-b"),
|
||||
]
|
||||
)
|
||||
|
||||
assert snippets_module._normalize_snippet_list_query_args(query_args) == {
|
||||
"creators": ["account-a", "account-b"],
|
||||
}
|
||||
|
||||
|
||||
def test_list_snippets_returns_pagination(app: Flask, monkeypatch: pytest.MonkeyPatch):
|
||||
snippets = [_snippet()]
|
||||
tag_id = "11111111-1111-1111-1111-111111111111"
|
||||
get_snippets = Mock(return_value=(snippets, 1, False))
|
||||
monkeypatch.setattr(snippets_module.SnippetService, "get_snippets", get_snippets)
|
||||
monkeypatch.setattr(snippets_module, "marshal", Mock(return_value=[{"id": "snippet-1"}]))
|
||||
|
||||
api = snippets_module.CustomizedSnippetsApi()
|
||||
handler = unwrap(api.get)
|
||||
|
||||
with app.test_request_context(
|
||||
f"/workspaces/current/customized-snippets?page=2&limit=10&tag_ids[0]={tag_id}&creator_ids[0]=account-2"
|
||||
f"/workspaces/current/customized-snippets?page=2&limit=10&tag_ids[0]={tag_id}&creators[0]=account-2"
|
||||
):
|
||||
response, status_code = handler(api, "tenant-1")
|
||||
|
||||
assert status_code == 200
|
||||
assert response == {
|
||||
"data": [{"id": "snippet-1"}],
|
||||
"data": [
|
||||
{
|
||||
"id": "snippet-1",
|
||||
"name": "Snippet",
|
||||
"description": "Description",
|
||||
"type": snippets_module.SnippetType.NODE.value,
|
||||
"version": 1,
|
||||
"use_count": 0,
|
||||
"is_published": False,
|
||||
"icon_info": None,
|
||||
"tags": [],
|
||||
"created_by": None,
|
||||
"author_name": None,
|
||||
"created_at": 1_704_067_200,
|
||||
"updated_by": None,
|
||||
"updated_at": 1_704_153_600,
|
||||
}
|
||||
],
|
||||
"page": 2,
|
||||
"limit": 10,
|
||||
"total": 1,
|
||||
@ -124,7 +179,6 @@ def test_create_snippet_defaults_unknown_type_and_returns_created(app: Flask, mo
|
||||
)
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(snippets_module, "marshal", Mock(return_value={"id": "snippet-1"}))
|
||||
|
||||
api = snippets_module.CustomizedSnippetsApi()
|
||||
handler = unwrap(api.post)
|
||||
@ -137,7 +191,8 @@ def test_create_snippet_defaults_unknown_type_and_returns_created(app: Flask, mo
|
||||
response, status_code = handler(api, "tenant-1", user)
|
||||
|
||||
assert status_code == 201
|
||||
assert response == {"id": "snippet-1"}
|
||||
assert response["id"] == "snippet-1"
|
||||
assert response["type"] == snippets_module.SnippetType.NODE.value
|
||||
assert create_snippet.call_args.kwargs["snippet_type"] == snippets_module.SnippetType.NODE
|
||||
|
||||
|
||||
@ -184,7 +239,6 @@ def test_get_snippet_detail_raises_when_missing(app: Flask, monkeypatch: pytest.
|
||||
def test_get_snippet_detail_returns_snippet(app: Flask, monkeypatch: pytest.MonkeyPatch):
|
||||
snippet = _snippet()
|
||||
monkeypatch.setattr(snippets_module.SnippetService, "get_snippet_by_id", Mock(return_value=snippet))
|
||||
monkeypatch.setattr(snippets_module, "marshal", Mock(return_value={"id": "snippet-1"}))
|
||||
|
||||
api = snippets_module.CustomizedSnippetDetailApi()
|
||||
handler = unwrap(api.get)
|
||||
@ -193,7 +247,8 @@ def test_get_snippet_detail_returns_snippet(app: Flask, monkeypatch: pytest.Monk
|
||||
response, status_code = handler(api, "tenant-1", snippet_id="snippet-1")
|
||||
|
||||
assert status_code == 200
|
||||
assert response == {"id": "snippet-1"}
|
||||
assert response["id"] == "snippet-1"
|
||||
assert response["name"] == "Snippet"
|
||||
|
||||
|
||||
def test_patch_snippet_returns_400_for_empty_payload(app: Flask, monkeypatch: pytest.MonkeyPatch):
|
||||
@ -230,7 +285,6 @@ def test_patch_snippet_updates_and_commits(app: Flask, monkeypatch: pytest.Monke
|
||||
monkeypatch.setattr(snippets_module.SnippetService, "update_snippet", update_snippet)
|
||||
monkeypatch.setattr(snippets_module, "Session", SessionContext)
|
||||
monkeypatch.setattr(snippets_module, "db", SimpleNamespace(engine=object()))
|
||||
monkeypatch.setattr(snippets_module, "marshal", Mock(return_value={"id": "snippet-1", "name": "New"}))
|
||||
|
||||
api = snippets_module.CustomizedSnippetDetailApi()
|
||||
handler = unwrap(api.patch)
|
||||
@ -243,7 +297,8 @@ def test_patch_snippet_updates_and_commits(app: Flask, monkeypatch: pytest.Monke
|
||||
response, status_code = handler(api, "tenant-1", user, snippet_id="snippet-1")
|
||||
|
||||
assert status_code == 200
|
||||
assert response == {"id": "snippet-1", "name": "New"}
|
||||
assert response["id"] == "snippet-1"
|
||||
assert response["name"] == "New"
|
||||
update_snippet.assert_called_once()
|
||||
assert update_snippet.call_args.kwargs["data"] == {
|
||||
"name": "New",
|
||||
@ -428,9 +483,7 @@ def test_check_dependencies_raises_when_snippet_missing(app: Flask, monkeypatch:
|
||||
|
||||
def test_check_dependencies_returns_dependency_result(app: Flask, monkeypatch: pytest.MonkeyPatch):
|
||||
snippet = _snippet()
|
||||
check_dependencies = Mock(
|
||||
return_value=SimpleNamespace(model_dump=Mock(return_value={"dependencies": [], "missing_dependencies": []}))
|
||||
)
|
||||
check_dependencies = Mock(return_value=SimpleNamespace(model_dump=Mock(return_value={"leaked_dependencies": []})))
|
||||
session = SimpleNamespace()
|
||||
|
||||
class SessionContext(_SessionContext):
|
||||
@ -453,7 +506,7 @@ def test_check_dependencies_returns_dependency_result(app: Flask, monkeypatch: p
|
||||
response, status_code = handler(api, "tenant-1", snippet_id="snippet-1")
|
||||
|
||||
assert status_code == 200
|
||||
assert response == {"dependencies": [], "missing_dependencies": []}
|
||||
assert response == {"leaked_dependencies": []}
|
||||
check_dependencies.assert_called_once_with(snippet=snippet)
|
||||
|
||||
|
||||
|
||||
@ -7357,11 +7357,6 @@
|
||||
"count": 4
|
||||
}
|
||||
},
|
||||
"web/service/use-snippet-workflows.ts": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/service/use-tools.ts": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
|
||||
@ -31,12 +31,12 @@ export type AgentProviderListResponse = Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
|
||||
export type SnippetPagination = {
|
||||
data?: Array<AnonymousInlineModel744Ff9Cc03E6>
|
||||
has_more?: boolean
|
||||
limit?: number
|
||||
page?: number
|
||||
total?: number
|
||||
export type SnippetPaginationResponse = {
|
||||
data: Array<SnippetListItemResponse>
|
||||
has_more: boolean
|
||||
limit: number
|
||||
page: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export type CreateSnippetPayload = {
|
||||
@ -50,28 +50,28 @@ export type CreateSnippetPayload = {
|
||||
type?: 'group' | 'node'
|
||||
}
|
||||
|
||||
export type Snippet = {
|
||||
created_at?: number
|
||||
created_by?: AnonymousInlineModelB0Fd3F86D9D5
|
||||
description?: string
|
||||
graph?: {
|
||||
export type SnippetResponse = {
|
||||
created_at: number
|
||||
created_by: SnippetAccountResponse | null
|
||||
description: string | null
|
||||
graph: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
icon_info?: {
|
||||
icon_info: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
id?: string
|
||||
input_fields?: {
|
||||
} | null
|
||||
id: string
|
||||
input_fields: Array<{
|
||||
[key: string]: unknown
|
||||
}
|
||||
is_published?: boolean
|
||||
name?: string
|
||||
tags?: Array<AnonymousInlineModel7B8B49Ca164e>
|
||||
type?: string
|
||||
updated_at?: number
|
||||
updated_by?: AnonymousInlineModelB0Fd3F86D9D5
|
||||
use_count?: number
|
||||
version?: number
|
||||
}>
|
||||
is_published: boolean
|
||||
name: string
|
||||
tags: Array<SnippetTagResponse>
|
||||
type: SnippetType
|
||||
updated_at: number
|
||||
updated_by: SnippetAccountResponse | null
|
||||
use_count: number
|
||||
version: number
|
||||
}
|
||||
|
||||
export type SnippetImportPayload = {
|
||||
@ -84,7 +84,12 @@ export type SnippetImportPayload = {
|
||||
}
|
||||
|
||||
export type SnippetImportResponse = {
|
||||
[key: string]: unknown
|
||||
current_dsl_version: string
|
||||
error: string
|
||||
id: string
|
||||
imported_dsl_version: string
|
||||
snippet_id: string | null
|
||||
status: ImportStatus
|
||||
}
|
||||
|
||||
export type UpdateSnippetPayload = {
|
||||
@ -94,7 +99,7 @@ export type UpdateSnippetPayload = {
|
||||
}
|
||||
|
||||
export type SnippetDependencyCheckResponse = {
|
||||
[key: string]: unknown
|
||||
leaked_dependencies: Array<PluginDependency>
|
||||
}
|
||||
|
||||
export type TextFileResponse = string
|
||||
@ -944,23 +949,23 @@ export type WorkspaceCustomConfigResponse = {
|
||||
replace_webapp_logo?: string | null
|
||||
}
|
||||
|
||||
export type AnonymousInlineModel744Ff9Cc03E6 = {
|
||||
author_name?: string
|
||||
created_at?: number
|
||||
created_by?: string
|
||||
description?: string
|
||||
icon_info?: {
|
||||
export type SnippetListItemResponse = {
|
||||
author_name: string | null
|
||||
created_at: number
|
||||
created_by: string | null
|
||||
description: string | null
|
||||
icon_info: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
id?: string
|
||||
is_published?: boolean
|
||||
name?: string
|
||||
tags?: Array<AnonymousInlineModel7B8B49Ca164e>
|
||||
type?: string
|
||||
updated_at?: number
|
||||
updated_by?: string
|
||||
use_count?: number
|
||||
version?: number
|
||||
} | null
|
||||
id: string
|
||||
is_published: boolean
|
||||
name: string
|
||||
tags: Array<SnippetTagResponse>
|
||||
type: SnippetType
|
||||
updated_at: number
|
||||
updated_by: string | null
|
||||
use_count: number
|
||||
version: number
|
||||
}
|
||||
|
||||
export type IconInfo = {
|
||||
@ -981,16 +986,26 @@ export type InputFieldDefinition = {
|
||||
type?: string | null
|
||||
}
|
||||
|
||||
export type AnonymousInlineModelB0Fd3F86D9D5 = {
|
||||
email?: string
|
||||
id?: string
|
||||
name?: string
|
||||
export type SnippetAccountResponse = {
|
||||
email: string
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export type AnonymousInlineModel7B8B49Ca164e = {
|
||||
id?: string
|
||||
name?: string
|
||||
type?: string
|
||||
export type SnippetTagResponse = {
|
||||
id: string
|
||||
name: string
|
||||
type: string
|
||||
}
|
||||
|
||||
export type SnippetType = 'group' | 'node'
|
||||
|
||||
export type ImportStatus = 'completed' | 'completed-with-warnings' | 'failed' | 'pending'
|
||||
|
||||
export type PluginDependency = {
|
||||
current_identifier?: string | null
|
||||
type: Type
|
||||
value: Github | Marketplace | Package
|
||||
}
|
||||
|
||||
export type AccountWithRole = {
|
||||
@ -1391,6 +1406,25 @@ export type TriggerProviderSubscriptionApiEntity = {
|
||||
workflows_in_use: number
|
||||
}
|
||||
|
||||
export type Type = 'github' | 'marketplace' | 'package'
|
||||
|
||||
export type Github = {
|
||||
github_plugin_unique_identifier: string
|
||||
package: string
|
||||
repo: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export type Marketplace = {
|
||||
marketplace_plugin_unique_identifier: string
|
||||
version?: string | null
|
||||
}
|
||||
|
||||
export type Package = {
|
||||
plugin_unique_identifier: string
|
||||
version?: string | null
|
||||
}
|
||||
|
||||
export type SimpleProviderEntityResponse = {
|
||||
icon_small?: I18nObject | null
|
||||
icon_small_dark?: I18nObject | null
|
||||
@ -1879,7 +1913,7 @@ export type GetWorkspacesCurrentCustomizedSnippetsData = {
|
||||
}
|
||||
|
||||
export type GetWorkspacesCurrentCustomizedSnippetsResponses = {
|
||||
200: SnippetPagination
|
||||
200: SnippetPaginationResponse
|
||||
}
|
||||
|
||||
export type GetWorkspacesCurrentCustomizedSnippetsResponse
|
||||
@ -1897,7 +1931,7 @@ export type PostWorkspacesCurrentCustomizedSnippetsErrors = {
|
||||
}
|
||||
|
||||
export type PostWorkspacesCurrentCustomizedSnippetsResponses = {
|
||||
201: Snippet
|
||||
201: SnippetResponse
|
||||
}
|
||||
|
||||
export type PostWorkspacesCurrentCustomizedSnippetsResponse
|
||||
@ -1976,7 +2010,7 @@ export type GetWorkspacesCurrentCustomizedSnippetsBySnippetIdErrors = {
|
||||
}
|
||||
|
||||
export type GetWorkspacesCurrentCustomizedSnippetsBySnippetIdResponses = {
|
||||
200: Snippet
|
||||
200: SnippetResponse
|
||||
}
|
||||
|
||||
export type GetWorkspacesCurrentCustomizedSnippetsBySnippetIdResponse
|
||||
@ -1997,7 +2031,7 @@ export type PatchWorkspacesCurrentCustomizedSnippetsBySnippetIdErrors = {
|
||||
}
|
||||
|
||||
export type PatchWorkspacesCurrentCustomizedSnippetsBySnippetIdResponses = {
|
||||
200: Snippet
|
||||
200: SnippetResponse
|
||||
}
|
||||
|
||||
export type PatchWorkspacesCurrentCustomizedSnippetsBySnippetIdResponse
|
||||
|
||||
@ -26,16 +26,6 @@ export const zSnippetImportPayload = z.object({
|
||||
yaml_url: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* SnippetImportResponse
|
||||
*/
|
||||
export const zSnippetImportResponse = z.record(z.string(), z.unknown())
|
||||
|
||||
/**
|
||||
* SnippetDependencyCheckResponse
|
||||
*/
|
||||
export const zSnippetDependencyCheckResponse = z.record(z.string(), z.unknown())
|
||||
|
||||
/**
|
||||
* TextFileResponse
|
||||
*/
|
||||
@ -801,91 +791,98 @@ export const zCreateSnippetPayload = z.object({
|
||||
type: z.enum(['group', 'node']).optional().default('node'),
|
||||
})
|
||||
|
||||
export const zAnonymousInlineModelB0Fd3F86D9D5 = z.object({
|
||||
email: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
/**
|
||||
* SnippetAccountResponse
|
||||
*/
|
||||
export const zSnippetAccountResponse = z.object({
|
||||
email: z.string(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
})
|
||||
|
||||
export const zAnonymousInlineModel7B8B49Ca164e = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
type: z.string().optional(),
|
||||
/**
|
||||
* SnippetTagResponse
|
||||
*/
|
||||
export const zSnippetTagResponse = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
})
|
||||
|
||||
export const zSnippet = z.object({
|
||||
created_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
created_by: zAnonymousInlineModelB0Fd3F86D9D5.optional(),
|
||||
description: z.string().optional(),
|
||||
graph: z.record(z.string(), z.unknown()).optional(),
|
||||
icon_info: z.record(z.string(), z.unknown()).optional(),
|
||||
id: z.string().optional(),
|
||||
input_fields: z.record(z.string(), z.unknown()).optional(),
|
||||
is_published: z.boolean().optional(),
|
||||
name: z.string().optional(),
|
||||
tags: z.array(zAnonymousInlineModel7B8B49Ca164e).optional(),
|
||||
type: z.string().optional(),
|
||||
updated_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
updated_by: zAnonymousInlineModelB0Fd3F86D9D5.optional(),
|
||||
use_count: z.int().optional(),
|
||||
version: z.int().optional(),
|
||||
/**
|
||||
* SnippetType
|
||||
*
|
||||
* Snippet Type Enum
|
||||
*/
|
||||
export const zSnippetType = z.enum(['group', 'node'])
|
||||
|
||||
/**
|
||||
* SnippetResponse
|
||||
*/
|
||||
export const zSnippetResponse = z.object({
|
||||
created_at: z.int(),
|
||||
created_by: zSnippetAccountResponse.nullable(),
|
||||
description: z.string().nullable(),
|
||||
graph: z.record(z.string(), z.unknown()),
|
||||
icon_info: z.record(z.string(), z.unknown()).nullable(),
|
||||
id: z.string(),
|
||||
input_fields: z.array(z.record(z.string(), z.unknown())),
|
||||
is_published: z.boolean(),
|
||||
name: z.string(),
|
||||
tags: z.array(zSnippetTagResponse),
|
||||
type: zSnippetType,
|
||||
updated_at: z.int(),
|
||||
updated_by: zSnippetAccountResponse.nullable(),
|
||||
use_count: z.int(),
|
||||
version: z.int(),
|
||||
})
|
||||
|
||||
export const zAnonymousInlineModel744Ff9Cc03E6 = z.object({
|
||||
author_name: z.string().optional(),
|
||||
created_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
created_by: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
icon_info: z.record(z.string(), z.unknown()).optional(),
|
||||
id: z.string().optional(),
|
||||
is_published: z.boolean().optional(),
|
||||
name: z.string().optional(),
|
||||
tags: z.array(zAnonymousInlineModel7B8B49Ca164e).optional(),
|
||||
type: z.string().optional(),
|
||||
updated_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
updated_by: z.string().optional(),
|
||||
use_count: z.int().optional(),
|
||||
version: z.int().optional(),
|
||||
/**
|
||||
* SnippetListItemResponse
|
||||
*/
|
||||
export const zSnippetListItemResponse = z.object({
|
||||
author_name: z.string().nullable(),
|
||||
created_at: z.int(),
|
||||
created_by: z.string().nullable(),
|
||||
description: z.string().nullable(),
|
||||
icon_info: z.record(z.string(), z.unknown()).nullable(),
|
||||
id: z.string(),
|
||||
is_published: z.boolean(),
|
||||
name: z.string(),
|
||||
tags: z.array(zSnippetTagResponse),
|
||||
type: zSnippetType,
|
||||
updated_at: z.int(),
|
||||
updated_by: z.string().nullable(),
|
||||
use_count: z.int(),
|
||||
version: z.int(),
|
||||
})
|
||||
|
||||
export const zSnippetPagination = z.object({
|
||||
data: z.array(zAnonymousInlineModel744Ff9Cc03E6).optional(),
|
||||
has_more: z.boolean().optional(),
|
||||
limit: z.int().optional(),
|
||||
page: z.int().optional(),
|
||||
total: z.int().optional(),
|
||||
/**
|
||||
* SnippetPaginationResponse
|
||||
*/
|
||||
export const zSnippetPaginationResponse = z.object({
|
||||
data: z.array(zSnippetListItemResponse),
|
||||
has_more: z.boolean(),
|
||||
limit: z.int(),
|
||||
page: z.int(),
|
||||
total: z.int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ImportStatus
|
||||
*/
|
||||
export const zImportStatus = z.enum(['completed', 'completed-with-warnings', 'failed', 'pending'])
|
||||
|
||||
/**
|
||||
* SnippetImportResponse
|
||||
*/
|
||||
export const zSnippetImportResponse = z.object({
|
||||
current_dsl_version: z.string(),
|
||||
error: z.string(),
|
||||
id: z.string(),
|
||||
imported_dsl_version: z.string(),
|
||||
snippet_id: z.string().nullable(),
|
||||
status: zImportStatus,
|
||||
})
|
||||
|
||||
/**
|
||||
@ -1493,6 +1490,53 @@ export const zTriggerProviderSubscriptionApiEntity = z.object({
|
||||
*/
|
||||
export const zTriggerSubscriptionListResponse = z.array(zTriggerProviderSubscriptionApiEntity)
|
||||
|
||||
/**
|
||||
* Type
|
||||
*/
|
||||
export const zType = z.enum(['github', 'marketplace', 'package'])
|
||||
|
||||
/**
|
||||
* Github
|
||||
*/
|
||||
export const zGithub = z.object({
|
||||
github_plugin_unique_identifier: z.string(),
|
||||
package: z.string(),
|
||||
repo: z.string(),
|
||||
version: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Marketplace
|
||||
*/
|
||||
export const zMarketplace = z.object({
|
||||
marketplace_plugin_unique_identifier: z.string(),
|
||||
version: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Package
|
||||
*/
|
||||
export const zPackage = z.object({
|
||||
plugin_unique_identifier: z.string(),
|
||||
version: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* PluginDependency
|
||||
*/
|
||||
export const zPluginDependency = z.object({
|
||||
current_identifier: z.string().nullish(),
|
||||
type: zType,
|
||||
value: z.union([zGithub, zMarketplace, zPackage]),
|
||||
})
|
||||
|
||||
/**
|
||||
* SnippetDependencyCheckResponse
|
||||
*/
|
||||
export const zSnippetDependencyCheckResponse = z.object({
|
||||
leaked_dependencies: z.array(zPluginDependency),
|
||||
})
|
||||
|
||||
/**
|
||||
* ConfigurateMethod
|
||||
*
|
||||
@ -2589,14 +2633,14 @@ export const zGetWorkspacesCurrentCustomizedSnippetsQuery = z.object({
|
||||
/**
|
||||
* Snippets retrieved successfully
|
||||
*/
|
||||
export const zGetWorkspacesCurrentCustomizedSnippetsResponse = zSnippetPagination
|
||||
export const zGetWorkspacesCurrentCustomizedSnippetsResponse = zSnippetPaginationResponse
|
||||
|
||||
export const zPostWorkspacesCurrentCustomizedSnippetsBody = zCreateSnippetPayload
|
||||
|
||||
/**
|
||||
* Snippet created successfully
|
||||
*/
|
||||
export const zPostWorkspacesCurrentCustomizedSnippetsResponse = zSnippet
|
||||
export const zPostWorkspacesCurrentCustomizedSnippetsResponse = zSnippetResponse
|
||||
|
||||
export const zPostWorkspacesCurrentCustomizedSnippetsImportsBody = zSnippetImportPayload
|
||||
|
||||
@ -2631,7 +2675,7 @@ export const zGetWorkspacesCurrentCustomizedSnippetsBySnippetIdPath = z.object({
|
||||
/**
|
||||
* Snippet retrieved successfully
|
||||
*/
|
||||
export const zGetWorkspacesCurrentCustomizedSnippetsBySnippetIdResponse = zSnippet
|
||||
export const zGetWorkspacesCurrentCustomizedSnippetsBySnippetIdResponse = zSnippetResponse
|
||||
|
||||
export const zPatchWorkspacesCurrentCustomizedSnippetsBySnippetIdBody = zUpdateSnippetPayload
|
||||
|
||||
@ -2642,7 +2686,7 @@ export const zPatchWorkspacesCurrentCustomizedSnippetsBySnippetIdPath = z.object
|
||||
/**
|
||||
* Snippet updated successfully
|
||||
*/
|
||||
export const zPatchWorkspacesCurrentCustomizedSnippetsBySnippetIdResponse = zSnippet
|
||||
export const zPatchWorkspacesCurrentCustomizedSnippetsBySnippetIdResponse = zSnippetResponse
|
||||
|
||||
export const zGetWorkspacesCurrentCustomizedSnippetsBySnippetIdCheckDependenciesPath = z.object({
|
||||
snippet_id: z.uuid(),
|
||||
|
||||
@ -222,6 +222,8 @@ describe('SnippetInfoDropdown', () => {
|
||||
expect(screen.getByText('snippet.editDialogTitle')).toBeInTheDocument()
|
||||
expect(screen.getByText('common.operation.save')).toBeInTheDocument()
|
||||
expect(screen.getByText(mockSnippet.name)).toBeInTheDocument()
|
||||
if (!mockSnippet.description)
|
||||
throw new Error('mockSnippet.description is required for this test')
|
||||
expect(screen.getByText(mockSnippet.description)).toBeInTheDocument()
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'submit-edit' }))
|
||||
|
||||
@ -49,7 +49,7 @@ const SnippetInfoDropdown = ({ snippet }: SnippetInfoDropdownProps) => {
|
||||
|
||||
const initialValue = React.useMemo(() => ({
|
||||
name: snippet.name,
|
||||
description: snippet.description,
|
||||
description: snippet.description ?? undefined,
|
||||
}), [snippet.description, snippet.name])
|
||||
|
||||
const handleOpenEditDialog = React.useCallback(() => {
|
||||
@ -80,7 +80,7 @@ const SnippetInfoDropdown = ({ snippet }: SnippetInfoDropdownProps) => {
|
||||
params: { snippetId: snippet.id },
|
||||
body: {
|
||||
name,
|
||||
description: description || undefined,
|
||||
description,
|
||||
},
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
|
||||
@ -113,6 +113,7 @@ const createSnippet = (overrides: Partial<SnippetListItem> = {}): SnippetListIte
|
||||
updated_at: 1_704_153_600,
|
||||
updated_by: 'updater-id',
|
||||
...overrides,
|
||||
version: overrides.version ?? 1,
|
||||
})
|
||||
|
||||
describe('SnippetCard', () => {
|
||||
@ -321,7 +322,7 @@ describe('SnippetCard', () => {
|
||||
expect(mockUpdateMutate).toHaveBeenCalledWith(expect.objectContaining({
|
||||
body: {
|
||||
name: 'Updated Snippet',
|
||||
description: undefined,
|
||||
description: '',
|
||||
},
|
||||
}), expect.any(Object))
|
||||
expect(mockToastError).toHaveBeenCalledWith('Update failed')
|
||||
|
||||
@ -52,7 +52,13 @@ vi.mock('@/service/use-snippets', () => ({
|
||||
vi.mock('@/service/client', () => ({
|
||||
consoleClient: {
|
||||
snippets: {
|
||||
syncDraftWorkflow: mockSyncDraftWorkflow,
|
||||
bySnippetId: {
|
||||
workflows: {
|
||||
draft: {
|
||||
post: mockSyncDraftWorkflow,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
@ -104,7 +110,7 @@ describe('SnippetCreateButton', () => {
|
||||
})
|
||||
})
|
||||
expect(mockSyncDraftWorkflow).toHaveBeenCalledWith({
|
||||
params: { snippetId: 'snippet-123' },
|
||||
params: { snippet_id: 'snippet-123' },
|
||||
body: {
|
||||
graph: {
|
||||
nodes: [],
|
||||
|
||||
@ -62,8 +62,8 @@ const SnippetCard = ({
|
||||
return new Map((membersData?.accounts ?? []).map(member => [member.id, member.name]))
|
||||
}, [membersData?.accounts])
|
||||
|
||||
const updatedByName = memberNameById.get(snippet.updated_by)
|
||||
|| memberNameById.get(snippet.created_by)
|
||||
const updatedByName = (snippet.updated_by ? memberNameById.get(snippet.updated_by) : undefined)
|
||||
|| (snippet.created_by ? memberNameById.get(snippet.created_by) : undefined)
|
||||
|| t('unknownUser')
|
||||
|
||||
const updatedAt = snippet.updated_at || snippet.created_at
|
||||
@ -73,7 +73,7 @@ const SnippetCard = ({
|
||||
})
|
||||
const initialValue = useMemo(() => ({
|
||||
name: snippet.name,
|
||||
description: snippet.description,
|
||||
description: snippet.description ?? undefined,
|
||||
}), [snippet.description, snippet.name])
|
||||
|
||||
const handleOpenEditDialog = () => {
|
||||
@ -119,7 +119,7 @@ const SnippetCard = ({
|
||||
params: { snippetId: snippet.id },
|
||||
body: {
|
||||
name,
|
||||
description: description || undefined,
|
||||
description,
|
||||
},
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
@ -148,7 +148,7 @@ const SnippetCard = ({
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-22.5 px-3.5 text-xs leading-normal text-text-tertiary">
|
||||
<div className="line-clamp-2" title={snippet.description}>
|
||||
<div className="line-clamp-2" title={snippet.description ?? undefined}>
|
||||
{snippet.description}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -144,6 +144,8 @@ describe('SnippetSidebarContent', () => {
|
||||
expect(screen.queryByRole('link', { name: /snippet\.management/i })).not.toBeInTheDocument()
|
||||
expect(screen.getByText(snippet.name)).toHaveAttribute('title', snippet.name)
|
||||
expect(screen.getByText(snippet.name)).toHaveClass('truncate')
|
||||
if (!snippet.description)
|
||||
throw new Error('snippet.description is required for this test')
|
||||
expect(screen.getByText(snippet.description)).toHaveAttribute('title', snippet.description)
|
||||
expect(screen.getByText(snippet.description)).toHaveClass('truncate')
|
||||
expect(screen.queryByRole('button', { name: /common\.operation\.add/i })).not.toBeInTheDocument()
|
||||
|
||||
@ -33,9 +33,10 @@ export const useSnippetPublish = ({
|
||||
params: { snippetId },
|
||||
})
|
||||
queryClient.setQueryData<SnippetContract | undefined>(
|
||||
consoleQuery.snippets.detail.queryKey({
|
||||
consoleQuery.workspaces.current.customizedSnippets.bySnippetId.get.key({
|
||||
type: 'query',
|
||||
input: {
|
||||
params: { snippetId },
|
||||
params: { snippet_id: snippetId },
|
||||
},
|
||||
}),
|
||||
old => old ? { ...old, is_published: true } : old,
|
||||
|
||||
@ -32,7 +32,13 @@ vi.mock('@/service/use-snippets', () => ({
|
||||
vi.mock('@/service/client', () => ({
|
||||
consoleClient: {
|
||||
snippets: {
|
||||
syncDraftWorkflow: mockSyncDraftWorkflow,
|
||||
bySnippetId: {
|
||||
workflows: {
|
||||
draft: {
|
||||
post: mockSyncDraftWorkflow,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
@ -123,7 +129,7 @@ describe('useCreateSnippet', () => {
|
||||
},
|
||||
})
|
||||
expect(mockSyncDraftWorkflow).toHaveBeenCalledWith({
|
||||
params: { snippetId: 'snippet-123' },
|
||||
params: { snippet_id: 'snippet-123' },
|
||||
body: {
|
||||
graph,
|
||||
input_fields: [
|
||||
|
||||
@ -61,7 +61,13 @@ vi.mock('@/app/components/workflow/store', () => ({
|
||||
vi.mock('@/service/client', () => ({
|
||||
consoleClient: {
|
||||
snippets: {
|
||||
syncDraftWorkflow: (...args: unknown[]) => mockSyncDraftWorkflow(...args),
|
||||
bySnippetId: {
|
||||
workflows: {
|
||||
draft: {
|
||||
post: (...args: unknown[]) => mockSyncDraftWorkflow(...args),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
@ -123,7 +129,7 @@ describe('snippet/use-nodes-sync-draft', () => {
|
||||
})
|
||||
|
||||
expect(mockSyncDraftWorkflow).toHaveBeenCalledWith({
|
||||
params: { snippetId: 'snippet-1' },
|
||||
params: { snippet_id: 'snippet-1' },
|
||||
body: {
|
||||
graph: {
|
||||
nodes: [{ id: 'node-1', position: { x: 0, y: 0 }, data: { title: 'Start' } }],
|
||||
@ -168,7 +174,7 @@ describe('snippet/use-nodes-sync-draft', () => {
|
||||
})
|
||||
|
||||
expect(mockSyncDraftWorkflow).toHaveBeenCalledWith({
|
||||
params: { snippetId: 'snippet-1' },
|
||||
params: { snippet_id: 'snippet-1' },
|
||||
body: {
|
||||
graph: {
|
||||
nodes: [{ id: 'node-1', position: { x: 0, y: 0 }, data: { title: 'Start' } }],
|
||||
@ -190,7 +196,7 @@ describe('snippet/use-nodes-sync-draft', () => {
|
||||
})
|
||||
|
||||
expect(mockSyncDraftWorkflow).toHaveBeenCalledWith({
|
||||
params: { snippetId: 'snippet-1' },
|
||||
params: { snippet_id: 'snippet-1' },
|
||||
body: {
|
||||
graph: {
|
||||
nodes: [{ id: 'node-1', position: { x: 0, y: 0 }, data: { title: 'Start' } }],
|
||||
@ -225,13 +231,13 @@ describe('snippet/use-nodes-sync-draft', () => {
|
||||
})
|
||||
|
||||
expect(mockSyncDraftWorkflow).toHaveBeenNthCalledWith(1, {
|
||||
params: { snippetId: 'snippet-1' },
|
||||
params: { snippet_id: 'snippet-1' },
|
||||
body: expect.objectContaining({
|
||||
hash: 'draft-hash',
|
||||
}),
|
||||
})
|
||||
expect(mockSyncDraftWorkflow).toHaveBeenNthCalledWith(2, {
|
||||
params: { snippetId: 'snippet-1' },
|
||||
params: { snippet_id: 'snippet-1' },
|
||||
body: expect.objectContaining({
|
||||
hash: 'hash-after-first-sync',
|
||||
}),
|
||||
|
||||
@ -42,15 +42,15 @@ export const useCreateSnippet = () => {
|
||||
try {
|
||||
const createPayload = {
|
||||
name,
|
||||
description: description || undefined,
|
||||
description,
|
||||
graph,
|
||||
input_fields,
|
||||
}
|
||||
const snippet = await createSnippetMutation.mutateAsync({
|
||||
body: createPayload,
|
||||
})
|
||||
await consoleClient.snippets.syncDraftWorkflow({
|
||||
params: { snippetId: snippet.id },
|
||||
await consoleClient.snippets.bySnippetId.workflows.draft.post({
|
||||
params: { snippet_id: snippet.id },
|
||||
body: {
|
||||
graph: createPayload.graph,
|
||||
input_fields: createPayload.input_fields,
|
||||
|
||||
@ -113,8 +113,8 @@ export const useNodesSyncDraft = (snippetId: string) => {
|
||||
} = workflowStore.getState()
|
||||
|
||||
try {
|
||||
const response = await consoleClient.snippets.syncDraftWorkflow({
|
||||
params: { snippetId },
|
||||
const response = await consoleClient.snippets.bySnippetId.workflows.draft.post({
|
||||
params: { snippet_id: snippetId },
|
||||
body: {
|
||||
...payload,
|
||||
hash: syncWorkflowDraftHash || undefined,
|
||||
|
||||
@ -31,6 +31,7 @@ const createSnippet = (overrides: Partial<PublishedSnippetListItem> = {}): Publi
|
||||
updated_at: 2,
|
||||
updated_by: 'user-1',
|
||||
...overrides,
|
||||
version: overrides.version ?? 1,
|
||||
})
|
||||
|
||||
describe('SnippetDetailCard', () => {
|
||||
|
||||
@ -15,6 +15,7 @@ const createSnippet = (overrides: Partial<PublishedSnippetListItem> = {}): Publi
|
||||
updated_at: 2,
|
||||
updated_by: 'user-1',
|
||||
...overrides,
|
||||
version: overrides.version ?? 1,
|
||||
})
|
||||
|
||||
describe('SnippetListItem', () => {
|
||||
|
||||
@ -283,9 +283,9 @@ export const useInsertSnippet = () => {
|
||||
|
||||
const handleInsertSnippet = useCallback(async (snippetId: string, insertPayload?: SnippetInsertPayload) => {
|
||||
try {
|
||||
const workflow = await queryClient.fetchQuery(consoleQuery.snippets.publishedWorkflow.queryOptions({
|
||||
const workflow = await queryClient.fetchQuery(consoleQuery.snippets.bySnippetId.workflows.publish.get.queryOptions({
|
||||
input: {
|
||||
params: { snippetId },
|
||||
params: { snippet_id: snippetId },
|
||||
},
|
||||
}))
|
||||
const { nodes: snippetNodes, edges: snippetEdges } = getSnippetGraph(workflow.graph)
|
||||
|
||||
@ -1,376 +1 @@
|
||||
import type {
|
||||
CreateSnippetPayload,
|
||||
IncrementSnippetUseCountResponse,
|
||||
PublishSnippetWorkflowResponse,
|
||||
Snippet,
|
||||
SnippetDraftConfig,
|
||||
SnippetDraftNodeRunPayload,
|
||||
SnippetDraftRunPayload,
|
||||
SnippetDraftSyncPayload,
|
||||
SnippetDraftSyncResponse,
|
||||
SnippetImportPayload,
|
||||
SnippetIterationNodeRunPayload,
|
||||
SnippetListResponse,
|
||||
SnippetLoopNodeRunPayload,
|
||||
SnippetWorkflow,
|
||||
UpdateSnippetPayload,
|
||||
WorkflowNodeExecution,
|
||||
WorkflowNodeExecutionListResponse,
|
||||
WorkflowRunDetail,
|
||||
WorkflowRunPagination,
|
||||
} from '@/types/snippet'
|
||||
import { type } from '@orpc/contract'
|
||||
import { base } from '../base'
|
||||
|
||||
export const listCustomizedSnippetsContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
query: {
|
||||
page: number
|
||||
limit: number
|
||||
keyword?: string
|
||||
tag_ids?: string[]
|
||||
creator_ids?: string[]
|
||||
is_published?: boolean
|
||||
}
|
||||
}>())
|
||||
.output(type<SnippetListResponse>())
|
||||
|
||||
export const createCustomizedSnippetContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
body: CreateSnippetPayload
|
||||
}>())
|
||||
.output(type<Snippet>())
|
||||
|
||||
export const getCustomizedSnippetContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets/{snippetId}',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<Snippet>())
|
||||
|
||||
export const updateCustomizedSnippetContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets/{snippetId}',
|
||||
method: 'PATCH',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
body: UpdateSnippetPayload
|
||||
}>())
|
||||
.output(type<Snippet>())
|
||||
|
||||
export const deleteCustomizedSnippetContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets/{snippetId}',
|
||||
method: 'DELETE',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const exportCustomizedSnippetContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets/{snippetId}/export',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
query: {
|
||||
include_secret?: 'true' | 'false'
|
||||
}
|
||||
}>())
|
||||
.output(type<string>())
|
||||
|
||||
export const importCustomizedSnippetContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets/imports',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
body: SnippetImportPayload
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const confirmSnippetImportContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets/imports/{importId}/confirm',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
importId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const checkSnippetDependenciesContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets/{snippetId}/check-dependencies',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const incrementSnippetUseCountContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/customized-snippets/{snippetId}/use-count/increment',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<IncrementSnippetUseCountResponse>())
|
||||
|
||||
export const getSnippetDraftWorkflowContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/draft',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<SnippetWorkflow>())
|
||||
|
||||
export const syncSnippetDraftWorkflowContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/draft',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
body: SnippetDraftSyncPayload
|
||||
}>())
|
||||
.output(type<SnippetDraftSyncResponse>())
|
||||
|
||||
export const getSnippetDraftConfigContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/draft/config',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<SnippetDraftConfig>())
|
||||
|
||||
export const getSnippetPublishedWorkflowContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/publish',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<SnippetWorkflow>())
|
||||
|
||||
export const publishSnippetWorkflowContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/publish',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<PublishSnippetWorkflowResponse>())
|
||||
|
||||
export const getSnippetDefaultBlockConfigsContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/default-workflow-block-configs',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const listSnippetWorkflowRunsContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflow-runs',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
query: {
|
||||
last_id?: string
|
||||
limit?: number
|
||||
}
|
||||
}>())
|
||||
.output(type<WorkflowRunPagination>())
|
||||
|
||||
export const getSnippetWorkflowRunDetailContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflow-runs/{runId}',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
runId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<WorkflowRunDetail>())
|
||||
|
||||
export const listSnippetWorkflowRunNodeExecutionsContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflow-runs/{runId}/node-executions',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
runId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<WorkflowNodeExecutionListResponse>())
|
||||
|
||||
export const runSnippetDraftNodeContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/draft/nodes/{nodeId}/run',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
nodeId: string
|
||||
}
|
||||
body: SnippetDraftNodeRunPayload
|
||||
}>())
|
||||
.output(type<WorkflowNodeExecution>())
|
||||
|
||||
export const getSnippetDraftNodeLastRunContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/draft/nodes/{nodeId}/last-run',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
nodeId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<WorkflowNodeExecution>())
|
||||
|
||||
export const runSnippetDraftIterationNodeContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/draft/iteration/nodes/{nodeId}/run',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
nodeId: string
|
||||
}
|
||||
body: SnippetIterationNodeRunPayload
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const runSnippetDraftLoopNodeContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/draft/loop/nodes/{nodeId}/run',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
nodeId: string
|
||||
}
|
||||
body: SnippetLoopNodeRunPayload
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const runSnippetDraftWorkflowContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflows/draft/run',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
body: SnippetDraftRunPayload
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const stopSnippetWorkflowTaskContract = base
|
||||
.route({
|
||||
path: '/snippets/{snippetId}/workflow-runs/tasks/{taskId}/stop',
|
||||
method: 'POST',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
snippetId: string
|
||||
taskId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const snippetsRouterContract = {
|
||||
list: listCustomizedSnippetsContract,
|
||||
create: createCustomizedSnippetContract,
|
||||
detail: getCustomizedSnippetContract,
|
||||
update: updateCustomizedSnippetContract,
|
||||
delete: deleteCustomizedSnippetContract,
|
||||
export: exportCustomizedSnippetContract,
|
||||
import: importCustomizedSnippetContract,
|
||||
confirmImport: confirmSnippetImportContract,
|
||||
checkDependencies: checkSnippetDependenciesContract,
|
||||
incrementUseCount: incrementSnippetUseCountContract,
|
||||
draftWorkflow: getSnippetDraftWorkflowContract,
|
||||
syncDraftWorkflow: syncSnippetDraftWorkflowContract,
|
||||
draftConfig: getSnippetDraftConfigContract,
|
||||
publishedWorkflow: getSnippetPublishedWorkflowContract,
|
||||
publishWorkflow: publishSnippetWorkflowContract,
|
||||
defaultBlockConfigs: getSnippetDefaultBlockConfigsContract,
|
||||
workflowRuns: listSnippetWorkflowRunsContract,
|
||||
workflowRunDetail: getSnippetWorkflowRunDetailContract,
|
||||
workflowRunNodeExecutions: listSnippetWorkflowRunNodeExecutionsContract,
|
||||
runDraftNode: runSnippetDraftNodeContract,
|
||||
lastDraftNodeRun: getSnippetDraftNodeLastRunContract,
|
||||
runDraftIterationNode: runSnippetDraftIterationNodeContract,
|
||||
runDraftLoopNode: runSnippetDraftLoopNodeContract,
|
||||
runDraftWorkflow: runSnippetDraftWorkflowContract,
|
||||
stopWorkflowTask: stopSnippetWorkflowTaskContract,
|
||||
}
|
||||
|
||||
export const snippetsConsoleRouterContract = {
|
||||
snippets: snippetsRouterContract,
|
||||
}
|
||||
export const snippetsConsoleRouterContract = {}
|
||||
|
||||
@ -34,6 +34,7 @@ import { resetPassword } from '@dify/contracts/api/console/reset-password/orpc.g
|
||||
import { ruleCodeGenerate } from '@dify/contracts/api/console/rule-code-generate/orpc.gen'
|
||||
import { ruleGenerate } from '@dify/contracts/api/console/rule-generate/orpc.gen'
|
||||
import { ruleStructuredOutputGenerate } from '@dify/contracts/api/console/rule-structured-output-generate/orpc.gen'
|
||||
import { snippets } from '@dify/contracts/api/console/snippets/orpc.gen'
|
||||
import { spec } from '@dify/contracts/api/console/spec/orpc.gen'
|
||||
import { systemFeatures } from '@dify/contracts/api/console/system-features/orpc.gen'
|
||||
import { tagBindings } from '@dify/contracts/api/console/tag-bindings/orpc.gen'
|
||||
@ -87,6 +88,7 @@ const communityContract = {
|
||||
ruleCodeGenerate,
|
||||
ruleGenerate,
|
||||
ruleStructuredOutputGenerate,
|
||||
snippets,
|
||||
spec,
|
||||
systemFeatures,
|
||||
tagBindings,
|
||||
|
||||
@ -8,7 +8,7 @@ export type SnippetSection = 'orchestrate'
|
||||
export type SnippetListItem = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
description: string | null
|
||||
updatedAt: string
|
||||
usage: string
|
||||
tags: Tag[]
|
||||
@ -19,7 +19,7 @@ export type SnippetListItem = {
|
||||
export type SnippetDetail = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
description: string | null
|
||||
updatedAt: string
|
||||
usage: string
|
||||
tags: Tag[]
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import type { SnippetWorkflow } from '@/types/snippet'
|
||||
import type { PublishSnippetWorkflowResponse, SnippetWorkflow } from '@/types/snippet'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { consoleQuery } from '@/service/client'
|
||||
import { get } from './base'
|
||||
import { consoleClient, consoleQuery } from '@/service/client'
|
||||
|
||||
const isNotFoundError = (error: unknown) => {
|
||||
return !!error && typeof error === 'object' && 'status' in error && error.status === 404
|
||||
@ -9,7 +8,11 @@ const isNotFoundError = (error: unknown) => {
|
||||
|
||||
export const fetchSnippetDraftWorkflow = async (snippetId: string) => {
|
||||
try {
|
||||
return await get<SnippetWorkflow>(`/snippets/${snippetId}/workflows/draft`, {}, { silent: true })
|
||||
return await consoleClient.snippets.bySnippetId.workflows.draft.get({
|
||||
params: { snippet_id: snippetId },
|
||||
}, {
|
||||
context: { silent: true },
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
if (isNotFoundError(error))
|
||||
@ -19,30 +22,35 @@ export const fetchSnippetDraftWorkflow = async (snippetId: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
const snippetWorkflowContract = consoleQuery.snippets.bySnippetId
|
||||
const snippetWorkflowClient = consoleClient.snippets.bySnippetId
|
||||
|
||||
const invalidateSnippetWorkflowQueries = async (
|
||||
queryClient: ReturnType<typeof useQueryClient>,
|
||||
snippetId: string,
|
||||
) => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.snippets.draftWorkflow.queryKey({
|
||||
queryKey: snippetWorkflowContract.workflows.draft.get.key({
|
||||
type: 'query',
|
||||
input: {
|
||||
params: { snippetId },
|
||||
params: { snippet_id: snippetId },
|
||||
},
|
||||
}),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.snippets.publishedWorkflow.queryKey({
|
||||
queryKey: snippetWorkflowContract.workflows.publish.get.key({
|
||||
type: 'query',
|
||||
input: {
|
||||
params: { snippetId },
|
||||
params: { snippet_id: snippetId },
|
||||
},
|
||||
}),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.snippets.workflowRuns.key(),
|
||||
queryKey: snippetWorkflowContract.workflowRuns.get.key({ type: 'query' }),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.snippets.lastDraftNodeRun.key(),
|
||||
queryKey: snippetWorkflowContract.workflows.draft.nodes.byNodeId.lastRun.get.key({ type: 'query' }),
|
||||
}),
|
||||
])
|
||||
}
|
||||
@ -50,9 +58,9 @@ export const useSnippetPublishedWorkflow = (
|
||||
snippetId: string,
|
||||
onSuccess?: (publishedWorkflow: SnippetWorkflow) => void,
|
||||
) => {
|
||||
const queryOptions = consoleQuery.snippets.publishedWorkflow.queryOptions({
|
||||
const queryOptions = snippetWorkflowContract.workflows.publish.get.queryOptions({
|
||||
input: {
|
||||
params: { snippetId },
|
||||
params: { snippet_id: snippetId },
|
||||
},
|
||||
enabled: !!snippetId,
|
||||
})
|
||||
@ -80,9 +88,9 @@ export const useSnippetDefaultBlockConfigs = (
|
||||
snippetId: string,
|
||||
onSuccess?: (nodesDefaultConfigs: unknown) => void,
|
||||
) => {
|
||||
const queryOptions = consoleQuery.snippets.defaultBlockConfigs.queryOptions({
|
||||
const queryOptions = snippetWorkflowContract.workflows.defaultWorkflowBlockConfigs.get.queryOptions({
|
||||
input: {
|
||||
params: { snippetId },
|
||||
params: { snippet_id: snippetId },
|
||||
},
|
||||
enabled: !!snippetId,
|
||||
})
|
||||
@ -100,11 +108,16 @@ export const useSnippetDefaultBlockConfigs = (
|
||||
export const usePublishSnippetWorkflowMutation = (snippetId: string) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
...consoleQuery.snippets.publishWorkflow.mutationOptions({
|
||||
onSuccess: async () => {
|
||||
await invalidateSnippetWorkflowQueries(queryClient, snippetId)
|
||||
return useMutation<PublishSnippetWorkflowResponse, Error, { params: { snippetId: string } }>({
|
||||
mutationKey: snippetWorkflowContract.workflows.publish.post.mutationKey(),
|
||||
mutationFn: ({ params }) => snippetWorkflowClient.workflows.publish.post({
|
||||
params: {
|
||||
snippet_id: params.snippetId,
|
||||
},
|
||||
body: {},
|
||||
}),
|
||||
onSuccess: async () => {
|
||||
await invalidateSnippetWorkflowQueries(queryClient, snippetId)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -6,10 +6,14 @@ import type {
|
||||
SnippetListItem as SnippetListItemUIModel,
|
||||
} from '@/models/snippet'
|
||||
import type {
|
||||
CreateSnippetPayload,
|
||||
IncrementSnippetUseCountResponse,
|
||||
Snippet as SnippetContract,
|
||||
SnippetDSLImportResponse,
|
||||
SnippetImportPayload,
|
||||
SnippetListResponse,
|
||||
SnippetWorkflow,
|
||||
UpdateSnippetPayload,
|
||||
} from '@/types/snippet'
|
||||
import {
|
||||
keepPreviousData,
|
||||
@ -31,6 +35,17 @@ type SnippetListParams = {
|
||||
}
|
||||
|
||||
type SnippetSummary = Pick<SnippetContract, 'id' | 'name' | 'description' | 'use_count' | 'tags' | 'updated_at' | 'is_published'>
|
||||
type SnippetIdInput = {
|
||||
params: {
|
||||
snippetId: string
|
||||
}
|
||||
}
|
||||
type CreateSnippetInput = {
|
||||
body: CreateSnippetPayload
|
||||
}
|
||||
type UpdateSnippetInput = SnippetIdInput & {
|
||||
body: UpdateSnippetPayload
|
||||
}
|
||||
|
||||
const DEFAULT_SNIPPET_LIST_PARAMS = {
|
||||
page: 1,
|
||||
@ -124,8 +139,13 @@ const normalizeSnippetListParams = (params: SnippetListParams) => {
|
||||
|
||||
const snippetListRootKey = ['snippets', 'list'] as const
|
||||
const snippetListKey = (params: SnippetListParams) => [...snippetListRootKey, params]
|
||||
const customizedSnippetsContract = consoleQuery.workspaces.current.customizedSnippets
|
||||
const customizedSnippetsClient = consoleClient.workspaces.current.customizedSnippets
|
||||
|
||||
const invalidateSnippetQueries = (queryClient: ReturnType<typeof useQueryClient>) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: customizedSnippetsContract.key(),
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.snippets.key(),
|
||||
})
|
||||
@ -134,15 +154,26 @@ const invalidateSnippetQueries = (queryClient: ReturnType<typeof useQueryClient>
|
||||
})
|
||||
}
|
||||
|
||||
const toGeneratedSnippetListQuery = (params: SnippetListParams) => {
|
||||
return {
|
||||
page: params.page,
|
||||
limit: params.limit,
|
||||
...(params.keyword ? { keyword: params.keyword } : {}),
|
||||
...(params.tag_ids?.length ? { tag_ids: params.tag_ids } : {}),
|
||||
...(params.creator_ids?.length ? { creators: params.creator_ids } : {}),
|
||||
...(typeof params.is_published === 'boolean' ? { is_published: params.is_published } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
export const useInfiniteSnippetList = (params: SnippetListParams = {}, options?: { enabled?: boolean }) => {
|
||||
const normalizedParams = normalizeSnippetListParams(params)
|
||||
|
||||
return useInfiniteQuery<SnippetListResponse>({
|
||||
queryKey: snippetListKey(normalizedParams),
|
||||
queryFn: ({ pageParam = normalizedParams.page }) => {
|
||||
return consoleClient.snippets.list({
|
||||
return customizedSnippetsClient.get({
|
||||
query: {
|
||||
...normalizedParams,
|
||||
...toGeneratedSnippetListQuery(normalizedParams),
|
||||
page: pageParam as number,
|
||||
},
|
||||
})
|
||||
@ -155,65 +186,82 @@ export const useInfiniteSnippetList = (params: SnippetListParams = {}, options?:
|
||||
}
|
||||
|
||||
export const useSnippetApiDetail = (snippetId: string) => {
|
||||
return useQuery(consoleQuery.snippets.detail.queryOptions({
|
||||
input: {
|
||||
params: { snippetId },
|
||||
},
|
||||
return useQuery({
|
||||
...customizedSnippetsContract.bySnippetId.get.queryOptions({
|
||||
input: {
|
||||
params: { snippet_id: snippetId },
|
||||
},
|
||||
}),
|
||||
enabled: !!snippetId,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
export const useCreateSnippetMutation = () => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(consoleQuery.snippets.create.mutationOptions({
|
||||
return useMutation<SnippetContract, Error, CreateSnippetInput>({
|
||||
mutationKey: customizedSnippetsContract.post.mutationKey(),
|
||||
mutationFn: input => customizedSnippetsClient.post(input),
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
},
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
export const useUpdateSnippetMutation = () => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
...consoleQuery.snippets.update.mutationOptions({
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
return useMutation<SnippetContract, Error, UpdateSnippetInput>({
|
||||
mutationKey: customizedSnippetsContract.bySnippetId.patch.mutationKey(),
|
||||
mutationFn: ({ params, body }) => customizedSnippetsClient.bySnippetId.patch({
|
||||
params: {
|
||||
snippet_id: params.snippetId,
|
||||
},
|
||||
body,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const useDeleteSnippetMutation = () => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
...consoleQuery.snippets.delete.mutationOptions({
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
return useMutation<unknown, Error, SnippetIdInput>({
|
||||
mutationKey: customizedSnippetsContract.bySnippetId.delete.mutationKey(),
|
||||
mutationFn: ({ params }) => customizedSnippetsClient.bySnippetId.delete({
|
||||
params: {
|
||||
snippet_id: params.snippetId,
|
||||
},
|
||||
}),
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const useIncrementSnippetUseCountMutation = () => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
...consoleQuery.snippets.incrementUseCount.mutationOptions({
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
return useMutation<IncrementSnippetUseCountResponse, Error, SnippetIdInput>({
|
||||
mutationKey: customizedSnippetsContract.bySnippetId.useCount.increment.post.mutationKey(),
|
||||
mutationFn: ({ params }) => customizedSnippetsClient.bySnippetId.useCount.increment.post({
|
||||
params: {
|
||||
snippet_id: params.snippetId,
|
||||
},
|
||||
}),
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const useExportSnippetMutation = () => {
|
||||
return useMutation<string, Error, { snippetId: string, include?: boolean }>({
|
||||
mutationFn: ({ snippetId, include = false }) => {
|
||||
return consoleClient.snippets.export({
|
||||
params: { snippetId },
|
||||
return customizedSnippetsClient.bySnippetId.export.get({
|
||||
params: { snippet_id: snippetId },
|
||||
query: { include_secret: include ? 'true' : 'false' },
|
||||
})
|
||||
},
|
||||
@ -225,13 +273,15 @@ export const useImportSnippetDSLMutation = () => {
|
||||
|
||||
return useMutation<SnippetDSLImportResponse, Error, { mode: 'yaml-content' | 'yaml-url', yamlContent?: string, yamlUrl?: string }>({
|
||||
mutationFn: ({ mode, yamlContent, yamlUrl }) => {
|
||||
return consoleClient.snippets.import({
|
||||
body: {
|
||||
mode,
|
||||
yaml_content: yamlContent,
|
||||
yaml_url: yamlUrl,
|
||||
},
|
||||
}) as Promise<SnippetDSLImportResponse>
|
||||
const body: SnippetImportPayload = {
|
||||
mode,
|
||||
yaml_content: yamlContent,
|
||||
yaml_url: yamlUrl,
|
||||
}
|
||||
|
||||
return customizedSnippetsClient.imports.post({
|
||||
body,
|
||||
})
|
||||
},
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
@ -244,11 +294,11 @@ export const useConfirmSnippetImportMutation = () => {
|
||||
|
||||
return useMutation<SnippetDSLImportResponse, Error, { importId: string }>({
|
||||
mutationFn: ({ importId }) => {
|
||||
return consoleClient.snippets.confirmImport({
|
||||
return customizedSnippetsClient.imports.byImportId.confirm.post({
|
||||
params: {
|
||||
importId,
|
||||
import_id: importId,
|
||||
},
|
||||
}) as Promise<SnippetDSLImportResponse>
|
||||
})
|
||||
},
|
||||
onSuccess: () => {
|
||||
invalidateSnippetQueries(queryClient)
|
||||
|
||||
@ -4,23 +4,37 @@ type SnippetType = 'node' | 'group'
|
||||
|
||||
type SnippetInputField = Record<string, unknown>
|
||||
|
||||
export type Snippet = {
|
||||
type SnippetTag = Tag
|
||||
|
||||
type SnippetAccount = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
type: SnippetType
|
||||
is_published: boolean
|
||||
version: string
|
||||
use_count: number
|
||||
tags: Tag[]
|
||||
input_fields: SnippetInputField[]
|
||||
created_at: number
|
||||
created_by: string
|
||||
updated_at: number
|
||||
updated_by: string
|
||||
email: string
|
||||
}
|
||||
|
||||
export type SnippetListItem = Omit<Snippet, 'version' | 'input_fields'>
|
||||
export type SnippetListItem = {
|
||||
id: string
|
||||
name: string
|
||||
description: string | null
|
||||
type: SnippetType
|
||||
is_published: boolean
|
||||
version: number
|
||||
use_count: number
|
||||
icon_info?: Record<string, unknown> | null
|
||||
tags: SnippetTag[]
|
||||
created_at: number
|
||||
created_by: string | null
|
||||
author_name?: string | null
|
||||
updated_at: number
|
||||
updated_by: string | null
|
||||
}
|
||||
|
||||
export type Snippet = Omit<SnippetListItem, 'created_by' | 'updated_by' | 'author_name'> & {
|
||||
graph: Record<string, unknown>
|
||||
input_fields: SnippetInputField[]
|
||||
created_by: SnippetAccount | null
|
||||
updated_by: SnippetAccount | null
|
||||
}
|
||||
|
||||
export type SnippetListResponse = {
|
||||
data: SnippetListItem[]
|
||||
@ -44,7 +58,7 @@ export type UpdateSnippetPayload = {
|
||||
}
|
||||
|
||||
export type SnippetImportPayload = {
|
||||
mode?: string
|
||||
mode: string
|
||||
yaml_content?: string
|
||||
yaml_url?: string
|
||||
snippet_id?: string
|
||||
@ -55,9 +69,9 @@ export type SnippetImportPayload = {
|
||||
export type SnippetDSLImportResponse = {
|
||||
id: string
|
||||
status: string
|
||||
snippet_id?: string
|
||||
current_dsl_version?: string
|
||||
imported_dsl_version?: string
|
||||
snippet_id: string | null
|
||||
current_dsl_version: string
|
||||
imported_dsl_version: string
|
||||
error: string
|
||||
}
|
||||
|
||||
@ -77,9 +91,8 @@ export type SnippetWorkflow = {
|
||||
}
|
||||
|
||||
export type SnippetDraftSyncPayload = {
|
||||
graph?: Record<string, unknown>
|
||||
graph: Record<string, unknown>
|
||||
hash?: string
|
||||
environment_variables?: Record<string, unknown>[]
|
||||
conversation_variables?: Record<string, unknown>[]
|
||||
input_fields?: SnippetInputField[]
|
||||
}
|
||||
@ -90,68 +103,12 @@ export type SnippetDraftSyncResponse = {
|
||||
updated_at: number
|
||||
}
|
||||
|
||||
export type SnippetDraftConfig = {
|
||||
parallel_depth_limit: number
|
||||
}
|
||||
|
||||
export type PublishSnippetWorkflowResponse = {
|
||||
result: string
|
||||
created_at: number
|
||||
}
|
||||
|
||||
export type WorkflowRunDetail = {
|
||||
id: string
|
||||
version: string
|
||||
status: 'running' | 'succeeded' | 'failed' | 'stopped' | 'partial-succeeded'
|
||||
elapsed_time: number
|
||||
total_tokens: number
|
||||
total_steps: number
|
||||
created_at: number
|
||||
finished_at: number
|
||||
exceptions_count: number
|
||||
}
|
||||
|
||||
export type WorkflowRunPagination = {
|
||||
limit: number
|
||||
has_more: boolean
|
||||
data: WorkflowRunDetail[]
|
||||
}
|
||||
|
||||
export type WorkflowNodeExecution = {
|
||||
id: string
|
||||
index: number
|
||||
node_id: string
|
||||
node_type: string
|
||||
title: string
|
||||
inputs: Record<string, unknown>
|
||||
process_data: Record<string, unknown>
|
||||
outputs: Record<string, unknown>
|
||||
status: string
|
||||
error: string
|
||||
elapsed_time: number
|
||||
created_at: number
|
||||
finished_at: number
|
||||
}
|
||||
|
||||
export type WorkflowNodeExecutionListResponse = {
|
||||
data: WorkflowNodeExecution[]
|
||||
}
|
||||
|
||||
export type SnippetDraftNodeRunPayload = {
|
||||
inputs?: Record<string, unknown>
|
||||
query?: string
|
||||
files?: Record<string, unknown>[]
|
||||
}
|
||||
|
||||
export type SnippetDraftRunPayload = {
|
||||
inputs?: Record<string, unknown>
|
||||
inputs: Record<string, unknown>
|
||||
files?: Record<string, unknown>[]
|
||||
}
|
||||
|
||||
export type SnippetIterationNodeRunPayload = {
|
||||
inputs?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type SnippetLoopNodeRunPayload = {
|
||||
inputs?: Record<string, unknown>
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user