[WIP] workflow builder
This commit is contained in:
@@ -18,11 +18,7 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
|
||||
const isEditing = !!pack;
|
||||
|
||||
// Store initial/database state for reset
|
||||
const initialConfSchema = pack?.conf_schema || {
|
||||
type: "object",
|
||||
properties: {},
|
||||
required: [],
|
||||
};
|
||||
const initialConfSchema = pack?.conf_schema || {};
|
||||
const initialConfig = pack?.config || {};
|
||||
|
||||
// Form state
|
||||
@@ -47,15 +43,17 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
|
||||
const createPack = useCreatePack();
|
||||
const updatePack = useUpdatePack();
|
||||
|
||||
// Check if schema has properties
|
||||
// Check if schema has properties (flat format: each key is a parameter name)
|
||||
const hasSchemaProperties =
|
||||
confSchema?.properties && Object.keys(confSchema.properties).length > 0;
|
||||
confSchema &&
|
||||
typeof confSchema === "object" &&
|
||||
Object.keys(confSchema).length > 0;
|
||||
|
||||
// Sync config values when schema changes (for ad-hoc packs only)
|
||||
useEffect(() => {
|
||||
if (!isStandard && hasSchemaProperties) {
|
||||
// Get current schema property names
|
||||
const schemaKeys = Object.keys(confSchema.properties || {});
|
||||
// Get current schema property names (flat format: keys are parameter names)
|
||||
const schemaKeys = Object.keys(confSchema);
|
||||
|
||||
// Create new config with only keys that exist in schema
|
||||
const syncedConfig: Record<string, any> = {};
|
||||
@@ -65,7 +63,7 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
|
||||
syncedConfig[key] = configValues[key];
|
||||
} else {
|
||||
// Use default from schema if available
|
||||
const defaultValue = confSchema.properties[key]?.default;
|
||||
const defaultValue = confSchema[key]?.default;
|
||||
if (defaultValue !== undefined) {
|
||||
syncedConfig[key] = defaultValue;
|
||||
}
|
||||
@@ -99,10 +97,14 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
|
||||
newErrors.version = "Version is required";
|
||||
}
|
||||
|
||||
// Validate conf_schema
|
||||
if (confSchema && confSchema.type !== "object") {
|
||||
newErrors.confSchema =
|
||||
'Config schema must have type "object" at root level';
|
||||
// Validate conf_schema (flat format: each value should be an object defining a parameter)
|
||||
if (confSchema && typeof confSchema === "object") {
|
||||
for (const [key, val] of Object.entries(confSchema)) {
|
||||
if (!val || typeof val !== "object" || Array.isArray(val)) {
|
||||
newErrors.confSchema = `Invalid parameter definition for "${key}" — each parameter must be an object`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate meta JSON
|
||||
@@ -126,7 +128,7 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
|
||||
}
|
||||
|
||||
const parsedConfSchema =
|
||||
Object.keys(confSchema.properties || {}).length > 0 ? confSchema : {};
|
||||
Object.keys(confSchema || {}).length > 0 ? confSchema : {};
|
||||
const parsedMeta = meta.trim() ? JSON.parse(meta) : {};
|
||||
const tagsList = tags
|
||||
.split(",")
|
||||
@@ -201,78 +203,75 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
|
||||
};
|
||||
|
||||
const insertSchemaExample = (type: "api" | "database" | "webhook") => {
|
||||
let example;
|
||||
let example: Record<string, any>;
|
||||
switch (type) {
|
||||
case "api":
|
||||
example = {
|
||||
type: "object",
|
||||
properties: {
|
||||
api_key: {
|
||||
type: "string",
|
||||
description: "API authentication key",
|
||||
},
|
||||
endpoint: {
|
||||
type: "string",
|
||||
description: "API endpoint URL",
|
||||
default: "https://api.example.com",
|
||||
},
|
||||
api_key: {
|
||||
type: "string",
|
||||
description: "API authentication key",
|
||||
required: true,
|
||||
secret: true,
|
||||
},
|
||||
endpoint: {
|
||||
type: "string",
|
||||
description: "API endpoint URL",
|
||||
default: "https://api.example.com",
|
||||
},
|
||||
required: ["api_key"],
|
||||
};
|
||||
break;
|
||||
|
||||
case "database":
|
||||
example = {
|
||||
type: "object",
|
||||
properties: {
|
||||
host: {
|
||||
type: "string",
|
||||
description: "Database host",
|
||||
default: "localhost",
|
||||
},
|
||||
port: {
|
||||
type: "integer",
|
||||
description: "Database port",
|
||||
default: 5432,
|
||||
},
|
||||
database: {
|
||||
type: "string",
|
||||
description: "Database name",
|
||||
},
|
||||
username: {
|
||||
type: "string",
|
||||
description: "Database username",
|
||||
},
|
||||
password: {
|
||||
type: "string",
|
||||
description: "Database password",
|
||||
},
|
||||
host: {
|
||||
type: "string",
|
||||
description: "Database host",
|
||||
default: "localhost",
|
||||
required: true,
|
||||
},
|
||||
port: {
|
||||
type: "integer",
|
||||
description: "Database port",
|
||||
default: 5432,
|
||||
},
|
||||
database: {
|
||||
type: "string",
|
||||
description: "Database name",
|
||||
required: true,
|
||||
},
|
||||
username: {
|
||||
type: "string",
|
||||
description: "Database username",
|
||||
required: true,
|
||||
},
|
||||
password: {
|
||||
type: "string",
|
||||
description: "Database password",
|
||||
required: true,
|
||||
secret: true,
|
||||
},
|
||||
required: ["host", "database", "username", "password"],
|
||||
};
|
||||
break;
|
||||
|
||||
case "webhook":
|
||||
example = {
|
||||
type: "object",
|
||||
properties: {
|
||||
webhook_url: {
|
||||
type: "string",
|
||||
description: "Webhook destination URL",
|
||||
},
|
||||
auth_token: {
|
||||
type: "string",
|
||||
description: "Authentication token",
|
||||
},
|
||||
timeout: {
|
||||
type: "integer",
|
||||
description: "Request timeout in seconds",
|
||||
minimum: 1,
|
||||
maximum: 300,
|
||||
default: 30,
|
||||
},
|
||||
webhook_url: {
|
||||
type: "string",
|
||||
description: "Webhook destination URL",
|
||||
required: true,
|
||||
},
|
||||
auth_token: {
|
||||
type: "string",
|
||||
description: "Authentication token",
|
||||
secret: true,
|
||||
},
|
||||
timeout: {
|
||||
type: "integer",
|
||||
description: "Request timeout in seconds",
|
||||
minimum: 1,
|
||||
maximum: 300,
|
||||
default: 30,
|
||||
},
|
||||
required: ["webhook_url"],
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -282,15 +281,11 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
|
||||
|
||||
// Immediately sync config values with schema defaults
|
||||
const syncedConfig: Record<string, any> = {};
|
||||
if (example.properties) {
|
||||
Object.entries(example.properties).forEach(
|
||||
([key, propDef]: [string, any]) => {
|
||||
if (propDef.default !== undefined) {
|
||||
syncedConfig[key] = propDef.default;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
Object.entries(example).forEach(([key, propDef]: [string, any]) => {
|
||||
if (propDef.default !== undefined) {
|
||||
syncedConfig[key] = propDef.default;
|
||||
}
|
||||
});
|
||||
setConfigValues(syncedConfig);
|
||||
};
|
||||
|
||||
@@ -578,7 +573,7 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
|
||||
</p>
|
||||
</div>
|
||||
<ParamSchemaForm
|
||||
schema={confSchema.properties}
|
||||
schema={confSchema}
|
||||
values={configValues}
|
||||
onChange={setConfigValues}
|
||||
errors={errors}
|
||||
|
||||
@@ -123,6 +123,10 @@ export default function RuleForm({ rule, onSuccess, onCancel }: RuleFormProps) {
|
||||
newErrors.label = "Label is required";
|
||||
}
|
||||
|
||||
if (!description.trim()) {
|
||||
newErrors.description = "Description is required";
|
||||
}
|
||||
|
||||
if (!packId) {
|
||||
newErrors.pack = "Pack is required";
|
||||
}
|
||||
@@ -347,7 +351,7 @@ export default function RuleForm({ rule, onSuccess, onCancel }: RuleFormProps) {
|
||||
htmlFor="description"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Description
|
||||
Description <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="description"
|
||||
@@ -355,8 +359,13 @@ export default function RuleForm({ rule, onSuccess, onCancel }: RuleFormProps) {
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
placeholder="Describe what this rule does..."
|
||||
rows={3}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
className={`w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 ${
|
||||
errors.description ? "border-red-500" : "border-gray-300"
|
||||
}`}
|
||||
/>
|
||||
{errors.description && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.description}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Enabled Toggle */}
|
||||
|
||||
@@ -30,16 +30,8 @@ export default function TriggerForm({
|
||||
const [description, setDescription] = useState("");
|
||||
const [webhookEnabled, setWebhookEnabled] = useState(false);
|
||||
const [enabled, setEnabled] = useState(true);
|
||||
const [paramSchema, setParamSchema] = useState<Record<string, any>>({
|
||||
type: "object",
|
||||
properties: {},
|
||||
required: [],
|
||||
});
|
||||
const [outSchema, setOutSchema] = useState<Record<string, any>>({
|
||||
type: "object",
|
||||
properties: {},
|
||||
required: [],
|
||||
});
|
||||
const [paramSchema, setParamSchema] = useState<Record<string, any>>({});
|
||||
const [outSchema, setOutSchema] = useState<Record<string, any>>({});
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
|
||||
// Fetch packs
|
||||
@@ -58,20 +50,8 @@ export default function TriggerForm({
|
||||
setDescription(initialData.description || "");
|
||||
setWebhookEnabled(initialData.webhook_enabled || false);
|
||||
setEnabled(initialData.enabled ?? true);
|
||||
setParamSchema(
|
||||
initialData.param_schema || {
|
||||
type: "object",
|
||||
properties: {},
|
||||
required: [],
|
||||
},
|
||||
);
|
||||
setOutSchema(
|
||||
initialData.out_schema || {
|
||||
type: "object",
|
||||
properties: {},
|
||||
required: [],
|
||||
},
|
||||
);
|
||||
setParamSchema(initialData.param_schema || {});
|
||||
setOutSchema(initialData.out_schema || {});
|
||||
|
||||
if (isEditing) {
|
||||
// Find pack by pack_ref
|
||||
@@ -129,13 +109,8 @@ export default function TriggerForm({
|
||||
description: description.trim() || undefined,
|
||||
enabled,
|
||||
param_schema:
|
||||
Object.keys(paramSchema.properties || {}).length > 0
|
||||
? paramSchema
|
||||
: undefined,
|
||||
out_schema:
|
||||
Object.keys(outSchema.properties || {}).length > 0
|
||||
? outSchema
|
||||
: undefined,
|
||||
Object.keys(paramSchema).length > 0 ? paramSchema : undefined,
|
||||
out_schema: Object.keys(outSchema).length > 0 ? outSchema : undefined,
|
||||
};
|
||||
|
||||
if (isEditing && initialData?.ref) {
|
||||
|
||||
Reference in New Issue
Block a user