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

Flex UI 2.x.x updates that can affect your customizations


This page describes Flex UI updates that you should be aware of when migrating to Flex UI 2.x.x. Review this information to determine if you need to make updates to your customizations to be compatible with Flex UI 2.x.x.

For more information about the entire migration process, see Migrate from Flex UI 1.x.x to 2.x.x.


Degraded mode

degraded-mode page anchor

We have introduced a Degraded mode for Flex UI - now Flex UI will initialize with limited capabilities, even if some of the components like SDKs (TaskRouter, Conversations, Voice, or Sync) are down. In case of disruptions to Twilio's services, Flex users can still log in to Flex and perform certain tasks related to operational services. For example, in the case of Twilio Voice experiencing an incident, your agent will still be able to handle messaging tasks.

Users will see a notification informing them of a possible disruption in the normal work of Flex UI and they will be able to download a thorough report with error details and logs.

For more on error handling and reporting, check out our Troubleshooting the Flex UI guide.


Currently, the Flex UI uses the Programmable Chat SDK to handle messaging channels. In 2.x.x, the Flex UI uses the Conversations SDK to replicate this functionality.

To ease migration of plugins from Flex UI 1.x.x to 2.x.x, we want to create a virtual bridge to also export Chat SDK-compatible constructs. Therefore, you can still use your Chat-based customizations with fewer changes. This bridge logic will render a warning highlighting that the accessed methods and properties are actually deprecated.

Identified differences between the Chat and Conversation libraries

identified-differences-between-the-chat-and-conversation-libraries page anchor

Here are the properties and methods that have been changed or removed.

Chat Client

TypeChat ClientConversation Client
propertychannelsconversations
methodcreateChannelcreateConversation
methodgetChannelBySidgetConversationBySid
methodgetChannelByUniqueNamegetConversationByUniqueName
methodgetSubscribedChannelsgetSubscribedConversations
methodgetUserDescriptor// pass user instead
methodgetLocalChannels// get subscribed channels
eventchannelAddedconversationAdded
eventchannelInvitedconversationInvited
eventchannelJoinedconversationJoined
eventchannelLeftconversationLeft
eventchannelRemovedconversationRemoved
eventchannelUpdatedconversationUpdated
eventmemberJoinedparticipantJoined
eventmemberLeftparticipantLeft
eventmemberUpdatedparticipantUpdated

Channel vs Conversations

typeChannelConversationNotes
propertyisPrivateReturns true
propertylastConsumedMessageIndexlastReadMessageIndex
propertytypeReturns a string 'private'
propertyadvanceLastConsumedMessageIndexadvanceLastReadMessageIndex
propertymembersparticipantsNot exposed
methodgetMemberByIdentitygetParticipantByIdentity
methodgetMemberBySidgetParticipantBySid
methodgetMembersgetParticipants
methodgetMembersCountgetParticipantsCount
methodgetUnconsumedMessagesCountgetUnreadMessagesCount
methodremoveMemberremoveParticipant
methodsetAllMessagesConsumedsetAllMessagesRead
methodsetNoMessagesConsumedsetAllMessagesUnread
methodupdateLastConsumedMessageIndexupdateLastReadMessageIndex

ChannelDescriptor

No parallel in the Conversations SDK, we fall back to Conversation.

UserDescriptor

No parallel in the Conversations SDK, we fall back to User.

Chat User vs Conversation User

typeChat UserConversation User
propertyonlineisOnline
propertynotifiableisNotifiable

Chat Message vs Conversation Message

typeMessageMessageNotes
propertychannelconversation
propertymemberSidparticipantSid

Chat Member vs Conversation Participant

typeMemberParticipantNote
propertychannelconversation
propertylastConsumedMessageIndexlastReadMessageIndex
propertylastConsumptionTimestamplastReadTimestamp
methodgetUserDescriptorUse getUser
event argumentupdateReason 'lastConsumedMessageIndex'updatedReason

'lastReadMessageIndex'
event argumentupdateReason 'lastConsumptionTimestamp'updatedReason

'lastReadTimestamp'

