Skip to content

Commit e383211

Browse files
fix #2198, fix #2199, fix #2200, fix #2201, fix #2202
1 parent 8290b73 commit e383211

8 files changed

Lines changed: 3501 additions & 145 deletions

File tree

manual/src/main/paradox/topics/workflows.md

Lines changed: 1947 additions & 112 deletions
Large diffs are not rendered by default.

otoroshi/app/api/api.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,4 +2571,37 @@ class GenericApiController(ApiAction: ApiAction, cc: ControllerComponents)(impli
25712571
case _ => Ok(body).as("application/json").withHeaders("Access-Control-Allow-Origin" -> "*")
25722572
}
25732573
}
2574+
2575+
def workflowDescriptorJson() = Action {
2576+
val body = otoroshi.next.workflow.WorkflowGenerators.generateJsonDescriptor().prettify
2577+
Ok(body).as("application/json").withHeaders("Access-Control-Allow-Origin" -> "*")
2578+
}
2579+
2580+
def workflowDescriptorMarkdown() = Action {
2581+
val body = otoroshi.next.workflow.WorkflowGenerators.generateMarkdownDescriptor()
2582+
Ok(body).as("text/plain").withHeaders("Access-Control-Allow-Origin" -> "*")
2583+
}
2584+
2585+
def workflowDescriptorWeb() = Action {
2586+
val body =
2587+
s"""<html>
2588+
| <head>
2589+
| <title>Workflow doc</title>
2590+
| <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js" integrity="sha512-LhccdVNGe2QMEfI3x4DVV3ckMRe36TfydKss6mJpdHjNFiV07dFpS2xzeZedptKZrwxfICJpez09iNioiSZ3hA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
2591+
| </head>
2592+
| <body>
2593+
| <div id="root"></div>
2594+
| <script>
2595+
| var converter = new showdown.Converter();
2596+
| fetch('/apis/workflows/doc.md').then(r => r.text()).then(md => {
2597+
| var html = converter.makeHtml(md);
2598+
| document.getElementById("root").innerHTML = html;
2599+
| });
2600+
| </script>
2601+
| </body>
2602+
|</html>
2603+
|""".stripMargin
2604+
2605+
Ok(body).as("text/html").withHeaders("Access-Control-Allow-Origin" -> "*")
2606+
}
25742607
}

otoroshi/app/next/workflow/api.scala

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import scala.concurrent._
1414
import scala.jdk.CollectionConverters.collectionAsScalaIterableConverter
1515
import scala.util.Success
1616

17+
// TODO: time budget per node
18+
// TODO: fuel budget per run, with fuel consumption per node
1719
class WorkflowEngine(env: Env) {
1820

1921
implicit val executorContext = env.otoroshiExecutionContext
@@ -107,8 +109,11 @@ case class WorkflowRun(id: String, attrs: TypedMap, env: Env) {
107109
}
108110

109111
trait WorkflowFunction {
110-
def inputSchema: Option[JsObject] = None
111-
def outputSchema: Option[JsObject] = None
112+
def documentationName: String = this.getClass.getName.replace("$", "")
113+
def documentationDescription: String = "no description"
114+
def documentationInputSchema: Option[JsObject] = None
115+
def documentationOutputSchema: Option[JsObject] = None
116+
def documentationExample: Option[JsObject] = None
112117
def callWithRun(
113118
args: JsObject
114119
)(implicit env: Env, ec: ExecutionContext, wfr: WorkflowRun): Future[Either[WorkflowError, JsValue]] = call(args)
@@ -134,6 +139,10 @@ trait Node {
134139
def result: Option[String] = json.select("result").asOptString
135140
def returned: Option[JsValue] = json.select("returned").asOpt[JsValue]
136141
def run(wfr: WorkflowRun)(implicit env: Env, ec: ExecutionContext): Future[Either[WorkflowError, JsValue]]
142+
def documentationName: String = this.getClass.getSimpleName.replace("$", "").toLowerCase()
143+
def documentationDescription: String = "no description"
144+
def documentationInputSchema: Option[JsObject] = None
145+
def documentationExample: Option[JsObject] = None
137146
final def internalRun(
138147
wfr: WorkflowRun
139148
)(implicit env: Env, ec: ExecutionContext): Future[Either[WorkflowError, JsValue]] = {
@@ -183,6 +192,18 @@ object Node {
183192
),
184193
"returned" -> Json.obj("$mem_ref" -> Json.obj("name" -> "call_res"))
185194
)
195+
val baseInputSchema = Json.obj(
196+
"type" -> "object",
197+
"required" -> Seq("kind"),
198+
"properties" -> Json.obj(
199+
"id" -> Json.obj("type" -> "string", "description" -> "id of the node (optional). for debug purposes only"),
200+
"description" -> Json.obj("type" -> "string", "description" -> "The description of what this node does in the workflow (optional). for debug purposes only"),
201+
"kind" -> Json.obj("type" -> "string", "description" -> "The kind of the node"),
202+
"enabled" -> Json.obj("type" -> "boolean", "description" -> "Is the node enabled (optional)"),
203+
"result" -> Json.obj("type" -> "string", "description" -> "The name of the memory that will be assigned with the result of this node (optional)"),
204+
"returned" -> Json.obj("type" -> "string", "description" -> "Overrides the output of the node with the result of an operator (optional)"),
205+
)
206+
)
186207
val nodes = new TrieMap[String, (JsObject) => Node]()
187208
def registerNode(name: String, f: (JsObject) => Node): Unit = {
188209
nodes.put(name, f)
@@ -197,11 +218,15 @@ object Node {
197218
}
198219

199220
trait WorkflowOperator {
221+
def documentationName: String = this.getClass.getName.replace("$", "")
222+
def documentationDescription: String = "no description"
223+
def documentationInputSchema: Option[JsObject] = None
224+
def documentationExample: Option[JsObject] = None
200225
def process(opts: JsValue, wfr: WorkflowRun, env: Env): JsValue
201226
}
202227

203228
object WorkflowOperator {
204-
private val operators = new TrieMap[String, WorkflowOperator]()
229+
val operators = new TrieMap[String, WorkflowOperator]()
205230
def registerOperator(name: String, operator: WorkflowOperator): Unit = {
206231
operators.put(name, operator)
207232
}

0 commit comments

Comments
 (0)