w4c-workflows-api/Controllers/NodesController.cs
2026-09-11 19:04:50 +03:00

103 lines
3.2 KiB
C#

using Microsoft.AspNetCore.Mvc;
using w4c_workflows.Filters;
using w4c_workflows.Models.Nodes;
using w4c_workflows.Services.Nodes;
namespace w4c_workflows.Controllers;
/// <summary>
/// Node catalog surface. The authoring UI uses this to render its palette and
/// its generic parameter forms; it authenticates with the tenant operator key
/// like the rest of the control plane.
/// </summary>
[ApiController]
[Route("api/nodes")]
public class NodesController : ControllerBase
{
private readonly NodeBlueprintCatalog _catalog;
private readonly NodeExecutorRegistry _executors;
public NodesController(NodeBlueprintCatalog catalog, NodeExecutorRegistry executors)
{
_catalog = catalog;
_executors = executors;
}
/// <summary>Lists node types for the palette, with optional search/filter.</summary>
[HttpGet]
[RequireScope("read")]
public IActionResult List(
[FromQuery] string? search,
[FromQuery] string? kind,
[FromQuery] string? category,
[FromQuery] bool includeHidden = false)
{
var results = _catalog.Search(search, kind, category);
if (!includeHidden)
results = results.Where(b => !b.Hidden).ToList();
return Ok(results.Select(Summarize));
}
/// <summary>All category labels, for the palette's category rail.</summary>
[HttpGet("categories")]
[RequireScope("read")]
public IActionResult Categories() => Ok(_catalog.Categories);
/// <summary>Full blueprint for one node type (optionally a pinned version).</summary>
[HttpGet("{type}")]
[RequireScope("read")]
public IActionResult Get(string type, [FromQuery] double? version)
{
var blueprint = _catalog.Resolve(type, version);
if (blueprint is null)
return NotFound(new { error = $"unknown node type '{type}'" });
return Ok(new NodeDetail(blueprint, _executors.CanRun(blueprint.Type)));
}
private NodeSummary Summarize(NodeBlueprint blueprint) => new(
blueprint.Type,
blueprint.Version,
blueprint.DisplayName,
blueprint.Description,
blueprint.Kind,
blueprint.Categories,
blueprint.Icon,
blueprint.IconColor,
blueprint.RunMode,
blueprint.Hidden,
blueprint.Origin,
blueprint.Inputs.Count,
blueprint.Outputs.Count,
blueprint.Inputs,
blueprint.Outputs,
blueprint.ProducesErrorBranch,
blueprint.Credentials.Any(c => c.Required),
_executors.CanRun(blueprint.Type));
}
/// <summary>Palette entry: blueprint identity plus port shape, without the full form schema.</summary>
public sealed record NodeSummary(
string Type,
double Version,
string DisplayName,
string? Description,
string Kind,
IReadOnlyList<string> Categories,
string? Icon,
string? IconColor,
string RunMode,
bool Hidden,
string Origin,
int Inputs,
int Outputs,
IReadOnlyList<NodePort> InputPorts,
IReadOnlyList<NodePort> OutputPorts,
bool HasErrorBranch,
bool RequiresCredentials,
bool Runnable);
/// <summary>Full blueprint detail plus whether an executor is installed for it.</summary>
public sealed record NodeDetail(NodeBlueprint Blueprint, bool Runnable);