Chat SDK methods and concepts dropped in the Conversations SDK

  1. There's no concept of a public channel. All the conversations are private .
  2. Descriptors have been removed. They used to be a "snapshot" of the described entity. This is easily replaceable by returning the actual entity and unsubscribing from its changes.
  3. There is no invite method anymore on conversations. We fall back to the add method as their functionalities are very similar.

Deprecated reducers

  • channels
  • channelInput

Deprecated props

  • channel
  • channelSid
  • isMemberOfChannel
  • member
  • autoInitChannel
  • activeChatChannel
  • chatChannel (on taskContext)

Deprecated Helpers

  • ChatChannelHelper - replaced by ConversationHelper

Deprecated methods

  • TaskHelper.getTaskChannelSid

Deprecated notifications ID

  • ChatOrchestrationAddToConversationFailed
  • ChatOrchestrationDeactivateConversationFailed
  • ChatOrchestrationLeaveConversationFailed

The Flex UI 1.x.x uses the twilio-client(link takes you to an external page) SDK for voice communications. In 2.x.x, it uses the twilio-voice(link takes you to an external page) SDK for this functionality since the twilio-client is now deprecated. Functionality and usage of the new Voice SDK remains largely the same with a few exceptions:

  • The events Connect , Disconnect , and Cancel which used to apply to the Device instance now applies to the Call instance instead.
  • The Device ready event has been replaced with a registered event. Likewise for online which is now unregistered .
  • The structure of the Device state has changed to:

_10
namespace Device {
_10
isBusy: boolean;
_10
enum State {
_10
Unregistered = 'unregistered';
_10
Registering = 'registering';
_10
Registered = 'registered';
_10
Destroyed = 'destroyed';
_10
}
_10
}

Listen for a running call on Flex UI 2.x.x

listen-for-a-running-call-on-flex-ui-2xx page anchor

To detect a running call within the Flex UI 2.x.x, you can listen for an incoming Voice event through the Flex Manager(link takes you to an external page). For detecting a call using UI actions, see "Common use cases and examples" on Use UI Actions.


_10
const manager = Flex.Manager.getInstance();
_10
manager.voiceClient.on('incoming', onVoiceClientConnectListener);
_10
_10
// Listener function
_10
function onVoiceClientConnectListener (){
_10
console.log("Call detected");
_10
// Do something
_10
}

For more details on the changes from the twilio-client to the twilio-voice SDK, see this migration guide. Also refer to the Twilio.Device and Twilio.Call pages for more details on the Device and Call objects of the Twilio Voice JavaScript SDK.


New Flex access token update behavior

new-flex-access-token-update-behavior page anchor

In Flex UI 1.x.x, your code may have listened to Flex access token updates in the following way:


_10
manager.store.getState().flex.session.loginHandler.on('tokenUpdated', (token) => {});

With Flex 2.x.x, loginHandler no longer supports this functionality. You can instead use the native Flex 'tokenUpdated' Event(link takes you to an external page) to achieve the same behavior:


_10
import { Manager } from "@twilio/flex-ui";
_10
const manager = Manager.getInstance();
_10
manager.events.addListener("tokenUpdated", (tokenPayload) => {});


New Actions and Flex Events for the TaskRouter SDK

new-actions-and-flex-events-for-the-taskrouter-sdk page anchor

We have added new Flex actions wrapping TaskRouter:


_27
import { Actions } from "@twilio/flex-ui";
_27
_27
// Set worker attributes
_27
Actions.invokeAction("SetWorkerAttributes", { attributes: {}, mergeExisting: true });
_27
_27
// Update worker token
_27
Actions.invokeAction("UpdateWorkerToken", { token: "newToken" });
_27
_27
// Update task attributes
_27
Actions.invokeAction("SetTaskAttributes", { sid: "WRxxxxx", attributes: {}, mergeExisting: true });
_27
_27
// Issue a Call to a Worker
_27
Actions.invokeAction("IssueCallToWorker", { callerId: "callerId", twiMLUrl: "twiMLUrl", options: {} });
_27
_27
// Dequeue the Reservation to the Worker.
_27
// This will perform telephony to dequeue a Task that was enqueued using the Enqueue TwiML verb.
_27
// A contact_uri must exist in the Worker's attributes for this call to go through.
_27
Actions.invokeAction("DequeueTask", { options: {} })
_27
_27
// Redirect the active Call tied to this Reservation
_27
Actions.invokeAction("RedirectCallTask", { callSid: "callSid", twiMLUrl: "twiMLUrl", options: {} });
_27
_27
// Update the Worker's leg in the Conference associated to this Reservation
_27
Actions.invokeAction("UpdateWorkerParticipant", { options: {} });
_27
_27
// Update the Customer leg in the Conference associated to this Task
_27
Actions.invokeAction("UpdateCustomerParticipant", { options: {} });

and introduced new Flex Events wrapping TaskRouter events:


_35
import { Manager } from "@twilio/flex-ui";
_35
const manager = Manager.getInstance();
_35
_35
// Emitted when a worker receives a new task
_35
manager.events.addListener("taskReceived", (task: ITask) => {});
_35
_35
// Emitted when the worker's activity changes
_35
manager.events.addListener("workerActivityUpdated", (activity: Activity, allActivities: Map<string, Activity>) => {});
_35
_35
// Emitted when the worker's attributes changes
_35
manager.events.addListener("workerAttributesUpdated", (newAttributes: Record<string, any>) => {});
_35
_35
// Emitted when the worker's task status gets updated
_35
manager.events.addListener("taskUpdated", (task:ITask) => {});
_35
_35
// Emitted when the worker's task gets set to 'accepted'
_35
manager.events.addListener("taskAccepted", (task:ITask) => {});
_35
_35
// Emitted when the worker's task gets set to 'canceled'
_35
manager.events.addListener("taskCanceled", (task:ITask) => {});
_35
_35
// Emitted when the worker's task gets set to 'completed'
_35
manager.events.addListener("taskCompleted", (task:ITask) => {});
_35
_35
// Emitted when the worker's task gets set to 'rejected'
_35
manager.events.addListener("taskRejected", (task:ITask) => {});
_35
_35
// Emitted when the worker's task gets set to 'rescinded'
_35
manager.events.addListener("taskRescinded", (task:ITask) => {});
_35
_35
// Emitted when the worker's task gets set to 'timeout'
_35
manager.events.addListener("taskTimeout", (task:ITask) => {});
_35
_35
// Emitted when the worker's task gets set to 'wrapup'
_35
manager.events.addListener("taskWrapup", (task:ITask) => {});

Now you can use exclusively Flex UI Actions Framework(link takes you to an external page) when working with TaskRouter SDK, without needing to access its methods directly.

Visit our Flex UI API docs(link takes you to an external page) for more details on Actions and Events.


Flex UI 2.x.x uses a new theming structure that more closely maps to the Twilio Paste(link takes you to an external page) design system. This new structure is based on the concept of design tokens(link takes you to an external page), a set of variables that you can modify. This structure promotes consistency, customization, and web accessibility.

Theme configuration changes

theme-configuration-changes page anchor

config.colorTheme is deprecated. Components which receive the theme as props have the following changes:

  1. props.theme.calculated is deprecated.

    1. Use props.theme.isLigh t instead of p rops.theme.calculated.lightTheme
    2. Use props.theme.tokens.textColors.colorText instead of props.theme.calculated.textColor .
  2. props.theme.colors is deprecated.
  3. props.theme.tokens is introduced:

_13
interface Tokens {
_13
backgroundColors: BackgroundColors;
_13
textColors: TextColors;
_13
borderColors: BorderColors;
_13
borderWidths: typeof BorderWidth;
_13
radii: typeof BorderRadius;
_13
fontSizes: typeof FontSize;
_13
fontWeights: typeof FontWeight;
_13
lineHeights: typeof LineHeight;
_13
sizings: typeof Sizing;
_13
spacings: typeof Spacing;
_13
_13
}

To override theme styles in Flex UI 2.x.x, see Override Flex UI 2.x.x themes, branding and styling.

Deprecated Predefined themes

deprecated-predefined-themes page anchor

Flex UI 2.x.x deprecates all predefined themes like DarkTheme, MediumTheme, BlueDarkTheme, BlueMediumTheme. It will now have 2 modes of Flex: Light and Dark.

List of deprecated tokens

list-of-deprecated-tokens page anchor

_30
const deprecatedTokens = [
_30
"errorColor",
_30
"errorGlow",
_30
"buttonHoverColor",
_30
"tabSelectedColor",
_30
"connectingColor",
_30
"disconnectedColor",
_30
"notificationBackgroundColorInformation",
_30
"notificationBackgroundColorSuccess",
_30
"notificationBackgroundColorWarning",
_30
"notificationBackgroundColorError",
_30
"notificationIconColorError",
_30
"notificationIconColorWarning",
_30
"userAvailableColor",
_30
"userUnavailableColor",
_30
"defaultButtonColor",
_30
"lightTextColor",
_30
"darkTextColor",
_30
"disabledColor",
_30
"focusColor",
_30
"focusGlow",
_30
"holdColor",
_30
"declineColor",
_30
"acceptColor",
_30
"declineTextColor",
_30
"acceptTextColor",
_30
"completeTaskColor",
_30
"flexBlueColor",
_30
"agentBusyColor"
_30
];

Deprecated Channel colors

deprecated-channel-colors page anchor

_11
const deprecatedChannelColors = [
_11
"inactive",
_11
"call",
_11
"video",
_11
"chat",
_11
"sms",
_11
"facebook",
_11
"line",
_11
"whatsapp",
_11
"custom"
_11
];

In Flex UI 2.x.x, we've introduced Flex.setProviders() to let you load providers once at the root level and set the context correctly. Developers won't have to worry about wrapping again, as the context will be set correctly. For usage examples, see:

When using Material UI for styling, it is important to wrap our plugins with a StylesProvider with a classNameGenerator that sets a productionPrefix and a seed so styles classes don't clash between plugins and Flex. The below example shows how to use a custom provider for styling Material UI components:


_14
import { StylesProvider, createGenerateClassName } from '@material-ui/core/styles';
_14
_14
Flex.setProviders({
_14
CustomProvider: (RootComponent) => (props) => {
_14
return (
_14
<StylesProvider generateClassName={createGenerateClassName({
_14
productionPrefix: 'pluginXYZ',
_14
seed: 'pluginXYZ',
_14
})}>
_14
<RootComponent {...props} />
_14
</StylesProvider>
_14
);
_14
}
_14
});

If you would like to gradually migrate from Material UI to Twilio Paste, you may use both in a single plugin by setting both a CustomProvider and a PasteThemeProvider:


_16
import { StylesProvider, createGenerateClassName } from '@material-ui/core/styles';
_16
import { CustomizationProvider } from "@twilio-paste/core/customization";
_16
_16
Flex.setProviders({
_16
CustomProvider: (RootComponent) => (props) => {
_16
return (
_16
<StylesProvider generateClassName={createGenerateClassName({
_16
productionPrefix: 'pluginXYZ',
_16
seed: 'pluginXYZ',
_16
})}>
_16
<RootComponent {...props} />
_16
</StylesProvider>
_16
);
_16
},
_16
PasteThemeProvider: CustomizationProvider
_16
});


Flex Messaging UI V2 changes

flex-messaging-ui-v2-changes page anchor
(information)

Info

This change is implemented in version alpha.15 and is turned off for accounts signed up for Flex UI 2.x.x Private Beta prior to this version being released as it is a breaking change in the component API. Please reach out to your technical account manager to have the new messaging UI enabled.

Moving to Flex Conversations with Flex 2.x.x has enabled us to provide an even more customizable Messaging UI, and this comes with a few of changes which you may need to adjust to.

New Dynamic Component structure - MessageInputV2

new-dynamic-component-structure---messageinputv2 page anchor

The new default input component in the messaging canvas is the dynamic component MessageInputV2 . This includes the text area component and a new dynamic component, MessageInputActions , and is structured like so:


_10
<MessageInputV2>
_10
<MessageInputArea key="textarea"/>
_10
<MessageInputActions key="actions"/>
_10
</MessageInputV2>

MessageInputActions contains the message send button and the file attachment button (if file attachment is enabled).

You can use custom actions for this component via the add, replace, and remove methods(link takes you to an external page).

MessageInputV2 has two new default props: hideSendButton and rows. These control the rendering of the send button and row height of the text area respectively. You can use hideSendButton together with returnKeySendsMessage to enable sending message on Enter.

Combined text and media messages

combined-text-and-media-messages page anchor

The SendMessage action is now capable of sending file attachments and text in the same message. Files can be passed to the SendMessage action on the attachedFiles field of its Action payload.The SendMedia action is deprecated but is still available.

Learn more about new components in the Flex UI API docs(link takes you to an external page).


User and Activity controls

user-and-activity-controls page anchor
user-activity-controls.

The user-controls child component in Flex UI 1.x.x has been split out into two new child components for the MainHeader(link takes you to an external page) in Flex UI 2.x.x:

  • activity shows and allows the user status to be changed.
  • user-controls shows the currently logged in user and allows the user to logout.
(warning)

Warning

This is a potential breaking change if you have customized UserCard and its child components using CSS.


State Management Changes

state-management-changes page anchor

As part of the upgrades to our core APIs, Flex UI 2.x.x includes the Redux Toolkit and some new APIs for managing your internal state. These tools provide some guardrails for your state management, helping you set up boilerplate code more easily and with better defaults.

We recommend using single Redux store, either let Flex UI create its own store or pass a custom store using Manager.create() API(link takes you to an external page)

A wrapper around Redux's useSelector method(link takes you to an external page). It exposes the same API but adds some Flex validations to ensure Flex's internal state is usable. This selector is specific for working with Flex state itself. Outside of accessing Flex state, we recommend using the default useSelector.


_10
const MyComponent = (props) => {
_10
const viewState = useFlexSelector(state => state.view);
_10
return (
_10
{viewState.isSideNavOpen &&
_10
<div>My Custom Code</div>
_10
}
_10
)
_10
}

The selector takes the current view state for the custom component. The selector guarantees that the state being selected is safe to read and can be used in the application without side effects. This couldn't be guaranteed with useSelector.

A wrapper around Redux's useDispatch method(link takes you to an external page). It prevents dispatches from causing side effects to Flex's state, ensuring your changes work as expected. Use this hook for interacting with Flex's state. You can use the native useDispatch method outside of Flex's state.


_10
const MyComponent = (props) => {
_10
const viewState = useFlexSelector(state => state.view);
_10
const dispatch = useFlexDispatch();
_10
return (
_10
{viewState.isSideNavOpen &&
_10
<button onClick={() => dispatch({type: 'close_side_bar'})}>My Custom Code</button>
_10
}
_10
)
_10
}

MessageInput.defaultProps.useSeparateInputStore

messageinputdefaultpropsuseseparateinputstore page anchor

The Flex UI 2.x.x no longer uses the MessageInput.defaultProps.useSeparateInputStore flag and its behavior has been deprecated. All Flex UI development must now be done with a separate Store. You can remove the flag without any repercussions.


You need to update your AppConfig structure to utilize the new config structure's names and capabilities.

Flex 1.x.xFlex 2.x.xChanges
Notifications.browserNotifications.enabledrenamed
warmTransfers-removed
colorThemethemeUpdated (more info)

Download Media Attachment changes

download-media-attachment-changes page anchor

DownloadMedia action no longer requires "message" as a part of the payload. Instead, a new property "media" of type "Media" from @twilio/conversations is required.

These actions were renamed to follow the action naming convention:

