3675f264f1
## Context Logic functions can declare workflow inputs typed as records or arrays of records (e.g. the People Data Labs enrichment functions), but the workflow builder rendered those as a plain text input with a variable picker, which is not usable. ## What this does - Adds an `objectUniversalIdentifier` link on input schema properties, so a record-typed input is tied to a workspace object. - The SDK build infers it from a `TwentyRecord<'objectUniversalIdentifier'>` marker type in the handler signature, reading the object's universal identifier straight from the source; explicit input schemas can still set the field directly. - The workflow builder renders these inputs as a single record picker or a record multi-select with the variable picker on the right. Selected records are stored as record ids; `TwentyRecord<UID>` is a branded `string`, so the handler signature reflects that it receives ids (a bound variable resolves to whatever the referenced step produced). - The multi-select collapses overflowing chips into a `+N` badge (reusing `ExpandableList`) and its variable picker offers both record objects and fields. - Updates the People Data Labs enrichment inputs as the reference implementation. <img width="802" height="824" alt="CleanShot 2026-06-12 at 16 54 10@2x" src="https://github.com/user-attachments/assets/a0896d74-0aab-49bd-a173-14c578a2e533" /> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21494?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
79 lines
2.1 KiB
TypeScript
79 lines
2.1 KiB
TypeScript
import { type InputJsonSchema } from '@/logic-function/input-json-schema.type';
|
|
import {
|
|
type InputSchema,
|
|
type InputSchemaProperty,
|
|
} from '@/workflow/types/InputSchema';
|
|
import { isNonEmptyString } from '@sniptt/guards';
|
|
|
|
const convertProperty = (jsonSchema: InputJsonSchema): InputSchemaProperty => {
|
|
const property: InputSchemaProperty = { type: 'unknown' };
|
|
|
|
switch (jsonSchema.type) {
|
|
case 'string':
|
|
property.type = 'string';
|
|
break;
|
|
case 'number':
|
|
case 'integer':
|
|
property.type = 'number';
|
|
break;
|
|
case 'boolean':
|
|
property.type = 'boolean';
|
|
break;
|
|
case 'array':
|
|
property.type = 'array';
|
|
if (jsonSchema.items) {
|
|
property.items = convertProperty(jsonSchema.items);
|
|
}
|
|
break;
|
|
case 'object':
|
|
property.type = 'object';
|
|
if (jsonSchema.properties) {
|
|
property.properties = Object.fromEntries(
|
|
Object.entries(jsonSchema.properties).map(([key, value]) => [
|
|
key,
|
|
convertProperty(value),
|
|
]),
|
|
);
|
|
}
|
|
break;
|
|
case 'record':
|
|
property.type = 'record';
|
|
break;
|
|
case 'records':
|
|
property.type = 'records';
|
|
break;
|
|
case 'null':
|
|
default:
|
|
property.type = 'unknown';
|
|
}
|
|
|
|
if (Array.isArray(jsonSchema.enum)) {
|
|
property.enum = jsonSchema.enum.filter(
|
|
(value): value is string => typeof value === 'string',
|
|
);
|
|
}
|
|
|
|
if (jsonSchema.multiline === true) {
|
|
property.multiline = true;
|
|
}
|
|
|
|
if (isNonEmptyString(jsonSchema.label)) {
|
|
property.label = jsonSchema.label;
|
|
}
|
|
|
|
if (isNonEmptyString(jsonSchema.objectUniversalIdentifier)) {
|
|
property.objectUniversalIdentifier = jsonSchema.objectUniversalIdentifier;
|
|
}
|
|
|
|
return property;
|
|
};
|
|
|
|
// Wraps in a single-element array because Twenty's InputSchema represents
|
|
// the parameter list of a function -- logic functions take a single params
|
|
// object, hence a one-element array containing it.
|
|
export const jsonSchemaToInputSchema = (
|
|
jsonSchema: InputJsonSchema,
|
|
): InputSchema => {
|
|
return [convertProperty(jsonSchema)];
|
|
};
|