Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -0,0 +1,717 @@
|
||||
import { WorkflowsTemplateDto } from "../dtos/WorkflowsTemplateDto";
|
||||
|
||||
type LanguageScopedWorkflowsTemplateDto = WorkflowsTemplateDto & {
|
||||
defaultLanguage: "en";
|
||||
languages: readonly ["en"];
|
||||
};
|
||||
|
||||
const ENGLISH_TEMPLATE_SCOPE = {
|
||||
defaultLanguage: "en",
|
||||
languages: ["en"],
|
||||
} as const;
|
||||
|
||||
function templateKey(path: string) {
|
||||
return `workflows.defaultTemplates.${path}`;
|
||||
}
|
||||
|
||||
const templates: LanguageScopedWorkflowsTemplateDto[] = [
|
||||
{
|
||||
...ENGLISH_TEMPLATE_SCOPE,
|
||||
adminOnly: true,
|
||||
key: "sampleHttpRequests",
|
||||
title: templateKey("sampleHttpRequests.title"),
|
||||
workflows: [
|
||||
{
|
||||
key: "getJsonPlaceholderTodoItem",
|
||||
name: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.name"),
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.description"),
|
||||
blocks: [
|
||||
{
|
||||
id: "manualTrigger",
|
||||
type: "manual",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.manualTrigger.description"),
|
||||
input: {
|
||||
validation: JSON.stringify(
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
id: { type: "number" },
|
||||
},
|
||||
required: ["id"],
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "httpRequest",
|
||||
type: "httpRequest",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.httpRequest.description"),
|
||||
input: {
|
||||
url: "{{$vars.jsonPlaceholderUrl}}/todos/{{$params.id}}",
|
||||
method: "GET",
|
||||
// body: "",
|
||||
// headers: {},
|
||||
throwsError: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "if",
|
||||
type: "if",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.if.description"),
|
||||
conditionGroups: [
|
||||
{
|
||||
type: "AND",
|
||||
conditions: [
|
||||
{
|
||||
variable: "{{httpRequest.statusCode}}",
|
||||
operator: "=",
|
||||
value: "200",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "logNotFound",
|
||||
type: "alertUser",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.logNotFound.description"),
|
||||
input: {
|
||||
type: "error",
|
||||
message: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.logNotFound.input.message"),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "logFound",
|
||||
type: "alertUser",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.logFound.description"),
|
||||
input: {
|
||||
message: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.logFound.input.message"),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "switchTitle",
|
||||
type: "switch",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.switchTitle.description"),
|
||||
conditionGroups: [
|
||||
{
|
||||
type: "AND",
|
||||
case: "case1",
|
||||
conditions: [
|
||||
{
|
||||
variable: "{{httpRequest.body.title}}",
|
||||
operator: "=",
|
||||
value: "delectus aut autem",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "AND",
|
||||
case: "case2",
|
||||
conditions: [
|
||||
{
|
||||
variable: "{{httpRequest.body.title}}",
|
||||
operator: "contains",
|
||||
value: "quis",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "switchCase1",
|
||||
type: "alertUser",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.switchCase1.description"),
|
||||
input: {
|
||||
message: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.switchCase1.input.message"),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "switchCase2",
|
||||
type: "alertUser",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.switchCase2.description"),
|
||||
input: {
|
||||
message: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.switchCase2.input.message"),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "switchDefault",
|
||||
type: "alertUser",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.switchDefault.description"),
|
||||
input: {
|
||||
message: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.switchDefault.input.message"),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "alertUser",
|
||||
type: "alertUser",
|
||||
description: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.alertUser.description"),
|
||||
input: {
|
||||
message: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.blocks.alertUser.input.message"),
|
||||
},
|
||||
},
|
||||
],
|
||||
toBlocks: [
|
||||
{ fromBlockId: "manualTrigger", toBlockId: "httpRequest" },
|
||||
{ fromBlockId: "httpRequest", toBlockId: "if" },
|
||||
{ fromBlockId: "if", toBlockId: "logNotFound", condition: "false" },
|
||||
{ fromBlockId: "if", toBlockId: "logFound", condition: "true" },
|
||||
{ fromBlockId: "logFound", toBlockId: "switchTitle" },
|
||||
{ fromBlockId: "switchTitle", toBlockId: "switchCase1", condition: "case1" },
|
||||
{ fromBlockId: "switchTitle", toBlockId: "switchCase2", condition: "case2" },
|
||||
{ fromBlockId: "switchTitle", toBlockId: "switchDefault", condition: "default" },
|
||||
{ fromBlockId: "switchCase1", toBlockId: "alertUser" },
|
||||
{ fromBlockId: "switchCase2", toBlockId: "alertUser" },
|
||||
{ fromBlockId: "switchDefault", toBlockId: "alertUser" },
|
||||
],
|
||||
inputExamples: [
|
||||
{
|
||||
key: "existingItem",
|
||||
title: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.inputExamples.existingItem.title"),
|
||||
input: { id: 10 },
|
||||
},
|
||||
{
|
||||
key: "nonExistingItem",
|
||||
title: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.inputExamples.nonExistingItem.title"),
|
||||
input: { id: -1 },
|
||||
},
|
||||
{
|
||||
key: "idParameterNotProvided",
|
||||
title: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.inputExamples.idParameterNotProvided.title"),
|
||||
input: {},
|
||||
},
|
||||
{
|
||||
key: "idParameterNotNumber",
|
||||
title: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.inputExamples.idParameterNotNumber.title"),
|
||||
input: { id: "abc" },
|
||||
},
|
||||
{
|
||||
key: "case1Equal",
|
||||
title: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.inputExamples.case1Equal.title"),
|
||||
input: { id: 1 },
|
||||
},
|
||||
{
|
||||
key: "case2Contains",
|
||||
title: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.inputExamples.case2Contains.title"),
|
||||
input: { id: 2 },
|
||||
},
|
||||
{
|
||||
key: "defaultCase",
|
||||
title: templateKey("sampleHttpRequests.workflows.getJsonPlaceholderTodoItem.inputExamples.defaultCase.title"),
|
||||
input: { id: 3 },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
variables: [{ name: "jsonPlaceholderUrl", value: "https://jsonplaceholder.typicode.com" }],
|
||||
},
|
||||
{
|
||||
...ENGLISH_TEMPLATE_SCOPE,
|
||||
adminOnly: true,
|
||||
key: "alertUser",
|
||||
title: templateKey("alertUser.title"),
|
||||
workflows: [
|
||||
{
|
||||
key: "alertUser",
|
||||
name: templateKey("alertUser.workflows.alertUser.name"),
|
||||
description: templateKey("alertUser.workflows.alertUser.description"),
|
||||
blocks: [
|
||||
{
|
||||
id: "manualTrigger",
|
||||
type: "manual",
|
||||
description: templateKey("alertUser.workflows.alertUser.blocks.manualTrigger.description"),
|
||||
input: {
|
||||
validation: JSON.stringify(
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
message: { type: "string" },
|
||||
},
|
||||
required: ["message"],
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "alertUser",
|
||||
type: "alertUser",
|
||||
description: templateKey("alertUser.workflows.alertUser.blocks.alertUser.description"),
|
||||
input: {
|
||||
message: `{{$params.message}}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
toBlocks: [{ fromBlockId: "manualTrigger", toBlockId: "alertUser" }],
|
||||
inputExamples: [
|
||||
{ key: "existingItem", title: templateKey("alertUser.workflows.alertUser.inputExamples.existingItem.title"), input: { message: "Hello world!" } },
|
||||
],
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
},
|
||||
{
|
||||
...ENGLISH_TEMPLATE_SCOPE,
|
||||
adminOnly: true,
|
||||
key: "iterator",
|
||||
title: templateKey("iterator.title"),
|
||||
workflows: [
|
||||
{
|
||||
key: "loopItems",
|
||||
name: templateKey("iterator.workflows.loopItems.name"),
|
||||
description: templateKey("iterator.workflows.loopItems.description"),
|
||||
blocks: [
|
||||
{
|
||||
id: "iterator",
|
||||
type: "iterator",
|
||||
description: templateKey("iterator.workflows.loopItems.blocks.iterator.description"),
|
||||
input: {
|
||||
variableName: "{{$params.array}}",
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
{
|
||||
id: "manual",
|
||||
type: "manual",
|
||||
description: templateKey("iterator.workflows.loopItems.blocks.manual.description"),
|
||||
input: {},
|
||||
conditionGroups: [],
|
||||
},
|
||||
{
|
||||
id: "log1",
|
||||
type: "log",
|
||||
description: templateKey("iterator.workflows.loopItems.blocks.log1.description"),
|
||||
input: {
|
||||
message: templateKey("iterator.workflows.loopItems.blocks.log1.input.message"),
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
{
|
||||
id: "log2",
|
||||
type: "log",
|
||||
description: templateKey("iterator.workflows.loopItems.blocks.log2.description"),
|
||||
input: {
|
||||
message: templateKey("iterator.workflows.loopItems.blocks.log2.input.message"),
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
],
|
||||
toBlocks: [
|
||||
{
|
||||
fromBlockId: "iterator",
|
||||
toBlockId: "log1",
|
||||
condition: "loopNext",
|
||||
},
|
||||
{
|
||||
fromBlockId: "iterator",
|
||||
toBlockId: "log2",
|
||||
condition: "loopEnd",
|
||||
},
|
||||
{
|
||||
fromBlockId: "manual",
|
||||
toBlockId: "iterator",
|
||||
},
|
||||
],
|
||||
inputExamples: [
|
||||
{
|
||||
key: "stringArray",
|
||||
title: templateKey("iterator.workflows.loopItems.inputExamples.stringArray.title"),
|
||||
input: {
|
||||
array: ["value 1", "value 2"],
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "objectArray",
|
||||
title: templateKey("iterator.workflows.loopItems.inputExamples.objectArray.title"),
|
||||
input: {
|
||||
array: [
|
||||
{
|
||||
name: "Value 1",
|
||||
value: "value 1",
|
||||
},
|
||||
{
|
||||
name: "Value 2",
|
||||
value: "value 2",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
credentialsRequired: [],
|
||||
},
|
||||
{
|
||||
...ENGLISH_TEMPLATE_SCOPE,
|
||||
key: "rowEventsEmployee",
|
||||
title: templateKey("rowEventsEmployee.title"),
|
||||
workflows: [
|
||||
// {
|
||||
// name: "Row Get: Employee",
|
||||
// description: "Gets employee or null",
|
||||
// blocks: [
|
||||
// {
|
||||
// id: "manual",
|
||||
// type: "manual",
|
||||
// input: {},
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// {
|
||||
// id: "rowGet",
|
||||
// type: "rowGet",
|
||||
// input: {
|
||||
// entity: "employee",
|
||||
// id: "{{$params.id}}",
|
||||
// },
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// {
|
||||
// id: "if",
|
||||
// type: "if",
|
||||
// input: {},
|
||||
// conditionGroups: [
|
||||
// {
|
||||
// type: "AND",
|
||||
// conditions: [
|
||||
// {
|
||||
// variable: "{{rowGet.row}}",
|
||||
// operator: "isNotEmpty",
|
||||
// value: "",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// id: "log1",
|
||||
// type: "log",
|
||||
// description: "Found",
|
||||
// input: {
|
||||
// message:
|
||||
// "Employee: {{rowGet.row.firstName}}. Last name: {{rowGet.row.lastName}}. Email: {{rowGet.row.email}}.Employee: {{rowGet.row.firstName}}. Last name: {{rowGet.row.lastName}}. Email: {{rowGet.row.email}}.",
|
||||
// },
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// {
|
||||
// id: "log2",
|
||||
// type: "log",
|
||||
// description: "Not found",
|
||||
// input: {
|
||||
// message: "Not found",
|
||||
// },
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// ],
|
||||
// toBlocks: [
|
||||
// {
|
||||
// fromBlockId: "manual",
|
||||
// toBlockId: "rowGet",
|
||||
// },
|
||||
// {
|
||||
// fromBlockId: "rowGet",
|
||||
// toBlockId: "if",
|
||||
// },
|
||||
// {
|
||||
// fromBlockId: "if",
|
||||
// toBlockId: "log1",
|
||||
// condition: "true",
|
||||
// },
|
||||
// {
|
||||
// fromBlockId: "if",
|
||||
// toBlockId: "log2",
|
||||
// condition: "false",
|
||||
// },
|
||||
// ],
|
||||
// inputExamples: [
|
||||
// {
|
||||
// title: "Valid request",
|
||||
// input: {
|
||||
// id: "ROW_ID_HERE",
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
key: "createdEmployee",
|
||||
name: templateKey("rowEventsEmployee.workflows.createdEmployee.name"),
|
||||
blocks: [
|
||||
{
|
||||
id: "event",
|
||||
type: "event",
|
||||
description: templateKey("rowEventsEmployee.workflows.createdEmployee.blocks.event.description"),
|
||||
input: {
|
||||
event: "row.created",
|
||||
entity: "employee",
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
{
|
||||
id: "log",
|
||||
type: "log",
|
||||
description: templateKey("rowEventsEmployee.workflows.createdEmployee.blocks.log.description"),
|
||||
input: {
|
||||
message: templateKey("rowEventsEmployee.workflows.createdEmployee.blocks.log.input.message"),
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
],
|
||||
toBlocks: [
|
||||
{
|
||||
fromBlockId: "event",
|
||||
toBlockId: "log",
|
||||
},
|
||||
],
|
||||
inputExamples: [
|
||||
{
|
||||
key: "fakeEmployee",
|
||||
title: templateKey("rowEventsEmployee.workflows.createdEmployee.inputExamples.fakeEmployee.title"),
|
||||
input: {
|
||||
event: "created",
|
||||
entity: "employee",
|
||||
row: {
|
||||
id: "fake-id",
|
||||
firstName: "Avery",
|
||||
lastName: "Morgan",
|
||||
email: "avery.morgan@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "invalidEvent",
|
||||
title: templateKey("rowEventsEmployee.workflows.createdEmployee.inputExamples.invalidEvent.title"),
|
||||
input: {
|
||||
event: "updated",
|
||||
entity: "employee",
|
||||
row: {
|
||||
id: "fake-id",
|
||||
firstName: "Avery",
|
||||
lastName: "Morgan",
|
||||
email: "avery.morgan@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "invalidEntity",
|
||||
title: templateKey("rowEventsEmployee.workflows.createdEmployee.inputExamples.invalidEntity.title"),
|
||||
input: {
|
||||
event: "created",
|
||||
entity: "sale",
|
||||
row: {
|
||||
id: "fake-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// name: "Row Create: Employee",
|
||||
// description: "Creates John Doe employee",
|
||||
// blocks: [
|
||||
// {
|
||||
// id: "rowCreate",
|
||||
// type: "rowCreate",
|
||||
// description: "Creates John Doe employee",
|
||||
// input: {
|
||||
// entity: "employee",
|
||||
// row: '{\n "firstName": "John",\n "lastName": "Doe",\n "email": "john@doe.com"\n}',
|
||||
// },
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// {
|
||||
// id: "manual",
|
||||
// type: "manual",
|
||||
// input: {},
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// ],
|
||||
// toBlocks: [
|
||||
// {
|
||||
// fromBlockId: "manual",
|
||||
// toBlockId: "rowCreate",
|
||||
// },
|
||||
// ],
|
||||
// inputExamples: [],
|
||||
// },
|
||||
{
|
||||
key: "updatedEmployee",
|
||||
name: templateKey("rowEventsEmployee.workflows.updatedEmployee.name"),
|
||||
description: templateKey("rowEventsEmployee.workflows.updatedEmployee.description"),
|
||||
blocks: [
|
||||
{
|
||||
id: "event",
|
||||
type: "event",
|
||||
description: templateKey("rowEventsEmployee.workflows.updatedEmployee.blocks.event.description"),
|
||||
input: {
|
||||
event: "row.updated",
|
||||
entity: "employee",
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
{
|
||||
id: "log",
|
||||
type: "log",
|
||||
description: templateKey("rowEventsEmployee.workflows.updatedEmployee.blocks.log.description"),
|
||||
input: {
|
||||
message: templateKey("rowEventsEmployee.workflows.updatedEmployee.blocks.log.input.message"),
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
],
|
||||
toBlocks: [
|
||||
{
|
||||
fromBlockId: "event",
|
||||
toBlockId: "log",
|
||||
},
|
||||
],
|
||||
inputExamples: [],
|
||||
},
|
||||
// {
|
||||
// name: "Row Update: Employee",
|
||||
// description: "Updates employee",
|
||||
// blocks: [
|
||||
// {
|
||||
// id: "manual",
|
||||
// type: "manual",
|
||||
// input: {},
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// {
|
||||
// id: "rowUpdate",
|
||||
// type: "rowUpdate",
|
||||
// input: {
|
||||
// data: '{\n "firstName": "Updated first name",\n "lastName": "Updated last name"\n}',
|
||||
// id: "{{$params.id}}",
|
||||
// entity: "employee",
|
||||
// },
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// ],
|
||||
// toBlocks: [
|
||||
// {
|
||||
// fromBlockId: "manual",
|
||||
// toBlockId: "rowUpdate",
|
||||
// },
|
||||
// ],
|
||||
// inputExamples: [
|
||||
// {
|
||||
// title: "Valid request",
|
||||
// input: {
|
||||
// id: "ROW_ID_HERE",
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
key: "deletedEmployee",
|
||||
name: templateKey("rowEventsEmployee.workflows.deletedEmployee.name"),
|
||||
description: templateKey("rowEventsEmployee.workflows.deletedEmployee.description"),
|
||||
blocks: [
|
||||
{
|
||||
id: "log",
|
||||
type: "log",
|
||||
description: templateKey("rowEventsEmployee.workflows.deletedEmployee.blocks.log.description"),
|
||||
input: {
|
||||
message: templateKey("rowEventsEmployee.workflows.deletedEmployee.blocks.log.input.message"),
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
{
|
||||
id: "event",
|
||||
type: "event",
|
||||
description: templateKey("rowEventsEmployee.workflows.deletedEmployee.blocks.event.description"),
|
||||
input: {
|
||||
event: "row.deleted",
|
||||
entity: "employee",
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
],
|
||||
toBlocks: [
|
||||
{
|
||||
fromBlockId: "event",
|
||||
toBlockId: "log",
|
||||
},
|
||||
],
|
||||
inputExamples: [],
|
||||
},
|
||||
// {
|
||||
// name: "Row Delete: Employee",
|
||||
// description: "Deletes employee",
|
||||
// blocks: [
|
||||
// {
|
||||
// id: "manual",
|
||||
// type: "manual",
|
||||
// input: {},
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// {
|
||||
// id: "rowDelete",
|
||||
// type: "rowDelete",
|
||||
// input: {
|
||||
// entity: "employee",
|
||||
// id: "{{$params.id}}",
|
||||
// },
|
||||
// conditionGroups: [],
|
||||
// },
|
||||
// ],
|
||||
// toBlocks: [
|
||||
// {
|
||||
// fromBlockId: "manual",
|
||||
// toBlockId: "rowDelete",
|
||||
// },
|
||||
// ],
|
||||
// inputExamples: [
|
||||
// {
|
||||
// title: "Valid request",
|
||||
// input: {
|
||||
// id: "ROW_ID_HERE",
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
...ENGLISH_TEMPLATE_SCOPE,
|
||||
key: "emails",
|
||||
title: templateKey("emails.title"),
|
||||
workflows: [
|
||||
{
|
||||
key: "mailjetEmail",
|
||||
name: templateKey("emails.workflows.mailjetEmail.name"),
|
||||
blocks: [
|
||||
{
|
||||
id: "manual",
|
||||
type: "manual",
|
||||
input: {},
|
||||
conditionGroups: [],
|
||||
},
|
||||
{
|
||||
id: "email",
|
||||
type: "email",
|
||||
description: templateKey("emails.workflows.mailjetEmail.blocks.email.description"),
|
||||
input: {
|
||||
provider: "mailjet",
|
||||
to: "{{$session.user.email}}",
|
||||
subject: templateKey("emails.workflows.mailjetEmail.blocks.email.input.subject"),
|
||||
body: templateKey("emails.workflows.mailjetEmail.blocks.email.input.body"),
|
||||
},
|
||||
conditionGroups: [],
|
||||
},
|
||||
],
|
||||
toBlocks: [
|
||||
{
|
||||
fromBlockId: "manual",
|
||||
toBlockId: "email",
|
||||
},
|
||||
],
|
||||
inputExamples: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default templates;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { formatWorkflowExecutionErrorText } from "./workflowExecutionErrorText";
|
||||
|
||||
function t(key: string, options?: Record<string, unknown>) {
|
||||
return JSON.stringify({ key, options });
|
||||
}
|
||||
|
||||
describe("formatWorkflowExecutionErrorText", () => {
|
||||
it("maps exact workflow runtime errors to translatable keys", () => {
|
||||
expect(formatWorkflowExecutionErrorText("URL is required", t)).toBe(
|
||||
JSON.stringify({
|
||||
key: "workflows.executionErrors.urlRequired",
|
||||
options: { defaultValue: "URL is required" },
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("maps parameterized workflow runtime errors to translatable keys", () => {
|
||||
expect(formatWorkflowExecutionErrorText('Variable "orders" is not an array', t)).toBe(
|
||||
JSON.stringify({
|
||||
key: "workflows.executionErrors.variableNotArray",
|
||||
options: { name: "orders", defaultValue: 'Variable "orders" is not an array' },
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps unknown provider errors unchanged", () => {
|
||||
expect(formatWorkflowExecutionErrorText("Provider failed for https://api.example.test", t)).toBe("Provider failed for https://api.example.test");
|
||||
});
|
||||
|
||||
it("returns an empty string for empty errors", () => {
|
||||
expect(formatWorkflowExecutionErrorText(null, t)).toBe("");
|
||||
expect(formatWorkflowExecutionErrorText(undefined, t)).toBe("");
|
||||
});
|
||||
});
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
type WorkflowErrorT = (key: string, options?: Record<string, unknown>) => string;
|
||||
|
||||
type WorkflowErrorRule = {
|
||||
key: string;
|
||||
match: string | RegExp;
|
||||
params?: (match: RegExpMatchArray) => Record<string, string>;
|
||||
};
|
||||
|
||||
const WORKFLOW_ERROR_RULES: WorkflowErrorRule[] = [
|
||||
{ match: "Workflow is not ready to run", key: "workflows.executionErrors.workflowNotReady" },
|
||||
{ match: /^Invalid workflow block type: (.+)$/u, key: "workflows.executionErrors.invalidBlockType", params: ([, type]) => ({ type }) },
|
||||
{ match: /^Workflow execution cycle detected at block (.+)$/u, key: "workflows.executionErrors.cycleDetected", params: ([, blockId]) => ({ blockId }) },
|
||||
{ match: /^Workflow execution exceeded maximum depth of (.+)$/u, key: "workflows.executionErrors.maxDepthExceeded", params: ([, depth]) => ({ depth }) },
|
||||
{ match: "URL is required", key: "workflows.executionErrors.urlRequired" },
|
||||
{ match: "Method is required", key: "workflows.executionErrors.methodRequired" },
|
||||
{ match: "Headers must be a JSON object", key: "workflows.executionErrors.headersJsonObject" },
|
||||
{ match: "Missing true block", key: "workflows.executionErrors.missingTrueBlock" },
|
||||
{ match: "Missing false block", key: "workflows.executionErrors.missingFalseBlock" },
|
||||
{ match: "If block must have exactly one condition group", key: "workflows.executionErrors.ifSingleConditionGroup" },
|
||||
{
|
||||
match: /^\[(.+)\] Missing block for condition: (.+)$/u,
|
||||
key: "workflows.executionErrors.missingConditionBlock",
|
||||
params: ([, blockName, condition]) => ({ blockName, condition }),
|
||||
},
|
||||
{ match: "Missing default block", key: "workflows.executionErrors.missingDefaultBlock" },
|
||||
{
|
||||
match: /^\[(.+)\] Missing loop next block$/u,
|
||||
key: "workflows.executionErrors.missingLoopNextBlock",
|
||||
params: ([, blockName]) => ({ blockName }),
|
||||
},
|
||||
{
|
||||
match: /^\[(.+)\] Missing loop end block$/u,
|
||||
key: "workflows.executionErrors.missingLoopEndBlock",
|
||||
params: ([, blockName]) => ({ blockName }),
|
||||
},
|
||||
{ match: /^Property not found for key: (.+)$/u, key: "workflows.executionErrors.propertyNotFound", params: ([, key]) => ({ key }) },
|
||||
{ match: /^Variable "(.+)" not found$/u, key: "workflows.executionErrors.variableNotFound", params: ([, name]) => ({ name }) },
|
||||
{ match: /^Variable "(.+)" is not an array$/u, key: "workflows.executionErrors.variableNotArray", params: ([, name]) => ({ name }) },
|
||||
{ match: "Variable blocks cannot persist workflow credentials.", key: "workflows.executionErrors.variableCredentialPersistence" },
|
||||
{ match: /^Invalid operator: (.+)$/u, key: "workflows.executionErrors.invalidOperator", params: ([, operator]) => ({ operator }) },
|
||||
{ match: /^Block type not implemented: (.+)$/u, key: "workflows.executionErrors.blockTypeNotImplemented", params: ([, type]) => ({ type }) },
|
||||
{ match: "No response from AI", key: "workflows.executionErrors.noAiResponse" },
|
||||
{ match: "Missing email data: provider, to, subject, body", key: "workflows.executionErrors.missingEmailData" },
|
||||
{ match: /^Invalid email provider: (.+)$/u, key: "workflows.executionErrors.invalidEmailProvider", params: ([, provider]) => ({ provider }) },
|
||||
{ match: /^Workflow not found: (.+)$/u, key: "workflows.executionErrors.workflowNotFoundWithId", params: ([, workflowId]) => ({ workflowId }) },
|
||||
{ match: "Workflow is not live.", key: "workflows.executionErrors.workflowNotLive" },
|
||||
{ match: "Workflow is not available for tenant API execution.", key: "workflows.executionErrors.workflowTenantApiUnavailable" },
|
||||
{ match: /^Workflow has no block with id (.+)$/u, key: "workflows.executionErrors.workflowMissingBlockWithId", params: ([, blockId]) => ({ blockId }) },
|
||||
{ match: "Workflow has no trigger block", key: "workflows.executionErrors.workflowMissingTriggerBlock" },
|
||||
{ match: "Workflow execution not found", key: "workflows.executionErrors.executionNotFound" },
|
||||
{ match: "Workflow execution is not waiting for a block", key: "workflows.executionErrors.executionNotWaitingForBlock" },
|
||||
{ match: "Workflow execution is not waiting", key: "workflows.executionErrors.executionNotWaiting" },
|
||||
{
|
||||
match: /^Workflow execution does not belong to workflow (.+)$/u,
|
||||
key: "workflows.executionErrors.executionWorkflowMismatch",
|
||||
params: ([, workflowId]) => ({ workflowId }),
|
||||
},
|
||||
{ match: "Workflow execution type mismatch", key: "workflows.executionErrors.executionTypeMismatch" },
|
||||
{ match: "Workflow execution is not queued", key: "workflows.executionErrors.executionNotQueued" },
|
||||
{ match: "Workflow stream execution failed.", key: "workflows.executionErrors.streamFailed" },
|
||||
];
|
||||
|
||||
export function formatWorkflowExecutionErrorText(error: string | null | undefined, t: WorkflowErrorT): string {
|
||||
if (!error) {
|
||||
return "";
|
||||
}
|
||||
|
||||
for (const rule of WORKFLOW_ERROR_RULES) {
|
||||
if (typeof rule.match === "string") {
|
||||
if (rule.match === error) {
|
||||
return t(rule.key, { defaultValue: error });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = error.match(rule.match);
|
||||
if (match) {
|
||||
return t(rule.key, { ...rule.params?.(match), defaultValue: error });
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { TFunction } from "i18next";
|
||||
import DefaultWorkflowTemplates from "./DefaultWorkflowTemplates";
|
||||
import {
|
||||
getTemplateBlockDescription,
|
||||
getTemplateInputExampleTitle,
|
||||
getTemplateTitle,
|
||||
getTemplateWorkflowDescription,
|
||||
getTemplateWorkflowName,
|
||||
localizeTemplateInputExampleInput,
|
||||
localizeTemplateBlockInput,
|
||||
localizeWorkflowTemplate,
|
||||
} from "./workflowTemplateI18n";
|
||||
import type { WorkflowsTemplateDto } from "../dtos/WorkflowsTemplateDto";
|
||||
|
||||
const template: WorkflowsTemplateDto = {
|
||||
key: "sample",
|
||||
title: "Sample",
|
||||
workflows: [
|
||||
{
|
||||
key: "workflow",
|
||||
name: "Workflow",
|
||||
description: "Description",
|
||||
blocks: [{ id: "manual", type: "manual", description: "Manual block", input: { message: "Hello", url: "https://example.com" } }],
|
||||
toBlocks: [],
|
||||
inputExamples: [{ key: "example", title: "Example", input: { message: "Hello", nested: { label: "Label" }, items: ["One"], array: ["Array item", { name: "Name", value: "Value" }] } }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const t: TFunction = ((key: string, options?: { defaultValue?: string }) => `${key}::${options?.defaultValue ?? ""}`) as TFunction;
|
||||
const repoRoot = process.cwd();
|
||||
|
||||
describe("workflowTemplateI18n", () => {
|
||||
it("builds semantic keys for default workflow template metadata", () => {
|
||||
const workflow = template.workflows[0];
|
||||
|
||||
expect(getTemplateTitle(template, t)).toBe("workflows.defaultTemplates.sample.title::Sample");
|
||||
expect(getTemplateWorkflowName(template, workflow, t)).toBe("workflows.defaultTemplates.sample.workflows.workflow.name::Workflow");
|
||||
expect(getTemplateWorkflowDescription(template, workflow, t)).toBe("workflows.defaultTemplates.sample.workflows.workflow.description::Description");
|
||||
expect(getTemplateBlockDescription(template, workflow, workflow.blocks[0], t)).toBe(
|
||||
"workflows.defaultTemplates.sample.workflows.workflow.blocks.manual.description::Manual block"
|
||||
);
|
||||
expect(getTemplateInputExampleTitle(template, workflow, workflow.inputExamples[0], t)).toBe(
|
||||
"workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.title::Example"
|
||||
);
|
||||
});
|
||||
|
||||
it("localizes only user-facing template block input fields", () => {
|
||||
const workflow = template.workflows[0];
|
||||
const localized = localizeTemplateBlockInput(template, workflow, workflow.blocks[0], t);
|
||||
|
||||
expect(localized).toEqual({
|
||||
message: "workflows.defaultTemplates.sample.workflows.workflow.blocks.manual.input.message::Hello",
|
||||
url: "https://example.com",
|
||||
});
|
||||
});
|
||||
|
||||
it("localizes keyed input example string payloads recursively", () => {
|
||||
const workflow = template.workflows[0];
|
||||
const input = localizeTemplateInputExampleInput(template, workflow, workflow.inputExamples[0], t);
|
||||
|
||||
expect(input).toEqual({
|
||||
message: "workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.input.message::Hello",
|
||||
nested: {
|
||||
label: "Label",
|
||||
},
|
||||
items: ["One"],
|
||||
array: [
|
||||
"workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.input.array.0::Array item",
|
||||
{
|
||||
name: "workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.input.array.1.name::Name",
|
||||
value: "workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.input.array.1.value::Value",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to canonical template values for custom imported JSON without keys", () => {
|
||||
const custom: WorkflowsTemplateDto = {
|
||||
title: "Custom",
|
||||
workflows: [{ name: "Custom workflow", blocks: [{ id: "block", type: "log", description: "Custom block" }], toBlocks: [], inputExamples: [] }],
|
||||
};
|
||||
const workflow = custom.workflows[0];
|
||||
|
||||
expect(getTemplateTitle(custom, t)).toBe("Custom");
|
||||
expect(getTemplateWorkflowName(custom, workflow, t)).toBe("Custom workflow");
|
||||
expect(getTemplateBlockDescription(custom, workflow, workflow.blocks[0], t)).toBe("Custom block");
|
||||
});
|
||||
|
||||
it("clones and localizes keyed templates for import persistence", () => {
|
||||
const localized = localizeWorkflowTemplate(template, t);
|
||||
|
||||
expect(localized).not.toBe(template);
|
||||
expect(localized.workflows[0]).not.toBe(template.workflows[0]);
|
||||
expect(localized.title).toBe("workflows.defaultTemplates.sample.title::Sample");
|
||||
expect(localized.workflows[0].name).toBe("workflows.defaultTemplates.sample.workflows.workflow.name::Workflow");
|
||||
expect(localized.workflows[0].description).toBe("workflows.defaultTemplates.sample.workflows.workflow.description::Description");
|
||||
expect(localized.workflows[0].blocks[0].description).toBe("workflows.defaultTemplates.sample.workflows.workflow.blocks.manual.description::Manual block");
|
||||
expect(localized.workflows[0].blocks[0].input).toEqual({
|
||||
message: "workflows.defaultTemplates.sample.workflows.workflow.blocks.manual.input.message::Hello",
|
||||
url: "https://example.com",
|
||||
});
|
||||
expect(localized.workflows[0].inputExamples[0].title).toBe("workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.title::Example");
|
||||
expect(localized.workflows[0].inputExamples[0].input).toEqual({
|
||||
message: "workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.input.message::Hello",
|
||||
nested: {
|
||||
label: "Label",
|
||||
},
|
||||
items: ["One"],
|
||||
array: [
|
||||
"workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.input.array.0::Array item",
|
||||
{
|
||||
name: "workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.input.array.1.name::Name",
|
||||
value: "workflows.defaultTemplates.sample.workflows.workflow.inputExamples.example.input.array.1.value::Value",
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(template.workflows[0].name).toBe("Workflow");
|
||||
});
|
||||
|
||||
it("leaves unkeyed custom templates unchanged apart from cloning", () => {
|
||||
const custom: WorkflowsTemplateDto = {
|
||||
title: "Custom",
|
||||
workflows: [
|
||||
{
|
||||
name: "Custom workflow",
|
||||
description: "Custom description",
|
||||
blocks: [{ id: "block", type: "log", description: "Custom block" }],
|
||||
toBlocks: [],
|
||||
inputExamples: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(localizeWorkflowTemplate(custom, t)).toEqual(custom);
|
||||
});
|
||||
|
||||
it("keeps built-in workflow template metadata on locale-backed keys", () => {
|
||||
const en = readTranslations("en");
|
||||
const de = readTranslations("de");
|
||||
const keys = DefaultWorkflowTemplates.flatMap(collectTemplateMetadataKeys);
|
||||
|
||||
expect(keys).toContain("workflows.defaultTemplates.emails.workflows.mailjetEmail.blocks.email.input.body");
|
||||
expect(keys).not.toEqual(expect.arrayContaining(["It works!", "Hello from Mailjet!", "User typed bye"]));
|
||||
for (const key of keys) {
|
||||
expect(key.startsWith("workflows.defaultTemplates."), key).toBe(true);
|
||||
expect(getTranslation(en, key), key).toBeTypeOf("string");
|
||||
expect(getTranslation(de, key), key).toBeTypeOf("string");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const LOCALIZABLE_TEMPLATE_INPUT_KEYS = new Set(["body", "message", "placeholder", "subject"]);
|
||||
|
||||
function collectTemplateMetadataKeys(template: WorkflowsTemplateDto) {
|
||||
return [
|
||||
template.title,
|
||||
...template.workflows.flatMap((workflow) => [
|
||||
workflow.name,
|
||||
workflow.description,
|
||||
...workflow.blocks.flatMap((block) => [
|
||||
block.description,
|
||||
...Object.entries(block.input ?? {})
|
||||
.filter(([key, value]) => LOCALIZABLE_TEMPLATE_INPUT_KEYS.has(key) && typeof value === "string" && !value.includes("{{"))
|
||||
.map(([, value]) => value as string),
|
||||
]),
|
||||
...workflow.inputExamples.flatMap((inputExample) => [inputExample.title, ...collectTemplateInputExampleInputKeys(template, workflow, inputExample)]),
|
||||
]),
|
||||
].filter((value): value is string => typeof value === "string" && value.length > 0);
|
||||
}
|
||||
|
||||
function collectTemplateInputExampleInputKeys(template: WorkflowsTemplateDto, workflow: WorkflowsTemplateDto["workflows"][number], inputExample: WorkflowsTemplateDto["workflows"][number]["inputExamples"][number]) {
|
||||
if (!template.key || !workflow.key || !inputExample.key) return [];
|
||||
const prefix = `workflows.defaultTemplates.${template.key}.workflows.${workflow.key}.inputExamples.${inputExample.key}.input`;
|
||||
return collectTemplateInputExampleInputKeyPaths(inputExample.input).map((path) => `${prefix}.${path}`);
|
||||
}
|
||||
|
||||
function collectTemplateInputExampleInputKeyPaths(value: unknown, path: string[] = []): string[] {
|
||||
if (typeof value === "string") return isLocalizableTemplateInputExamplePath(path) ? [path.join(".")] : [];
|
||||
if (Array.isArray(value)) return value.flatMap((item, index) => collectTemplateInputExampleInputKeyPaths(item, [...path, String(index)]));
|
||||
if (value && typeof value === "object") {
|
||||
return Object.entries(value).flatMap(([key, entryValue]) => collectTemplateInputExampleInputKeyPaths(entryValue, [...path, key]));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function isLocalizableTemplateInputExamplePath(path: readonly string[]): boolean {
|
||||
const last = path.at(-1);
|
||||
if (!last) return false;
|
||||
if (LOCALIZABLE_TEMPLATE_INPUT_KEYS.has(last)) return true;
|
||||
if (path[0] === "array" && path.length === 3 && (last === "name" || last === "value")) return true;
|
||||
return /^\d+$/u.test(last) && path.length === 2 && path[0] === "array";
|
||||
}
|
||||
|
||||
function readTranslations(locale: "en" | "de") {
|
||||
return JSON.parse(fs.readFileSync(path.join(repoRoot, `apps/web/public/locales/${locale}/translations.json`), "utf8")) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function getTranslation(translations: Record<string, unknown>, key: string) {
|
||||
return key.split(".").reduce<unknown>((value, segment) => {
|
||||
if (value && typeof value === "object" && segment in value) {
|
||||
return (value as Record<string, unknown>)[segment];
|
||||
}
|
||||
return undefined;
|
||||
}, translations);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import type { TFunction } from "i18next";
|
||||
import type { WorkflowTemplateDto, WorkflowsTemplateDto } from "../dtos/WorkflowsTemplateDto";
|
||||
|
||||
type TemplateBlock = WorkflowTemplateDto["blocks"][number];
|
||||
type TemplateInputExample = WorkflowTemplateDto["inputExamples"][number];
|
||||
|
||||
const LOCALIZABLE_TEMPLATE_INPUT_KEYS = new Set(["body", "message", "placeholder", "subject"]);
|
||||
|
||||
function translate(t: TFunction, key: string | undefined, fallback: string | undefined) {
|
||||
if (!key || !fallback) {
|
||||
return fallback ?? "";
|
||||
}
|
||||
return t(key, { defaultValue: fallback });
|
||||
}
|
||||
|
||||
function templatePrefix(template: WorkflowsTemplateDto) {
|
||||
return template.key ? `workflows.defaultTemplates.${template.key}` : undefined;
|
||||
}
|
||||
|
||||
function workflowPrefix(template: WorkflowsTemplateDto, workflow: WorkflowTemplateDto) {
|
||||
const prefix = templatePrefix(template);
|
||||
return prefix && workflow.key ? `${prefix}.workflows.${workflow.key}` : undefined;
|
||||
}
|
||||
|
||||
export function getTemplateTitle(template: WorkflowsTemplateDto, t: TFunction) {
|
||||
return translate(t, templatePrefix(template) ? `${templatePrefix(template)}.title` : undefined, template.title);
|
||||
}
|
||||
|
||||
export function getTemplateWorkflowName(template: WorkflowsTemplateDto, workflow: WorkflowTemplateDto, t: TFunction) {
|
||||
return translate(t, workflowPrefix(template, workflow) ? `${workflowPrefix(template, workflow)}.name` : undefined, workflow.name);
|
||||
}
|
||||
|
||||
export function getTemplateWorkflowDescription(template: WorkflowsTemplateDto, workflow: WorkflowTemplateDto, t: TFunction) {
|
||||
return translate(t, workflowPrefix(template, workflow) ? `${workflowPrefix(template, workflow)}.description` : undefined, workflow.description);
|
||||
}
|
||||
|
||||
export function getTemplateBlockDescription(template: WorkflowsTemplateDto, workflow: WorkflowTemplateDto, block: TemplateBlock, t: TFunction) {
|
||||
return translate(t, workflowPrefix(template, workflow) ? `${workflowPrefix(template, workflow)}.blocks.${block.id}.description` : undefined, block.description);
|
||||
}
|
||||
|
||||
export function localizeTemplateBlockInput(
|
||||
template: WorkflowsTemplateDto,
|
||||
workflow: WorkflowTemplateDto,
|
||||
block: TemplateBlock,
|
||||
t: TFunction
|
||||
): TemplateBlock["input"] {
|
||||
const prefix = workflowPrefix(template, workflow);
|
||||
if (!prefix || !block.input) {
|
||||
return block.input;
|
||||
}
|
||||
|
||||
let changed = false;
|
||||
const input = Object.fromEntries(
|
||||
Object.entries(block.input).map(([key, value]) => {
|
||||
if (!LOCALIZABLE_TEMPLATE_INPUT_KEYS.has(key) || typeof value !== "string") {
|
||||
return [key, value];
|
||||
}
|
||||
changed = true;
|
||||
return [key, translate(t, `${prefix}.blocks.${block.id}.input.${key}`, value)];
|
||||
})
|
||||
);
|
||||
|
||||
return changed ? input : block.input;
|
||||
}
|
||||
|
||||
export function getTemplateInputExampleTitle(
|
||||
template: WorkflowsTemplateDto,
|
||||
workflow: WorkflowTemplateDto,
|
||||
inputExample: TemplateInputExample,
|
||||
t: TFunction
|
||||
) {
|
||||
return translate(
|
||||
t,
|
||||
workflowPrefix(template, workflow) && inputExample.key ? `${workflowPrefix(template, workflow)}.inputExamples.${inputExample.key}.title` : undefined,
|
||||
inputExample.title
|
||||
);
|
||||
}
|
||||
|
||||
export function localizeTemplateInputExampleInput(
|
||||
template: WorkflowsTemplateDto,
|
||||
workflow: WorkflowTemplateDto,
|
||||
inputExample: TemplateInputExample,
|
||||
t: TFunction
|
||||
): TemplateInputExample["input"] {
|
||||
const prefix = workflowPrefix(template, workflow);
|
||||
if (!prefix || !inputExample.key) {
|
||||
return inputExample.input;
|
||||
}
|
||||
return localizeTemplateInputExampleValue(inputExample.input, `${prefix}.inputExamples.${inputExample.key}.input`, t) as TemplateInputExample["input"];
|
||||
}
|
||||
|
||||
export function localizeWorkflowTemplate(template: WorkflowsTemplateDto, t: TFunction): WorkflowsTemplateDto {
|
||||
return {
|
||||
...template,
|
||||
title: getTemplateTitle(template, t),
|
||||
workflows: template.workflows.map((workflow) => ({
|
||||
...workflow,
|
||||
name: getTemplateWorkflowName(template, workflow, t),
|
||||
description: getTemplateWorkflowDescription(template, workflow, t),
|
||||
blocks: workflow.blocks.map((block) => {
|
||||
const localizedInput = localizeTemplateBlockInput(template, workflow, block, t);
|
||||
return localizedInput
|
||||
? {
|
||||
...block,
|
||||
description: getTemplateBlockDescription(template, workflow, block, t),
|
||||
input: localizedInput,
|
||||
}
|
||||
: {
|
||||
...block,
|
||||
description: getTemplateBlockDescription(template, workflow, block, t),
|
||||
};
|
||||
}),
|
||||
inputExamples: workflow.inputExamples.map((inputExample) => ({
|
||||
...inputExample,
|
||||
title: getTemplateInputExampleTitle(template, workflow, inputExample, t),
|
||||
input: localizeTemplateInputExampleInput(template, workflow, inputExample, t),
|
||||
})),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
function localizeTemplateInputExampleValue(value: unknown, key: string, t: TFunction, path: readonly string[] = []): unknown {
|
||||
if (typeof value === "string") {
|
||||
return isLocalizableTemplateInputExamplePath(path) ? translate(t, key, value) : value;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((item, index) => localizeTemplateInputExampleValue(item, `${key}.${index}`, t, [...path, String(index)]));
|
||||
}
|
||||
if (value && typeof value === "object") {
|
||||
return Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [entryKey, localizeTemplateInputExampleValue(entryValue, `${key}.${entryKey}`, t, [...path, entryKey])]));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function isLocalizableTemplateInputExamplePath(path: readonly string[]): boolean {
|
||||
const last = path.at(-1);
|
||||
if (!last) return false;
|
||||
if (LOCALIZABLE_TEMPLATE_INPUT_KEYS.has(last)) return true;
|
||||
if (path[0] === "array" && path.length === 3 && (last === "name" || last === "value")) return true;
|
||||
return /^\d+$/u.test(last) && path.length === 2 && path[0] === "array";
|
||||
}
|
||||
Reference in new issue
Block a user