Flex UI 1.0Flex UI 2.x.x
InsightsPlayer:playInsightsPlayerPlay
InsightsPlayer:showInsightsPlayerShow
InsightsPlayer:hideInsightsPlayerHide
InsightsPlayer:initializedInsightsPlayerInitialized
HistoricalReporting:viewHistoricalReportingView

  • Removed FilterData (shouldn't be needed) and TeamFiltersPanelProps (use TeamFiltersPanelChildrenProps instead) interfaces from Flex.Supervisor .
  • Removed filters props from the Component properties for TeamsView(link takes you to an external page) . Use TeamsView.defaultProps.filters to apply a filter.
  • Removed uniqueName from TaskCanvasTabsChildrenProps .
  • Removed the deprecated WorkerProfile.defaultProps.details prop. Use WorkerProfile.Content to add additional details to the worker profile panel.
  • Legacy filtering in TeamsView was removed. Filters from WorkersDataTable.defaultProps.filters will still be added to the new filter panel, but the support for filter factories was dropped.
  • WorkersDataTable.defaultProps.initialCompareFunction was removed. Support for sorting was added to the workers table and you can now use sortWorkers , sortCalls , and sortTasks on WorkersDataTable.defaultProps to specify the compare functions used by the workers, calls and tasks columns. For initial sorting, we've introduced a new prop, defaultSortColumn , to the WorkersDataTable where it would take the key as the value. Please refer to WorkersDataTable of the Flex UI API Reference(link takes you to an external page) for key details.
  • WorkersDataTable.defaultProps.tablePlaceholder was removed. The message displayed when the table is empty can be modified with the TeamsViewResultsSummaryNoWorkersDisplayedTitle and TeamsViewResultsSummaryNoWorkersDisplayed templates.
  • Cleaned up the WorkersDataTableChildrenProps . Only workers , selectedTask , selectedWorker , and monitoredTaskSid are now available.
  • WorkersDataTable no longer forces updates every second. This could be considered breaking for customers who added columns, which contain some timers (eg. task age) and which will no longer tick every second.

We have also cleaned up our api and renamed or remove objects and interfaces. Most of the changes should not have any impact on plugins.

Removed/renamed deprecated objects and interfaces

removedrenamed-deprecated-objects-and-interfaces page anchor
  • UserControlsImplProps has been removed. Refer to UserControlsChildrenProps instead
  • call.oldHold removed from TaskContext and state.phone.connection.onHold removed from state. Use TaskHelper.isCallOnHold(task) to get the status of the call.
  • DeprecatedLoginView component removed
  • DeprecatedRuntimeLoginView component removed
  • state.flex.phone.connections property removed. Refer to state.flex.phone.connection instead.
  • Event selectedViewChanged now only receives one argument ( newViewName ) and it's not triggered on view resize anymore. To listen to view resize events, please subscribe to the viewResized event.
  • ActionsImpl object has been removed. Please refer to Actions instead.
  • registerGlobalStyles has been removed. Please refer to registerStyles instead
  • AudioManager's ErrorCode has been renamed to AudioErrorCode
  • Actions.emit has been removed - use Actions.invokeActions instead.
  • Actions.removeAllListeners has been removed - please use Actions.removeListener and provide the specific listeners you want to remove.
  • Removed export of Flex.ErrorManager . This functionality has been replaced with Flex.Monitor.sendDebuggerEvent
  • Removed selectionStart / selectionEnd from MessageState , MessageInputArea , MessageInput , ConversationState
  • Removed show and hide methods from the ModalPopupWithEntryControl
  • Changed hiddenQueueFilter to queueFilter which takes a predicate function. See "Add a Worker Directory Tabs Queue Filter" on Work with Components and Props for usage details

Removed unused objects and interfaces

removed-unused-objects-and-interfaces page anchor
  • ChatModule
  • ChatStateCallback
  • chatReducer
  • registerGlobalStyles
  • StateMachineCb
  • StateMachine
  • initWithStrings
  • Version (not VERSION)
  • Initialize (from flex-core)
  • DeepPartial
  • NotificationManager
  • withDefaultPropsUpdate
  • AggregatedDataTile
  • ArrayInterpolation
  • FunctionInterpolation
  • Interpolation
  • StyledOptions
  • Themed
  • CreateStyled
  • CreateStyledOtherComponent
  • CreateStyledStatelessComponent
  • StyledComponent
  • StyledComponentMethods
  • StyledOtherComponent
  • StyledStatelessComponent,
  • getBackgroundWithHoverCSS
  • ThemeSupport
  • Utils
  • CountryManager
  • Animations
  • SVGContainerProps
  • FrameConstants
  • StyledUl
  • CSSProps

Component and config changes

component-and-config-changes page anchor
  • TaskInfoPanel inner html styles tweaked to accommodate new design
  • TaskInfoPanelContent string inner html updated
  • TaskCanvasTabs resets to default task when switching between tabs
  • Flag file-attachments-in-chat is deprecated
  • Customizing the TaskListItem(link takes you to an external page) color directly is no longer possible. Please refer to addwrapper() in Work with Components and Props for customizing the component

Rate this page: