FactoryFour Learn Center Index

Last updated December 4, 2020


Modular Interactive Frames

Introduction to the frame building library used to create custom, interactive interfaces.


Introduction

Create custom interfaces using our modular frame building library. These custom interfaces can be displayed in many places across the application: task panel, order overview, dashboard and more.

Structure

This is implemented as an iframe that, as of writing, an implementation manager must setup using internal tools. The iframe runs a hook that both performs any API actions required by the hook and returns a configuration object, which is rendered by the front-end library. The configuration object has an array of sections composed of one or many display elements.

Sections

Sections are the top-level structural component of the configuration object.

module.exports = async (ctx) => {
    return {
        body: {
            sections: [{
              // sections formatted here
            }]
        }
    };
}

Every section returned requires a title and an array of elements.

type Section = {
	title: string;
	width?: string; // recommended as a percentage
	elements: AnyElement[];
};

Elements

Display-Only Elements

  1. Description: HTML text that can be displayed to the user – jexl parsing built-in
     export type DescriptionElement = {
         key: string;
         type: 'description';
         text: string;
         displayOptions?: DisplayOptions;
     };
    

    Use Cases: Great for displaying contextual information and links

  2. Break: Introduce a line break - useful to visually breakup elements within a section

     export type BreakElement = {
         type: 'break';
     };
    

Interactive Elements

These components either write data to the model or trigger an action.

Note: The model is included in the payload sent to the hook for button clicks, which allows for configuration of the action before clicking a button.

  1. Input: Simple input field to write to the model. Placeholder is an option field to display to the user when the input is empty.

     export type InputElement = {
         key: string;
         type: 'input';
         placeholder?: string;
     };
    
  2. Dropdown: Single-select dropdown for short lists. When an option is selected, the dropdown value will be written to the model with its key in the model matching the key of the element.

     export type DropdownElement = {
         key: string;
         type: 'dropdown';
         options: {
             value: string;
             title: string;
             displayOptions?: DisplayOptions;
         }[];
         allowNone?: boolean;
         placeholder?: string;
     };
    

    Options:

    • See Display Options for how to show or hide options in the dropdown via the option display options element
    • allowNone will permit the user to unselect a value from the dropdown - good for a default value
    • placeholder value presented to the user as a default value is allowNone is true or as a message to the user to display
  3. Table: Table component with selectable rows, similar to the dropdown only writing the row object to the model rather than a single value

     export type TableElement = {
         key: string;
         type: 'table';
         perPage?: number;
         schema: {
             fields: {
                 name: string;
                 key: string;
                 type: 'string' | 'number' | 'date';
             }[];
             sort: {
                 ascending: boolean;
                 key: string;
             }
         };
         values: any[];
     };
    
  4. Button: Simple button for users to trigger actions.

     export type ButtonElement = {
         key: string;
         type: 'button';
         text: string;
         displayOptions?: DisplayOptions;
     };
    

    If many buttons are listed in a single section, they will arrange neatly inline. When a button is clicked, the frame will make a request to the provided hook indicating that a specific button was pressed. While this request to the hook is pending, the button will remain in a loading state, and all other interactive elements will be disabled.

Click Handling

When a button is clicked it passes the key of the clicked button back to the hook, so the same hook must also handle the click by key.

const handleClick = async (ctx) => {
    if (ctx.body.key === 'buttonKey1') {
        return {
            body: {} // Action
        };
    }
    if (ctx.body.key === 'buttonKey2') {
        return {
            body: {} // Action
        };
    }
    return {
        status: 400,
        body: {
            message: 'Unrecognized click',
        },
    };
}

Actions

export type RedirectAction = {
	action: 'redirect';
	url: string;
	inApp?: boolean;
	target?: '_blank'|'_top';
}

export type MessageAction = {
	action: 'message';
	text: string;
}

export type ModalAction = {
	action: 'modal';
	url: string;
	title?: string;
}

export type FormAction = {
	action: 'form';
	shouldRefresh?: boolean;
	formId: string;
}

export type NewForm = {
	action: 'new_form';
	shouldRefresh?: boolean;
	schemaId: string;
}

Search the FactoryFour Learn Center


FactoryFour Learn Center