Components:beforeCreate helpers - bettyblocks/cli GitHub Wiki

beforeCreate helpers provide convenient functions and Components that make it easier to configure your Prefabs with the beforeCreate pop-up. For a basic explanation of beforeCreate check this page.

The following props are available inside the beforeCreate component:

Contents

prefab

An object which contains the original prefab.

save

A function that accepts a (mutated) prefab as an argument. When called the beforeCreate pop-up will close and the prefab will be added to the canvas.

close

A function which closes the pop-up and prevents the prefab from being dropped on the canvas when called.

cloneStructure

The B.cloneStructure allows you to clone the root structure of another prefab. You can then modify this clone and re-insert it into your prefab like so:

const prefabName = 'Image`; // an ImagePrefab
urls.forEach(url => {

  const imageStructure = cloneStructure(prefabName);

  setOption(imageStructure, 'url', (option) => ({
      ...option,
      value: [url]
    })
  );

  prefab.structure.push(imageStructure);
});

prepareAction

prepareAction will create a new action action based on a model and it's properties.

const result = await prepareAction(
            componentId,        // the component you would like to bind the action to
            idProperty,         // the id property of the model the user has selected
            properties,         // all the properties that you would like to create actionInputs for.
            'update',           // the name of the template for the action that you would like to create.
            authProfile         // the authentication profile object for creating a login template (optional)
            permissions         // used to set the permission of the action. 'private' | 'public' | 'inherit':
                                  // -  when set to private, the action is set to private with the admin execute permission set to true.
                                  // -  public set the action to public which allows everyone to be able to execute it.
                                  // -  inherit will act as public or private depending if the page has a pageAuthenticationProfileId.
            pageAuthenticationProfileId // used to determine if action should be private or public.
          );

The type of result is:

export interface PreparedAction {
  action: {
    actionId: string;
  };
  variables: Record<string, [Property, ActionVariable]>; // for each propertyId, the property and the associated input variable
  relatedIdProperties: Record<string, string>; // for each propertyId, if the user selects relational properties, this contains the id properties of the related models.
  recordInputVariable: ActionVariable | null;
  resultVariable: ActionVariable;
}

Once you have a an action and input variables you can then create components based on this action. Here are the steps to do that:

  1. If you would like to associate a component with the action, for example a form set up the following action.
option description value
option ( 'ACTION_JS' , { label : 'Action' , value : '' }) stores the actionId action.actionId
  1. If you would like components that are connected to the property and the action variables that were created add this.
option description value
option ( 'ACTION_JS_PROPERTY' , { label : 'Property' , value : '' , }) stores the association between property and action variable. When you're component get's deleted, the backend can take care of deleting the associated action input variable for you actionVariable.id

setOption

setOption allows you to update an option.

setOption(structure, "modelId", (option) => ({
  ...option, // the original option as configured in the prefab
  value: modelId, // the new value for the option
  configuration: {
    // the new configuration for the option
    disabled: true,
  },
}));

If the option is not found, it will log to the browser console.

makeBettyInput

makeBettyInput(
  BettyPrefabs.AUTO_COMPLETE,
  model,
  property,
  variable,
  result.relatedIdProperties,
  result.relatedModelIds
);

This will configure a form input that is bound to a form. You may use your own prefabs as well, or you can use names from the default set BettyPrefabs.*.

If you do provide your own prefab make sure that at minimum it has the component options, documented under prepareAction().

makeBettyUpdateInput

makeBettyUpdateInput(
  BettyPrefabs.AUTO_COMPLETE,
  model,
  property,
  variable,
  result.relatedIdProperties,
  result.relatedModelIds
);

If you want to have a form input with a prefilled value, you can use this helper.

The parameters makeBettyInput and makeBettyUpdateInput needs are:

  1. The name of the prefab
  2. The model of the input
  3. The property of the input
  4. The action variable the input needs to fill in

In case of relational properties like a belongs-to, has-many or has-and-belongs-to-many: 5. The ids of the properties of a related model 6. The ids of the related models

addActionVariable

Adds a new action input variable to an existing action

addActionVariable(
  actionId, // id of an existing action
  name, // name of the new variable
  kind, // kind of the variable on of "INTEGER", "STRING" or "ARRAY"
  options // see below
);

ActionVariables have different options depending on the action variables. By default they all support a value option like so: { value: "some-value" }.

When using the ARRAY kind remember to set the kind of array in the option like so: { kind: "INTEGER" }. To be clear:

addActionVariable('001', 'my integer array', kind: 'ARRAY', options: { value: '', kind: 'INTEGER' });

constants

BettyPrefabs includes: AUTO_COMPLETE ,BOOLEAN ,DATE ,DATE_TIME ,DECIMAL ,EMAIL_ADDRESS ,HIDDEN ,IBAN ,INTEGER ,LIST ,PASSWORD ,PHONE_NUMBER ,PRICE ,RADIO ,SELECT ,STRING ,SUBMIT_BUTTON ,TEXT ,TIME ,UPDATE_FORM ,URL

PropertyKinds includes: AUTO_INCREMENT, BELONGS_TO, BOOLEAN, BOOLEAN_EXPRESSION, DATE, DATE_TIME, DECIMAL, EMAIL_ADDRESS, FILE, FLOAT, HAS_AND_BELONGS_TO_MANY, HAS_MANY, HAS_ONE, IBAN, IMAGE, INTEGER, LIST, PASSWORD, PDF, PHONE_NUMBER, PRICE, SERIAL, STRING, SUM, TEXT, TIME, URL

components

A collection of components we made available for you to use. The components help to keep to the Betty Blocks style guide and give read access to metadata. Here is a list in alphabetical order containing every component we expose, their API, and an example on how to use them:

Box

Box is a powerful component of the Grommet framework. Use it to easily set up layouts.

Check Grommet's documentation to see how it can be used and which props are available: https://v2.grommet.io/box

Button

Button is a component of the Grommet framework.

Check Grommet's documentation to see how it can be used and which props are available: https://v2.grommet.io/button

We recommend only the usage of the following props:

Props type default description
color "blue" | "orange" | "purple" | "turquoise" "turquoise" Color of the button. Also applies to hover, focus and active styling
disabled boolean false Disable all interactions with component
label string "" Button label
onClick () => void Function executed when the button is clicked
plain boolean false Property to create an outline button
primary boolean false Property to create a primary button
size "small" | "medium" | "large" "medium" Size of the button

Examples:

Primary button:

<Button label="Button text" onClick={() => {}} primary />

Screenshot:

Primary button

Secondary button:

<Button label="Button text" onClick={() => {}} />

Screenshot:

Secondary button

Tertiary button:

<Button label="Button text" onClick={() => {}} plain />

Screenshot:

Tertiary button

ButtonGroup

A button group with the functionality of a radio button group. Use it together with ButtonGroupButton.

Props type default description
color "purple" | "turquoise" | "blue" | "orange" "turquoise" Color of the button group. Also applies to hover, focus and active styling
fill boolean false Fill the component width to its parent.
onChange* (event: React.ChangeEvent<HTMLInputElement>) => void Function which executes when a button is selected in the button group
value string Value of the button group button which should be shown as active
size "small" | "medium" | "large" "medium" Size of the button group

Example:

See ButtonGroupButton for a usage example.

Screenshot:

See ButtonGroupButton for a screenshot.

ButtonGroupButton

A button group button to use inside a ButtonGroup.

Props type default description
disabled boolean false Disable all interactions with component
label string Label of the button group button
name* string Should be the same string as other button group buttons in the current button group to make the radio button functionality work
value string Unique string which is available in ButtonGroup's callback function's argument as event.target.value

Example:

({ components: { ButtonGroup, ButtonGroupButton } }) => {
  const [state, setState] = React.useState("a");

  return (
    <ButtonGroup
      onChange={({ target: { value } }) => {
        setState(value);
      }}
      value={state}
    >
      <ButtonGroupButton label="Option a" value="a" name="options" />
      <ButtonGroupButton label="Option b" value="b" name="options" />
      <ButtonGroupButton label="Option c" value="c" name="options" />
    </ButtonGroup>
  );
};

Screenshot:

Button group button

Content

A layout helper component that applies spacing to comply with the Betty Blocks style guide.

Example usage:

({ components: { Content } }) => {
  return <Content>Your content here...</Content>;
};

DeleteButton

DeleteButton is a component from the Grommet framework which we extended and changed styles to make it comply with the delete button in the Betty Blocks style guides.

Check Grommet's documentation to see how it can be used and which props are available: https://v2.grommet.io/button

We recommend only the usage of the following props:

Props type default description
disabled boolean false Disable all interactions with component
label string "" Button label
onClick () => void Function executed when the button is clicked
size "small" | "medium" | "large" "medium" Size of the button

Example:

<DeleteButton label="Button text" onClick={() => {}} />

Screenshot:

Delete button

NOTE: This is the hover state of the delete button. The normal state is the same as the secondary button.

DestructiveButton

DestructiveButton is a component from the Grommet framework which we extended and changed styles to make it comply with the destructive button in the Betty Blocks style guides.

Check Grommet's documentation to see how it can be used and which props are available: https://v2.grommet.io/button

We recommend only the usage of the following props:

Props type default description
disabled boolean false Disable all interactions with component
label string "" Button label
onClick () => void Function executed when the button is clicked
size "small" | "medium" | "large" "medium" Size of the button

Example:

<DestructiveButton label="Button text" onClick={() => {}} />

Screenshot:

Desctructive button

Field

A layout helper component to wrap around input components to add a label and spacing which both comply with the Betty Blocks style guide.

Props type default description
label string "" Field label
error ReactNode Error text
info ReactNode Help text

Example usage:

({ components : { Content, Field, ModelSelector } }) => {
  return (
    <Content>
      <Field label="Model">
        <ModelSelector ... />
      </Field>
    </Content>
  );
}

Screenshot:

Field helper

Footer

A layout helper component to get a pop-up footer that complies with the Betty Blocks style guide.

Props type default description
onClose () => void Function which is executed when the cancel button is clicked.
onSave () => void Function which is executed when the save button is clicked.

Example usage:

({ close, components: { Footer }, save }) => {
  return (
    <Footer
      onClose={close}
      onSave={() => {
        save(newPrefab);
      }}
    />
  );
};

Screenshot:

Footer helper

Header

A layout helper component to get a pop-up header which complies with the Betty Blocks style guide.

Props type default description
title string Title of the header.
subtitle string Subtitle of the header.
onClose () => void Function which is executed when the close icon is clicked.

Example usage:

({ close, components: { Header } }) => {
  return (
    <Header
      title="Configure component"
      subtitle="Message to support the title"
      onClose={close}
    />
  );
};

Screenshot:

Header helper

Heading

Heading is a component of the Grommet framework. Use it to display titles that comply with the Betty Blocks style guide.

Check Grommet's documentation to see how it can be used and which props are available: https://v2.grommet.io/heading

Most important props:

Props type default description
level "1" | "2" | "3" | "4" | "5" | "6" | "7" "1" Level for the html heading element to be used.
size "small" | "medium" | "large" | "xlarge" "medium" Size of the text

Example:

<Heading size="xlarge">Hello world</Heading>

Screenshot:

Heading helper

ModelSelector

Use it to select a model from the current application.

Props type default description
disabled boolean false Disable all interactions with component.
fill boolean false Fill the component width to its parent.
onChange (id: string) => void Function which executes when a model is selected in the model selector.
size "small" | "medium" | "large" "large" Size of the model selector.
value string A model id used to show the selected model in the model selector.

Example usage:

({ components: { ModelSelector } }) => {
  const [modelId, setModelId] = React.useState("");

  return (
    <ModelSelector
      onChange={(value) => {
        setModelId(value);
      }}
      value={modelId}
    />
  );
};

Screenshot:

ModelSelector helper

ComponentSelector

The componentSelector is a dropdown helper for selecting a component, the components that it shows can be configured. The componentSelector accepts the following arguments:

Props type default description
allowedComponents [stings] [] An array comprising component names which are allowed to be shown by the dropdown menu.
placeholder string "No component available" Text that is shown when no value is selected in the dropdown menu.
value string '' Id of the component to set as selected in the dropdown.
onChange (component: NormalizedComponent) => void Function which executes when a component is selected in the component selector.

Example usage:

<ComponentSelector
  onChange={(component) => {
    const foundModelId = Object.values(component.options).reduce(
      (acc, option) => (option.type === "MODEL" ? option.value : acc),
      null
    );
    setThisPageState((prevState) => ({
      ...prevState,
      modelId: foundModelId,
      component,
    }));
    setModelId(foundModelId);
  }}
  value={thisPageState.component ? thisPageState.component.id : ""}
  placeholder="No components available."
  allowedComponents={["DataTable", "DataList"]}
/>

Screenshot:

ComponentSelector helper

AuthenticationProfileSelector

Use it to select an authentication profile from the current application.

Props type default description
disabled boolean false Disable all interactions with component.
fill boolean false Fill the component width to its parent.
onChange (id: string) => void Function which executes when an authentication profile is selected in the authentication profile selector.
size "small" | "medium" | "large" "large" Size of the authentication profile selector.
value string An authentication profile id used to show the selected profile in the authentication profile selector.

Example usage:

({ components: { AuthenticationProfileSelector } }) => {
  const [authProfileId, setAuthProfileId] = React.useState("");

  return (
    <AuthenticationProfileSelector
      onChange={(id) => {
        setAuthProfileId(id);
      }}
      value={authProfileId}
    />
  );
};

PartialSelector

Use it to select a partial from the current application.

Props type default description
disabled boolean false Disable all interactions with component.
fill boolean false Fill the component width to its parent.
onChange (id: string) => void Function which executes when a partial is selected in the partial selector.
size "small" | "medium" | "large" "large" Size of the partial selector.
value string value is the id of the selected partial.
allowedTypes string[] allowedTypes is used to disable the selection of certain partials. Only the partials with a root component that matches with a type in the array will be selectable
preSelected string Allows the auto-generation of partials. When you fill in a name, it will look under prefabs -> partials and when the name matches one of the partial templates (this is case insensitive), an 'auto-generate' button will appear with which u can generate a new partial based on the template. When the user already has a partial with said name, It will automatically select it. When neither is the case, nothing will happen.

Example usage:

({ components: { PartialSelector } }) => {
  const [partialId, setPartialId] = React.useState("");
  return (
    <PartialSelector
      onChange={(id) => {
        setPartialId(id);
      }}
      value={partialId}
      allowedTypes={[
        "BODY_COMPONENT",
        "CONTAINER_COMPONENT",
        "CONTENT_COMPONENT",
      ]}
    />
  );
};

PropertySelector

Use it to select a property from the current application in the current data scope.

Props type default description
disabled boolean false Disable all interactions with component.
fill boolean false Fill the component width to its parent.
modelId string Model id of a model to add to the current scope of models to select properties from.
onChange (property: string | Property) => void Function which executes when a property is selected in one of the property
size "small" | "medium" | "large" "large" Size of the property selector.
value* string | Property A property id used to show the selected property in the property selector.

Example usage:

({ components: { PropertySelector } }) => {
  const [property, setProperty] = React.useState("");

  return (
    <PropertySelector
      onChange={(value) => {
        setProperty(value);
      }}
      value={property}
    />
  );
};

Screenshot:

PropertySelector helper

PropertiesSelector

Use it to select properties from the current page scope in the application.

Props type default description
modelId string Model id of a model to add to the current scope of models to select properties from.
onChange* (property: Property[]) => void Function which executes when a property is selected in one of the property selectors.
value* Property[] An array of properties used to show the selected properties in the properties selector.

Example usage:

({ components: { PropertiesSelector } }) => {
  const [properties, setProperties] = React.useState([]);

  return (
    <PropertiesSelector
      onChange={(value) => {
        setProperties(value);
      }}
      value={properties}
    />
  );
};

Screenshot:

PropertiesSelector helper

EndpointSelector

Use it to select an endpoint from the current application.

Props type default description
fill boolean false Fill the component width to its parent.
onChange (endpoint: string) => void Function which executes when a endpoint is selected in one of the endpoint selectors
value* string A endpoint id used to show the selected endpoint in the endpoint selector.

Example usage:

({ components: { EndpointSelector } }) => {
  const [endpoint, setEndpoint] = React.useState("");

  return (
    <EndpointSelector
      onChange={(endpoint) => {
        setProperty(endpoint);
      }}
      value={endpoint}
    />
  );
};

Screenshot:

EndpointSelector helper

Text

Text is a component of the Grommet framework. Use it to display text which complies with the Betty Blocks style guide.

Check Grommet's documentation to see how it can be used and which props are available: https://v2.grommet.io/text

Most important props:

Props type default description
size "xsmall" | "small" | "medium" | "large" "medium" Size of the text

Example:

<Text>Hello world</Text>

Screenshot:

Text helper

TextInput

TextInput is a component of the Grommet framework. Use it to display text inputs that comply with the Betty Blocks style guide.

Check Grommet's documentation to see how it can be used and which props are available: https://v2.grommet.io/textinput

Most important props:

Props type default description
disabled boolean false Disable all interactions with component
name string The name of the text input for when in a form
onChange (event: React.ChangeEvent<HTMLInputElement>) => void Function which executes when text is changed in the text input
placeholder string Text input placeholder text
size "medium" | "large" "medium" Size of the text input

Example:

({ components: { TextInput } }) => {
  const [state, setState] = React.useState("");

  return (
    <TextInput
      placeholder="Placeholder..."
      value={state}
      onChange={({ target: { value } }) => {
        setState(value);
      }}
    />
  );
};

Screenshot:

Text input helper

Focussed:

Text input helper active

TextArea

TextArea is a component of the Grommet framework. Use it to display text areas that comply with the Betty Blocks style guide.

Check Grommet's documentation to see how it can be used and which props are available: https://v2.grommet.io/textarea

Most important props:

Props type default description
disabled boolean false Disable all interactions with component
name string The name of the text input for when in a form
onChange (event: React.ChangeEvent<HTMLInputElement>) => void Function which executes when text is changed in the text input
placeholder string Text input placeholder text
size "medium" | "large" "medium" Size of the text input
resize boolean true Determines whether users can resize the textarea

Example:

({ components: { TextArea } }) => {
  const [state, setState] = React.useState("");

  return (
    <TextArea
      resize={false}
      onChange={({ target: { value } }) => {
        setState(value);
      }}
      value={state}
    />
  );
};

Screenshot:

Text area helper

Focussed:

Text input helper active

circlequestion

CircleQuestion is an Icon. Used to display an Icon in form of question mark. Can be used in combination with BBToltip component: If user hovers on it, the tooltip with the given text(data-tip) appears. Most important props:

Props type description
color string Optional, Give the icon the color
data-tip string The text that is displayed on icon hover
data-for string Id of bind BBToltip
a11yTitle string Optional, allignment of the title
size "small" | "medium" | "large" | "xlarge" | string Optional, Size of the icon

Example:

<CircleQuestion
  color="grey500"
  size="medium"
  data-tip="You can use this action input variable in the action itself."
  data-for="variable-tooltip"
/>

bbtooltip

BBTooltip is a component that displays a tooltip on hover, this can be used in combination with CircleQuestion, see above. Most important props:

Props type description
id string Id that corresponds to data-for of component that triggers tooltip show
place 'top' | 'right' | 'bottom' | 'left' Placement of tooltip
type 'dark' | 'success' | 'warning' | 'error' | 'info' | 'light' Tooltip styling theme
effect 'float' | 'solid' Behavior of tooltip

Example:

<CircleQuestion
  color="grey500"
  size="medium"
  data-tip="You can use this action input variable in the action itself."
  data-for="variable-tooltip"
/>
<BBTooltip
  id="variable-tooltip"
  place="top"
  type="dark"
  effect="solid"
/>

helpers

camelToSnakecase

This is a helper to convert camelCase to snake_case this is used for generating variables from the beforeCreate based on models. Will lowercase all characters and replace spaces with underscores. You can use this helper like this:

camelToSnakeCase("Test String")
// will return: "test_string"

useCurrentPageId

This helper will retrieve the UUID of the current page. If there is no UUID available it will return an empty string. You can use the helper like this:

beforeCreate: ({
  // extract other components if needed
  helpers: { useCurrentPageId }
}
const pageUuid = useCurrentPageId();

useModelQuery

Sometimes you need more information from a model than just the id (e.g. all the properties for a given model), this is where you can use useModelQuery. It works much in the same way as a useQuery from apollo does.

You can either use the onCompleted hook in the modelQuery to set your state.

useModelQuery({
  variables: { id: modelId },
  skip: !modelId,
  onCompleted: data => {
    // use data here
  },
});

Or you can use it more traditionally and destruct the objects from the query call.

const { data, loading, error } = useModelQuery({
  variables: { id: modelId },
  skip: !modelId,
});

createBlacklist

This helper receives an array of white list types and based on that excludes those types from a standard array of allowed types. So the result is an array of unsupported types.

This is the whole list of allowed types:

[ 'AUTO_INCREMENT',
  'BELONGS_TO',
  'BOOLEAN',
  'BOOLEAN_EXPRESSION',
  'COUNT',
  'DATE',
  'DATE_EXPRESSION',
  'DATE_TIME',
  'DATE_TIME_EXPRESSION',
  'DECIMAL',
  'DECIMAL_EXPRESSION',
  'EMAIL',
  'EMAIL_ADDRESS',
  'ENUM',
  'FILE',
  'FLOAT',
  'GOOGLE_DOCUMENT',
  'HAS_AND_BELONGS_TO_MANY',
  'HAS_MANY',
  'HAS_ONE',
  'IBAN',
  'IMAGE',
  'INTEGER',
  'INTEGER_EXPRESSION',
  'LIST',
  'LOGIN_TOKEN',
  'MINUTES',
  'MINUTES_EXPRESSION',
  'MULTI_FILE',
  'MULTI_IMAGE',
  'PASSWORD',
  'PDF',
  'PERIODIC_COUNT',
  'PHONE_NUMBER',
  'PRICE',
  'PRICE_EXPRESSION',
  'RICH_TEXT',
  'SERIAL',
  'SIGNED_PDF',
  'STRING',
  'STRING_EXPRESSION',
  'SUM',
  'TEXT',
  'TEXT_EXPRESSION',
  'TIME',
  'URL',
  'ZIPCODE',
}

Example of usage:

const unsupportedKinds = createBlacklist(['TEXT', 'URL', 'IBAN', 'STRING']);

useModelIdSelector

This helper searches through the parent component's tree for the closest component that uses a model, and returns its id. Helpers makes usage of global state. Does not require any input arguments. In material-ui-component-set this helper can be used like that:

const modelId = useModelIdSelector();

useActionIdSelector

When you want to retrieve id of the action that is used in the upper component tree, you can use this selector helper. Does not require any input arguments. In material-ui-component-set this helper can be used like that:

const actionId = useActionIdSelector();

usePrefabSelector

That helper uses the value of the global state. It checks the components' tree and returns the object with the name and id of the closest form where the component was dragged to if such was found.

this function:

export const usePrefabSelector = (): { name: string; id: string } => {
  return useSelector((state: State): { name: string; id: string } | null => {
    const { components } = state.page;
    const formId = state.page.beforeCreate.targetId;
    const { prefabName: name, id } = components[formId];
    return { name, id };
  });
};

In material-ui-component-set this helper can be used like that:

const selectedPrefab = usePrefabSelector();

addModelAndProperties

Creates a new model with the given properties

addModelAndProperties(
  modelName, // name op the new model, **has to be unique** (string)
  properties // object array containing label and kind
);

modelName has to be unique otherwise you will encounter crashes

The property kind can be any known type of property, to see a full list click here

addModelAndProperties('Customer', [
  {
    label: 'name',
    kind: 'STRING',
  },
  {
    label: 'dateOfBirth',
    kind: 'DATE',
  },
  {
    label: 'age',
    kind: 'INTEGER',
  },
]);

addSchemaModel

Creates a new schema model with the given name and json object

addSchemaModel(
   name, // name of the schema model (string)
   jsonSchema // Json object of the schema
)

Name has to be unique otherwise you will encounter crashes

The json schema has to follow a specific structure.

addSchemaModel('MyNewSchemaModel',  {
    id: "https://bettyblocks.com/question.schema.json",
    schema: "https://json-schema.org/draft/2020-12/schema",
    description: "BLA BLA BLA",
    title: "Question",
    type: "object",
    properties: {
      "score": {
        "type": "integer"
      },
      "answer": {
        "type": "string"
      },
      "uuid": {
        "type": "string"
      },
      "type": {
        "type": "string"
      },
      "title": {
        "type": "string"
      },
      "body": {
     	 "type": "string"
      }
   }
  });
⚠️ **GitHub.com Fallback** ⚠️