Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

UI Migration Guide



Flex-UI and WebChat-UI 0.13 -> 1.0

flex-ui-and-webchat-ui-013---10 page anchor

This guide contains a list of the breaking changes introduced between version 0.13 and 1.0 of Flex UI. If you have done programmatic customizations to Flex UI or Flex WebChat UI, you will need to make sure that your custom code is updated to support these changes.


Breaking and notable changes

breaking-and-notable-changes page anchor

Using a custom Redux store

using-a-custom-redux-store page anchor

To use a custom redux store, use the Flex store enhancer with a store creation method:


_27
const reducers = combineReducers({
_27
flex: Flex.FlexReducer,
_27
app: myReducer
_27
});
_27
_27
const middleware = applyMiddleware();
_27
_27
const store = createStore(
_27
reducers,
_27
compose(
_27
middleware,
_27
Flex.applyFlexMiddleware()
_27
)
_27
);
_27
_27
Flex
_27
.Manager.create(configuration, store)
_27
.then(manager => {
_27
ReactDOM.render(
_27
<Provider store={store}>
_27
<Flex.ContextProvider manager={manager}>
_27
<Flex.RootContainer />
_27
</Flex.ContextProvider>
_27
</Provider>,
_27
container
_27
);
_27
})

Plugins and Plugin Builder

plugins-and-plugin-builder page anchor

After Flex GA, the preferred way of customizing Flex, both Twilio hosted and locally hosted deployment models, is plugins.

Flex plugins are essential to customizing Flex instances so your development team can share components with agents and supervisors across your organization. Read more about customizing Flex with plugins here

If you have styled you UI, using the theming object, then you will need to make sure you do the following changes:

The colorTheme object now has 4 parameters:

  • baseName : string - to set a predefined theme
  • colors : object - to define a set of base colors that are used throughout the UI to define your custom theme
  • light : boolean - controls whether UI will aim at choosing dark texts or light text colors to allow for readability. It also controls icon colors, hover colors and more
  • overrides : object - a set of style overrides for each component

An example of setting the color configurations in appConfig:


_32
config.colorTheme = {
_32
baseName: "DarkTheme",
_32
colors: {
_32
base1: "blue",
_32
base2: "orange",
_32
base3: "yellow",
_32
base4: "black",
_32
base5: "white",
_32
base6: "pink",
_32
base7: "red",
_32
base8: "blue",
_32
base9: "brown",
_32
base10: "black",
_32
base11: "white",
_32
},
_32
light: false,
_32
overrides: {
_32
MainHeader: {
_32
Container: {
_32
background: "#35372c"
_32
}
_32
},
_32
SideNav: {
_32
Container: {
_32
background: "#35372c"
_32
},
_32
Button: {
_32
background: "35372c"
_32
},
_32
},
_32
}
_32
}

We have introduced React Router for routing in Flex UI

  • New actions to navigate the browser to different locations in the way similar to HTML5
  • History API:
    • HistoryPush
    • HistoryReplace
    • HistoryGo
    • HistoryGoBack
    • HistoryGoForward
  • New property route for a View component to mount a view to a route different from its name

Support for browser and memory history that is configurable through the configuration file.

Making Flex UI work with routing within your application

making-flex-ui-work-with-routing-within-your-application page anchor

In case you are using routing libraries like react-router-redux or connected-react-router, you may wish to sync history between your application and Flex. To do so, provide the history object that you are using for your Router as a parameter to Flex store enhancer:


_41
const reducers = combineReducers({
_41
flex: Flex.FlexReducer,
_41
app: myReducer
_41
});
_41
_41
const history = createHistory();
_41
_41
const middleware = applyMiddleware();
_41
_41
const store = createStore(
_41
reducers,
_41
compose(
_41
middleware,
_41
Flex.applyFlexMiddleware(history)
_41
)
_41
);
_41
_41
Flex
_41
.Manager.create(configuration, store)
_41
.then(manager => {
_41
ReactDOM.render(
_41
<Provider store={store}>
_41
<ConnectedRouter history={history}>
_41
<Switch>
_41
<Route path="/hi" component={() => {
_41
setTimeout(() => { history.push("/"); }, 5000);
_41
return (
_41
<div>Hi! I will redirect to Flex in 5 seconds flat!</div>
_41
);
_41
}}></Route>
_41
<Route component={() => {
_41
return (<Flex.ContextProvider manager={manager}>
_41
<Flex.RootContainer />
_41
</Flex.ContextProvider>);
_41
}}></Route>
_41
</Switch>
_41
</ConnectedRouter>
_41
</Provider>,
_41
container
_41
);
_41
})

We have introduced Component.Content.remove to allow the removal of components from dynamic component children (both native and programmatically-added ones). See the specification here.

This feature now requires a key property for all custom components passed to Component.Content.register/add. E.g. <div key="custom-key"/>

If you have added custom components to Flex UI, make sure they have a key property defined.

  • Property task type changed to ITask for task-based components. Previously, the TaskState interface, which had only source and reservation properties, was used. The source and reservation properties remain the same, but now attributes and other task properties can be accessed from the task object itself. For example, this.props.task.attributes can be used where applicable and there should be no further need to use the source sub-property (which refers to the Task Router SDK object).
  • Tasks in store are referenced by reservation sid now. (Previously, they had been referenced by task sid .)
  • Task objects in the Actions framework have a new field, sourceObject, which will point to the actual SDK object:
    • Reservation in case the data source for the task is TaskRouterSDK. Applies for components and actions in AgentDesktopView .
    • InsightsObject in case the data source for the task is InsightsSDK. Applies for components and actions in TeamsView
    • Source is still there, but is deprecated.
  • All actions that had taskSid in the payload will now expect sid instead
  • Payloads have changed for some Actions:
    • SetActivity action now has a payload in the form of {activitySid: string; activityName?: string; activityAvailable?: boolean} . Only activitySid is used in the default implementation, and is required when invoking the action by the user, but the other two parameters are filled for better context for users who override the action and need more information on what the new activity will be. Additionally, SetActivity can now be called with just activityName in the payload.
    • SelectTaskInSupervisor now expects/provides an object as its payload in the form of {task?: ITask, sid?: string} . Providing either will autofill the other, so both will be available for whoever taps into the action via the Actions framework.
    • SelectWorkerInSupervisor now expects/provides an object as its payload in the form of {worker?: ITask, workerSid?: string} . Providing either will autofill the other, so both will be available for whoever taps into the action via the Actions framework.
    • MonitorCall now expects/provides an object as its payload in the form of {task?: ITask, sid?: string} . Providing either will autofill the other, so both will be available for whoever taps into the action via the Actions framework.
    • HoldCall will no longer toggle the hold state, but will instead be meant only for call holding. A separate UnholdCall action was added.

The HangupCall and HoldCall actions will now accept optional parameters sid:string or task:ITask in the payload object. Actions will work without them if just one call is available, but it is advised to use those parameters to be more specific for future multi-call scenarios. Even if the task/taskSid are not specified, when adding listeners or overriding these actions, those parameters are filled out automatically.

Call recording can be enabled from the configuration service. This option sets the following parameters in the conference payload when a conference is created:

  • "conferenceRecord": true,
  • "conferenceRecordingStatusCallback": "https://webhooks.twilio.com/v1/Accounts/{accountSid}/Workspaces/{workspaceSid}/Tasks/{taskSid}/FlexRecordingWebhook",
  • "conferenceRecordingStatusCallbackMethod": "POST"

You can retrieve the accountSid and workspaceSid via the configuration services, i.e.

manager.serviceConfiguration.account_sid

manager.serviceConfiguration.taskrouter_workspace_sid

(warning)

Warning

If you have replaced an AcceptTask action, registered a custom action that issues a conference instruction, or directly issued a conference instruction via TaskRouterSDK (or any other way of setting a conference payload), make sure that the above params are set properly to support call recording.

Transfers and endConferenceOnExit

transfers-and-endconferenceonexit page anchor

To enable call transfers, calls will be currently accepted with endConferenceOnExit set to false, meaning that the call will not stop for the customer when an agent hangs up, and to end the call, the customer will need to hang up themselves (otherwise, they will stay in the call alone).

If the above behavior is not acceptable for your use case and you will not be using transfer functionality, you may opt out of transfers by setting the disableTransfers config option to true. If this option is set to true, the endConferenceOnExit option will be set to true, but transfers to other agents will not be available.

All of the functions to orchestrate different channels and tokens have been removed. Now, a combination of backend services and Studio flows is used instead.

  • Theming - the same changes that have been implemented for Flex UI have been implemented here as well.
  • Pre-engagement data - when a chat session is created, pre-engagement data is saved to chat channel attributes ( channel.attributes.pre_engagement_data ), that can be accessed in the Studio Flow or directly from Programmable Chat via the SDK or REST API.
  • Configuration options startEngagementUrl and serviceBaseUrl have been removed and new configuration options are required in the application configuration:
    • accountSid - Account SID where Flex is running
    • flexFlowSid - Flex Flow SID created at onboarding for chat

The accountSid and flexFlowSid can be found on the admin dashboard development configuration page: https://flex.twilio.com/admin/developers(link takes you to an external page)

Changes to Manager object

changes-to-manager-object page anchor
  • ContactCenterManager was renamed to Manager
  • Changed Manager.create method signature - first accountSid parameter was dropped

We have started using a Twilio configuration service for project-level remote configuration that can be shared between different instances of Flex UI.

  • A new method for Manager's instances fetchConfiguration asynchronously retrieves a configuration from the Flex Configuration service
  • A new method for Manager's instance updateConfig merges provided configurations on top of any existing configuration
  • Manager's instance configuration behavior:
    • Whenever a new instance of Manager is created, it will fetch the remote configuration from Flex Configuration service. Local configuration will be applied on top of remote configuration
    • Manager's instance configuration setter is deprecated

The Task Channel Definition API has been introduced. This is how all of the native channels are defined in Flex UI, and is the advised way of registering your own custom channels or customizing existing ones. The specification can be found here.

  • Only JWE tokens are now supported
  • The SupervisorDesktopView component was renamed to TeamsView
  • The template SideNavSupervisorView was renamed to SideNavTeamsView
  • Templates and channel definitions use the channelType attribute from a task to detect the chat channel type. Previously, the endpoint parameter was used.

A new Flex API method, progress, renders a fancy loading indicator to a provided selector: Flex.progress("#container")


Migrating from sample app 0.13 -> 1.0

migrating-from-sample-app-013---10 page anchor
  • Upgrade packages in package.json "@twilio/flex-ui": "^1.0.0",
    "react": "^16.5.2",
    "react-dom": "^16.5.2"
  • ADD: "eslintConfig": {
    "extends": "react-app"
    },
  • REMOVE: react-app-rewired": "1.5.2”
  • UPDATE: scripts: {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test"
    "eject": "react-scripts eject
    }
  • Update index.js


    _61
    import React from "react";
    _61
    import ReactDOM from "react-dom";
    _61
    import "regenerator-runtime/runtime";
    _61
    import * as Flex from "@twilio/flex-ui";
    _61
    import "./index.css";
    _61
    import App from "./App";
    _61
    import registerServiceWorker from "./registerServiceWorker";
    _61
    const configStorageKey = "FLEX_CONFIG";
    _61
    const mountNode = document.getElementById("root");
    _61
    window.onload = () => {
    _61
    const predefinedConfig = window.appConfig || {};
    _61
    const runtimeConfig = getRuntimeConfig();
    _61
    const configuration = {
    _61
    ...predefinedConfig,
    _61
    ...runtimeConfig
    _61
    };
    _61
    Flex
    _61
    .progress(mountNode)
    _61
    .Manager.create(configuration)
    _61
    .then(manager => renderApp(manager))
    _61
    .catch(error => handleError(error));
    _61
    };
    _61
    function renderApp(manager) {
    _61
    ReactDOM.render(
    _61
    <App manager={manager} />,
    _61
    mountNode
    _61
    );
    _61
    }
    _61
    function handleError(error) {
    _61
    console.error("Failed to initialize Flex", error);
    _61
    const missingAccountSid = error instanceof Flex.ConfigError && error.key === "accountSid";
    _61
    if (!missingAccountSid) {
    _61
    throw error;
    _61
    }
    _61
    ReactDOM.render(
    _61
    <Flex.RuntimeLoginView
    _61
    onSuccess={(loginData, runtimeDomain) => {
    _61
    setRuntimeConfig(loginData, runtimeDomain);
    _61
    window.location.reload();
    _61
    }}
    _61
    />,
    _61
    mountNode
    _61
    );
    _61
    }
    _61
    function setRuntimeConfig(loginData, runtimeDomain) {
    _61
    const config = {
    _61
    serviceBaseUrl: runtimeDomain,
    _61
    sso: {
    _61
    accountSid: loginData.accountSid
    _61
    }
    _61
    };
    _61
    const serializedConfig = JSON.stringify(config);
    _61
    localStorage.setItem(configStorageKey, serializedConfig);
    _61
    }
    _61
    function getRuntimeConfig() {
    _61
    const serializedConfig = localStorage.getItem(configStorageKey);
    _61
    localStorage.removeItem(configStorageKey);
    _61
    const config = JSON.parse(serializedConfig || "{}");
    _61
    return config;
    _61
    }
    _61
    registerServiceWorker();

  • Update App.js
    Move customization to manager into the render method below:****


    _20
    import React from "react";
    _20
    import * as Flex from "@twilio/flex-ui";
    _20
    _20
    class App extends React.Component {
    _20
    render() {
    _20
    const { manager } = this.props;
    _20
    _20
    if (!manager) {
    _20
    return null;
    _20
    }
    _20
    _20
    return (
    _20
    <Flex.ContextProvider manager={manager}>
    _20
    <Flex.RootContainer />
    _20
    </Flex.ContextProvider>
    _20
    );
    _20
    }
    _20
    }
    _20
    _20
    export default App;

  • Refactor Checklist:

    • Any components accessing task status like this: this.props.task.reservation now can access status like this: this.props.task.status
    • If getting reservation like this: const reservation = StateHelper.getReservation(task.sid); now can use this: const reservation = payload.task.sourceObject;
    • Be sure to update any Actions you are using to reference reservation sid , not taskSid

Rate this page: