You are on page 1of 120

Table

of Contents

Overview
Introduction 1.1

Changelog 1.2
FAQ 1.3

User Guide
Getting Started 2.1

Layout Manager 2.2


Widget Manager 2.3
Sample Library 2.4

Sample Project 2.5


Default Layouts - Elite 2.6
Default Layouts - Oceana 2.7

Default Layouts - AACC 2.8

API Reference
Widget API Methods 3.1
onDataEvent 3.1.1

sendMessage 3.1.2
sendNotification 3.1.3
getConfiguration 3.1.4

getInteractionId 3.1.5

getWorkCardCount 3.1.6
getInteractionData 3.1.7

sendChatMessage 3.1.8

sendEmailMessage 3.1.9
removeEmailAttachment 3.1.10

reportChatTyping 3.1.11

startVoiceInteraction 3.1.12
acceptInteraction 3.1.13

holdInteraction 3.1.14

unholdInteraction 3.1.15
endInteraction 3.1.16

singleStepTransfer 3.1.17

2
consult 3.1.18
endConsult 3.1.19
completeTransfer 3.1.20

completeConference 3.1.21

getCapabilities 3.1.22
setTransferToServicesList 3.1.23

getDispositionCodes 3.1.24

setDispositionCode 3.1.25
getWorkCodes 3.1.26

setWorkCode 3.1.27

getNotReadyReasonCodes 3.1.28

getAdditionalWorkCodes 3.1.29
sendDTMF 3.1.30
insertMessageIntoResponseArea 3.1.31

insertContentIntoEmailBody 3.1.32
createCustomCard 3.1.33
updateCustomCard 3.1.34

deleteCustomCard 3.1.35
createCustomStatePanel 3.1.36
updateCustomStatePanel 3.1.37

deleteCustomStatePanel 3.1.38
updateMenuItems 3.1.39
searchEnterpriseDirectory 3.1.40

isEnterpriseContactsServiceAvailable 3.1.41
unregister 3.1.42
startWork 3.1.43

startWorkNotReady 3.1.44

setAgentReady 3.1.45
setAgentACW 3.1.46

finishWork 3.1.47

additionalWork 3.1.48
setAgentNotReady 3.1.49

bidi 3.1.50

forceReload 3.1.51
setFocus 3.1.52

Widget API Events 4.1

onInteractionEvent 4.1.1
onChannelStatusUpdateEvent 4.1.2

onUserTypingEvent 4.1.3

onEmailAttachmentUploadEvent 4.1.4

3
onFileUploadEvent 4.1.5
onFileTransferInitiatedEvent 4.1.6
onFileTransferCompleteEvent 4.1.7

onInteractionEndedEvent 4.1.8

onCRMDataEvent 4.1.9
onContextDataEvent 4.1.10

onMediaEvent 4.1.11

onMediaMessageEvent 4.1.12
onPagePushUrlEvent 4.1.13

onAgentStateEvent 4.1.14

onNavigationEvent 4.1.15

onLocaleUpdatedEvent 4.1.16
onBeforeTextDirectionChangedEvent 4.1.17
onStylesheetsReadyEvent 4.1.18

onObserveEvent 4.1.19
onRequestServicesEvent 4.1.20
onCapabilitiesEvent 4.1.21

onMessageEvent 4.1.22
onTeamMemberEvent 4.1.23
onEnterpriseContactsReceivedEvent 4.1.24

onEnterpriseServiceAvailableEvent 4.1.25
onEnterpriseServiceUnavailableEvent 4.1.26
onCustomCardDeletedEvent 4.1.27

onCardFocusedEvent 4.1.28
onSSOTokenRefreshEvent 4.1.29

Tools and Configuration


Widget Build Tools 5.1

Using Sample Library 5.2


Hosting Widgets 5.3

Widget Server Configuration 5.4

Capabilities 5.5
Using Web Components 5.6

Examples
Hello World 6.1

Widget Communication 6.2

Prompted Digits 6.3

Localisation 6.4

4
5
Introduction

Widget Framework Developer Documentation


Overview
The Widget Framework is a new feature that extends the customization capabilities of workspaces. By using this feature contact
centers will be able to:

customise the layout and behavior of Workspaces for an entire contact center.
have access to a Widget API so that developers can create custom widgets that can be configured and deployed in
workspaces.

Both of these features combined enable contact centers and Avaya customers to customise Workspaces to their business needs.

View Widget Framework Documentation in new tab

Important - Please read the Widget Build Tools and Change Log sections for each new release in order to ensure that you
are up to date with the latest changes. Otherwise, you may see that custom widgets will not load properly in Workspaces.

Note: This documentation is only available in English.

Links and Materials


Download the Sample Widget Library
Download the Sample Library Project
Download the Avaya Workspaces Widget Framework Documentation
View NEO CSS Framework documentation in new tab

6
Changelog

Widget Framework Changes

Release 3.7.0.0
Changes
Added the following property to the button object returned by createCustomCard or updateCustomCard method:
customCardId
Added the following Widget API methods:
bidi
setFocus
getWorkCardCount
Added the following Widget API events:
onBeforeTextDirectionChangedEvent
onStylesheetsReadyEvent
onCustomCardDeletedEvent
onCardFocusedEvent
onSSOTokenRefreshEvent
Added a new disableDefaultTabActivation property to the custom card object passed to the createCustomCard method

Release 3.6.1.0
Changes
Added the following Widget API methods:
sendEmailMessage
removeEmailAttachment
Added the following Widget API events:
onEmailAttachmentUploadEvent

Release 3.6.0.1
Changes
Added a new timeout property to the custom card object passed to the createCustomCard method
Removed the following deprecated events:
onCapabilitiesChangedEvent
onMediaDataEvent
Removed deprecated getCanStartVoiceInteraction method
Added the following Widget API methods:
updateMenuItems
sendChatMessage
reportChatTyping
getInteractionData
Added the following Widget API events:
onUserTypingEvent
onFileUploadEvent

7
Changelog

onFileTransferInitiatedEvent
onFileTransferCompleteEvent
Renamed isBeingObserved property passed within onInteractionEvent and onInteractionEndedEvent to isObserved
Extended onContextDataEvent with clientValidation data specifying max characters allowed when sending messages for
Chat, SMS or Social interactions
Added a new positionIndex property to the custom card object passed to the createCustomCard and updateCustomCard
methods

Release 3.6.0.0
Changes
Added the agent capabilities to the data passed in the [onAgentStateChangeEvent]
Added the following Widget API methods:
createCustomCard
updateCustomCard
deleteCustomCard
searchEnterpriseDirectory
isEnterpriseContactsServiceAvailable
getNotReadyReasonCodes
getAdditionalWorkCodes
startWork
startWorkNotReady
setAgentReady
setAgentACW
finishWork
additionalWork
setAgentNotReady
Added the following Widget API events:
onEnterpriseContactsReceivedEvent
onEnterpriseServiceAvailableEvent
onEnterpriseServiceUnavailableEvent
onInteractionEndedEvent
Added onPagePushUrlEvent to Widget API events. This was originally added as a 3.5.0.1 hotfix but was also ported forward
to 3.6.0.0.

Release 3.5.0.1
Changes
Added the following Widget API methods:
insertMessageIntoResponseArea
insertContentIntoEmailBody
Added the following new capabilities to the data passed in the onCapabilitiesEvent or the data returned by the getCapabilities
method:
canSendMessage
Added new push-suggested-responses sample widget to demonstrate usage of the insertMessageIntoResponseArea and
insertContentIntoEmailBody methods.
Added onPagePushUrlEvent to Widget API events.

8
Changelog

Release 3.5.0.0
Changes
Added the following Widget API methods:
getDispositionCodes
setDispositionCode
getWorkCodes
setWorkCode
sendDTMF
Added the following new capabilities to the data passed in the onCapabilitiesEvent or the data returned by the getCapabilities
method:
canSetDispositionCode
canSetWorkCode
canSendDtmf
Added the following new properties to the data passed in the onInteractionEvent:
skillId
topicId

New Core Widgets in 3.5.0.0


Customer Search - Agent can use this to Search for customer's that are stored in the CRM
Reporting Dashboard Manager - Reporting user can configure Dashboards
Reporting View Manager - Reporting user can create and edit views
Reporting Dashboard Viewer - Displays configured Dashboards
Reporting Calculated Measures - Reporting user can create and edit Calculated Measures to use in Report Views
Note - If custom layouts have been configured previous to upgrade, users will have to configure these widgets using
the Administrator layout manager .

Release 3.4.0.10
Changes
Added the following Widget API methods:
acceptInteraction
holdInteraction
unholdInteraction
endInteraction
singleStepTransfer
consult
endConsult
completeTransfer
completeConference
getCapabilities
Added onCapabilitiesEvent to Widget API events.
Added the following new properties to the data passed in the onInteractionEvent:

stateReason
interactionType
isCustomerInteraction

9
Changelog

isConsult
The getCanStartVoiceInteraction() Widget API method has been deprecated and will be removed in the next release.
Please use getCapabilities() instead.

The onCapabilitiesChangedEvent Widget API event has been deprecated and will be removed in the next release. Please
use onCapabilitiesEvent instead.

Release 3.4.0.1
Changes
Added onMediaEvent to Widget API events.
onMediaDataEvent has been deprecated and will be removed in the next release. Please use onMediaMessageEvent instead.

Added onRequestServicesEvent to Widget API events.


Added setTransferToServicesList Widget API method.
Added Admin Settings tab and Override Transfer to Service Destination List checkbox.
Added a Filtered Transfer To Service List sample widget to the sample widget library.
Removed sendTextEmailTemplate and sendHTMLEmailTemplate Widget API methods. These were used by an external
Email Templates widget which has now been changed to a core internal widget.

Release 3.4.0.0
Changes
Included the NEO CSS framework.
Added NEO CSS framework online documentation.
Improved Widget API online documentation.
Added 4 new widgets to the sample widget library.
Added a new project template to create widget library projects.
New Widget Manager UI added to Workspaces administrator
Added sendTextEmailTemplate and sendHTMLEmailTemplate Widget API methods to send custom email templates to the
Email widget.
Added getCanStartVoiceInteraction Widget API method to implement click-to-call functionality.
Added startVoiceInteraction Widget API method to implement click-to-call functionality.
Added onCapabilitiesChangedEvent Widget API event.
Added onTeamMemberEvent Widget API event to get team member data.

New Core Widgets in 3.4.0.0


Email templates - Used to inject email templates to the Email Widget.
Note - If a custom layout has been configured previous to upgrade, users will have to configure this widget using the
Administrator layout manager .

10
FAQ

Frequently Asked Questions (FAQ)


Where can I download the latest widget framework documentation?

The widget framework developer documentation can be downloaded directly from the Workspaces administrator log in. To access
the documentation, you will need access to a live contact center deployment and will have to log in to Workspaces as an
Administrator user (configured in ACM). Once logged-in, you can download the documentation and sample widget library by
clicking on the URL links in the Overview section of the Workspaces Administrator widget.

Can I write a widget that a supervisor can use to send messages to a widget used by agents?

No. Widget to widget communication is intended so that two or more widgets can communicate with each other within a single
instance of Workspaces and only when the agent is presented with a work card. For example, when an agent receives a call and
accepts the work card, two or more widgets can communicate and access details about the call and perform actions such as
querying a remote database or loading a web page, etc. Widget communication only occurs within the context of the work card,
which means that if an agent has several work cards, widgets can only communicate with each other and only within the bounds
of their own work card type (voice, chat, email, etc.)

How can I access the prompted digits from a customer call from a widget?

Prompted digits information is available in the "onInteractionEvent" which is documented in the Widget API.

How can I access an external CRM system from my widgets?

Widgets offer several options for integrating external systems such as CRM systems.

IFRAME - a simple widget can be written to encapsulate the CRM website in an IFRAME and make the CRM system
accessible via a web page.
REST API - If the CRM system has a REST API, a widget can be written to directly query the CRM's REST API, this
approach would be considered a pure client-side integration.
SALESFORCE - Workspaces comes with an in-built Salesforce CRM adapter that provides client-side integration out of the
box. Salesforce CRM data is available as a data object in the Widget API.
BACKEND - a custom CRM can be integrated as a Breeze snap-in and integrated with Workspaces via the UAC component
and Client JavaScript SDK, then this integration can be exposed in the Widget API in a similar fashion as the native
Salesforce CRM adapter.
PROXY - a custom CRM can be integrated via a Proxy REST API or a Proxy Web Application. A proxy REST API wraps an
existing CRM system and makes it REST capable so that widgets can access CRM data indirectly via the proxy. A proxy web
application is a simple web app/page that encapsulates the CRM interface and makes it accessible via an IFRAME indirectly
without blocking any content or permission restrictions.

How do I import a widget?

Each widget contains a configuration file in JSON format (e.g. hello-world.json ). This configuration file can be imported from
the Widget Manager section in the Workspaces Administrator.

Why do you use AngularJS for writing widgets? Can we use another framework?

Workspaces is written in AngularJS version 1.5.0. We do not support Angular 2. As a requirement, widgets need to be written as
AngularJS directives and because AngularJS is flexible, widgets could load external JavaScript code and HTML templates
developed in other frameworks (e.g. ReactJS, VueJS, etc). However, we don't recommend doing this because it contradicts the
philosophy of keeping widgets simple!

Is it all Angular JS and what release do we support? Does it have to be the release we support?

The latest AngularJS release we support in the widget framework is Angular JS version 1.5.0. The minimum AngularJS release
supported is 1.2.

11
FAQ

Are the widgets contained or can they use other features in Workspaces?

Widgets are bound to work cards in Workspaces. They can not access or use other Workspaces features unless that feature is
requested and supported by the UAC component in Breeze.

How do you generate the widget files?

There are no tools to generate the widget files in Workspaces 3.2/3.3. Instead, we recommend that developers modify the widgets
in the sample library and adapt them to their needs.

Where and how do you load widgets?

Core widgets like Chat, Email, Customer Details are bundled in Workspaces and do not need to be loaded, they are available by
default in every Workspaces version. External widgets need to be hosted on a remote web server via HTTPS with CORS enabled.
The URL for this web server needs to be configured so that Workspaces can load the widgets.

What are these widgets in Workspaces?

There are two types of widgets in Workspaces.

Core widgets - these are the default widgets provided in Workspaces and developed and supported by Avaya, for example the
Chat, Email, Customer Details widgets, etc. These widgets are bundled in every version of Workspaces.
External widgets - these are widgets developed by a third-party and maintained externally. These are typically widgets
written by Avaya customers. These widgets use the Widget Framework API and implement custom functionality (e.g.
integrate with customer infrastructure).

How do you localize a widget?

Localization support for external widgets is not supported in Workspaces 3.2/3.3/3.4

Can I access the Client JavaScript SDK from my widget?

Widgets don't have access to the Client JavaScript SDK directly.

How can my widget access a legacy application that it not web based?

Widgets are written using web technologies (JavaScript, HTML, CSS, JSON). You can still write a widget that implements a
screen sharing protocol such as VNC/RDP to access a legacy application that is not web based.

Can you load ActiveX controls, Flash or Java Applets inside widgets?

It is possible but not recommended as these are considered legacy web technologies prone to browser incompatibilities and
security issues.

Are widgets secure? Are there any risks of leaking data to unauthorized applications or users?

Widgets inherit the Browsers security model and security permissions of the underlying network and the security model of the
Workspaces solution. We recommend that the widget library is hosted on internal web servers only accessible from VPN or
restricted networks.

Do you provide custom CSS UI components such as buttons or forms that I can use in my widgets?

Custom CSS UI components are provided in Workspaces 3.4 via the NEO CSS Framework.

Can I import my own CSS style sheets and use them in my widgets?

Yes. Custom CSS style sheets can be used as long as they don't overwrite the global web font used by Workspaces or implement a
CSS reset.

Do you have examples of more complex widgets or larger applications integrated into Workspaces using the Widget API?

12
FAQ

Not at this moment. However, AWFOS is an application entirely written using the widget framework developed by an internal
team at Avaya. The sample widget library provided is intended to showcase the Widget API and most widgets are intentionally
simple.

13
Getting Started

Getting Started
Administrator User
To customize Workspaces, a new Administrator user role is required. This user can be created and configured in ACM (Avaya
Control Manager). The administrator user won't have access to any channels or any contact center features. The only purpose of
this user is to customize Workspaces.

Workspaces Administrator UI
Once the Administrator is created and configured, they can easily customize the layout of Workspaces via this Workspaces
Administrator UI.

Using this interface, an administrator user has access to the default layout configuration of Workspaces and can perform the
following actions:

customize the default home layout


customize the layout for the default channels (e.g. Voice, Chat, SMS, Email, Social)
customize the layout of "core" sidebar tabs and replace core widgets in any layout
add up to 2 additional custom sidebar tabs for each of the default channels
select from an existing list of pre-configured grid layouts and default widgets
configure which layouts are shown to agents and supervisors or both
import and export layouts into Workspaces
save and apply layout changes to all contact center users
reset layout changes to default configuration
view details of default Workspaces widgets
import and deploy externally developed widgets

Restrictions:

cannot delete core sidebar tabs


cannot delete core widgets

What can be customized


You can change the sidebar tabs
You can change the widgets that are displayed in the canvas area

What can NOT be customized


You cannot delete core tabs
You cannot add or delete new layouts for custom channels

14
Getting Started

15
Layout Manager

Layout Manager
You can choose to alter the layout based on role, interaction type or defaults. The following layouts can be customized:

Home: default layout presented when the user initially logs in or selects the home tab
Voice: layout presented when a Voice interaction is accepted
Webchat: layout presented when a Webchat interaction is accepted
Email: layout presented when an Email interaction is accepted
SMS: layout presented when an SMS interaction is accepted
Social: layout presented when a social interaction is accepted
Outbound: layout presented when an Outbound interaction is accepted
Video: layout presented when a Video interaction is accepted
Generic: layout presented when a Generic channel interaction is accepted

It is important to note that if you wish to change the layout for all interaction types, you will need to make the change in each
interaction type (i.e. changing the layout for Voice will not affect other interaction types)

Customizing layout sidebar options


After choosing a layout to customize you will be presented with the customize sidebar view. Here you can select your sidebar
options for the layout and add a new sidebar tab.

16
Layout Manager

The button will set the sidebar tab as the default for that layout. This tab will be selected when Workspaces enters
the context of the chosen layout. e.g For the voice layout - when a voice interaction is accepted.

Clicking the button allows the user to edit the properties of this sidebar tab.
Name
Description
Icon
Alignment
Role
Layout
Widgets

Note: only the Select Layout and Select Widgets properties can be set for core sidebar tabs (non custom tabs)

The button allows you to clone the sidebar tab, providing a starting point for a new sidebar tab. A new sidebar tab
will be appended to the bottom of the sidebar tab list.

The button removes the selected tab from the current layout.

Adding a new Sidebar Tab


Click on the Layout tab link.
Choose a layout you wish to add the Sidebar tab to.
Click "ADD NEW SIDEBAR TAB" button.

17
Layout Manager

On the Configuration tab:

Fill out the details of your new tab in the Sidebar Options panel.
Select the layout you want by clicking the radio button below the layout choices.
Click on each Widget area and select the desired Widget to be displayed in that position.

When complete click on the "SAVE CHANGES" button.

Your new Sidebar tab should now be available on the Customize Sidebar screen.

18
Layout Manager

The newly created Sidebar tab will now be visible on the Sidebar. The tooltip text will be displayed when the tab is hovered over.

Clicking on the new Sidebar tab will display the Widgets that were configured for the Sidebar tab in the main Context area of the
UI.

19
Layout Manager

Importing a Layout
Click on the Layout tab link.
Click on the "IMPORT LAYOUT" button. This will open your File Explorer.
Navigate to the location on your hard drive/storage to where a previously saved layout is located and import the file.
Your layout will be updated to the imported configuration.

Exporting a Layout
Click on the Layout tab link.
Click on the "EXPORT LAYOUT" button. This will download the layout to your downloads folder location.

Resetting a Layout to Default Configuration


If you do not wish to keep changes you make to the layout you have the option to reset to the default layout. This can be
performed by following these steps:

Click on the Layout tab link.


Click on the "RESET TO DEFAULT CONFIGURATION" button.
You will receive a confirmation dialog confirming you wish to reset the layout.
Click "OK".
The layout will be reset to the default settings.

20
Layout Manager

21
Widget Manager

Widget Manager
Sample Widget JSON

{
"metadata": {
"name": "Hello World",
"description": "Basic Hello world example",
"tags": "agent, demo, hello, world",
"library": "Sample",
"version": "1.0.0",
"date": "2017-02-14T23:24:41.230Z",
"id": "5e066f61-5794-4aab-bc1d-3dda05743062"
},
"configuration": {
"external": true,
"timeout": 5000,
"serie": true,
"name": "5e066f61-5794-4aab-bc1d-3dda05743062",
"element": "<hello-world></hello-world>",
"icon": "aoc-home",
"files": [
"hello-world/libs/external.js",
"hello-world/libs/miniq.js",
"hello-world/hello-world.css",
"hello-world/hello-world.js"
]
}
}

Importing a Widget
Rules:
A widget must contain the following properties: metadata.name , metadata.description , metadata.id ,
metadata.library , configuration.name , configuration.icon , configuration.element ;

Library name must be different than Workspaces ;


A widget can be added only once.
The widget must be imported from the bundle folder which contains the built/minified version of the widget.
Click on Widgets tab.
From the Widgets screen click on the "IMPORT WIDGET" button.

This will open your File Explorer.

Navigate to the location on your hard drive/storage where you saved your widget library and import the file the JSON file for
the hello-world widget.

Important - You must import the built/minified version of the widget from the bundle folder.

Once the widget is imported, you should be able to see it in the list of widgets.

22
Widget Manager

To Delete a Widget, click on the "REMOVE" icon on the Widgets list.

23
Sample Library

About the Sample Widget Library


We provide a sample widget library to give developers an overview of the Widget Framework. The sample widget library includes
several widgets that demonstrate some of the features of the Widget API.

The table below describes the list of widgets included in the sample widget library:

Widget Description

hello-world This widget demonstrates all the Widget API methods and Widget API events.

crm-
This widget demonstrates how to obtain customer history data from the Salesforce CRM system. Client
history-
will need to be successfully connected to Salesforce to use this widget.
timeline

email-
This widget demonstrates how to produce a word cloud visualization of the email text.
word-cloud

message-
This widget demonstrates how to use the Widget API for widget to widget communication.
echo

pdf-viewer This widget demonstrates how to load an external PDF document from an URL.

This widget demonstrates how to use the Widget API to fetch prompted digits information from a voice
prompt- work card. This widget needs to be configured on voice layout on a system that has CollectedDigits
digits configured in ACM : Oceana Core Data Service Collected Digits Key Note: The sample pdf provided
with the widget is for id: 1141

slide-share This widget demonstrates how to configure a slide share presentation using an iframe.

twitter-feed This widget demonstrates how to display a twitter live feed loaded using an iframe.

vimeo-
This widget demonstrates how to create a video player using the Vimeo service.
player

youtube-
This widget demonstrates how to create a video player using the YouTube service.
player

address-
This widget demonstrates searching the enterprise directory (LDAP)
book

google-
This widget hosts google maps within workspaces.
maps

transfer-to-
This widget demonstrates how to override the Transfer to Service List.
service-list

knowledge-
This widget demonstrates a knowledge base word cloud.
base

filtered-
transfer-to- This widget demonstrates how to override the Transfer to Service List.
service-list

single-step-
This widget demonstrates how to perform a single step transfer to an address.
transfer

interaction-
This widget demonstrates various interaction capabilities such as accept/hold/unhold/end/consult etc.
operations

interaction- This widget demonstrates how to handle and communicate with participants on Chat/SMS/Social
messenger interactions

electrical-
grid-line- This widget demonstrates some css animation.
checker

24
Sample Library

push-
This widget demonstrates how to insert messages into the response area on a Chat/SMS/Social widget and
suggested-
also how to insert HTML or Plain text into the Email widget.
responses

25
Sample Project

About the Sample Project


We provide a sample project template to help developers create a widget library project.

With this sample project template, developers will be able to:

Create widgets using the Grunt task runner


Compile, minify and bundle widgets for production use

The table below describes the contents of the sample project template:

Widget Description

Readme.md This file contains instructions on how to install and use the project template

Gruntfile.js This file is used by the Grunt task runner to create, compile and bundle widgets

package.json This file contains all the NodeJS package dependencies needed by the project template

View instructions on how to use the build tools and the sample project template

26
Default Layouts - Elite

Workspaces - Elite Contact Center Default layouts


Below is a description of default layouts in Workspaces for Elite. Each interaction type triggers its own default layout.
These can be changed using layout manager.

Default Canvas Widget Navigation Navigation Navigation


Screen
Widgets Layout Controls (Agent) (Supervisor) (Administrator)

Home
Team Same as
Customer
Viewer Agent +
Home n/a Search Same as Agent
Welcome My
Settings
Page Agents
Help

Home
Customer
Customer Details
Details Customer
Same as
Journey
Voice Agent +
Interaction n/a n/a
Interaction My
Details Screenpops
Agents
Customer
Customer Search
History Settings
Help

Home
Customer
Details
Tab for
parent
interaction
Same as
type
Customer Agent +
Customer n/a Customer n/a
Journey My
Journey Journey
Agents
Screenpops
Customer
Search
Settings
Help

Home
Customer
Details
Tab for
Open parent
Screenpop full interaction
Same as
screen type
Agent +
Screenpops If multiple Customer n/a
Screenpops My
screenpops Journey
Agents
toggle using
tabs Screenpops
Customer
Search
Settings
Help

Home
Customer
Search
Supervisor Review Analytics
Supervisor n/a n/a
Desktop Agent status My
Desktop
Agents
Settings
Help

27
Default Layouts - Elite

28
Default Layouts - Oceana

Workspaces - Oceana Contact Center Default layouts


Below is a description of default layouts in Workspaces for Oceana. Each interaction type triggers its own default layout.
These can be changed using layout manager.

Default Canvas Widget Navigation Navigation Navigation


Screen
Widgets Layout Controls (Agent) (Supervisor) (Administrator)

Home
Team Same as Agent
Viewer Customer +
Home n/a Same as Agent
Welcome Search Analytics
Page Settings My Agents
Help

Home

Customer
Details
Customer
Details
Customer Same as Agent
Voice Journey +
Interaction n/a n/a
Interaction Analytics
Details
Screenpops My Agents
Customer
Customer
History
Search
Settings
Help

Send
Home
message
Send
Customer
suggested
Details
phrase
Chat
Edit
Co-
suggested
Browse
Chat phrase before Same as Agent
sending +
Web Chat Customer n/a
Suggested If in Analytics
Journey
Content Conference: My Agents
Send
Screenpops
message to
Agents only
Customer
(Whisper)
Search
Send
Settings
message to all
Help
participants

Home

Customer
Details
Send SMS
SMS
Send
SMS suggested Same as Agent
Customer
phrase +
SMS Journey n/a
Suggested Edit Analytics
Content suggested My Agents
Screenpops
phrase before
sending
Customer
Search
Settings
Help

Home

29
Default Layouts - Oceana

Customer
Details
Email
Same as Agent
Email
Email Reply Customer +
Email n/a
[Read] Reply to all Journey Analytics
Templates
My Agents
Screenpops

Customer
Search
Settings
Help

Home

Customer
Details
Email
Same as Agent
Email Customer
Email +
Email Send Email Journey n/a
[Reply] Analytics
Templates
My Agents
Screenpops

Customer
Search
Settings
Help

Home

Customer
Details
Social
Social Same as Agent
Screenpops
+
Social Send Social n/a
Suggested Analytics
Customer
Content My Agents
Journey

Customer
Search
Settings
Help

Home

Customer
Outbound
Details Same as Agent
+
Outbound n/a Customer n/a
Interaction Analytics
Search
Details My Agents
Settings
Help
Outbound
Script

Home

Customer
Open Details
Screenpop full
Same as Agent
screen Customer +
Generic If multiple Journey n/a
Screenpops Analytics
screenpops
My Agents
toggle using Customer
tabs Search
Settings

30
Default Layouts - Oceana

Help

Home

Customer
Details

Mute Screenpops Same as Agent


Hide +
Video Video n/a
Picture In Customer Analytics
Picture Journey My Agents

Customer
Search
Settings
Help

Home

Customer
Details
Tab for
parent
interaction
type Same as Agent
Customer +
Customer n/a n/a
Journey Customer Analytics
Journey
Journey My Agents

Screenpops

Customer
Search
Settings
Help

Home

Customer
Details
Tab for
parent
Open
interaction
Screenpop full
type Same as Agent
screen
+
Screenpops If multiple n/a
Screenpops Customer Analytics
screenpops
Journey My Agents
toggle using
tabs
Screenpops

Customer
Search
Settings
Help

Home

Customer
Request Details
control from Tab for
user parent
Release interaction
Chat type
control to user Same as Agent
(mini
(if agent has +
Co-Browse view) Customer n/a
control) Analytics
Co- Journey
Refresh My Agents
Browse
End Co-
Browse Screenpops
Session

31
Default Layouts - Oceana

Session Customer
Search
Settings
Help

Home
Review
Customer
Agent status
Search
Supervisor Observe
Supervisor n/a Analytics n/a
Desktop Agent
Desktop My Agents
Barge In on
Settings
Agent
Help

Home
Dashboards
Home
(Edit Private /
Dashboards
Administer View Public)
(Public)
Dashboards Views (Edit
Views
Create Private / View
(Public)
Analytics Views n/a Public)
Analytics Calculated
Create Calculated
Measures
Calculated Measures (Edit
(Public)
Measures Private / View
Settings
Public)
Help
Settings
Help

32
Default Layouts - AACC

Workspaces - Avaya Aura Contact Center Default layouts


Below is a description of default layouts in Workspaces for AACC. Each interaction type triggers its own default layout.
These can be changed using layout manager.

Default Canvas Navigation Navigation Navigation


Screen Widget Controls
Widgets Layout (Agent) (Supervisor) (Administrator)

Home
Team
Viewer
Customer
Home n/a n/a Same as Agent
Search
Welcome
Settings
Page
Help

Customer
Home
Details
Voice Customer
Interaction n/a n/a n/a
Interaction Search
Details
Settings
Help
Customer
History

Send message
Send suggested
phrase
Edit suggested Home
Web
phrase before
Chat
sending Customer
Web Chat n/a n/a
If in Conference: Search
Suggested
Send message to Settings
Content
Agents only Help
(Whisper)
Send message to
all participants

Home
Reply Reply
Email Reply to all Customer
n/a n/a
[Read] Suggested Insert text into Search
Content email Settings
Help

Home
Email
Send Email
Email Customer
Insert text into n/a n/a
[Reply] Suggested Search
email
Content Settings
Help

Home

Customer
Details
Same as
Screenpops Agent +
Video Video Mute Analytics n/a
Hide Customer My
Journey Agents

Customer
Search
Settings
Help

33
Default Layouts - AACC

34
Widget API Methods

Widget API
The Widget API enables third-party developers to write custom widgets and deploy them in Workspaces. To write a custom
widget, you will need access to the Widget API Developer Documentation and code examples. The Widget API is designed to
make it easier for anyone with a basic understanding of HTML, CSS and JavaScript to write a custom widget and deploy it in
Workspaces.

To get developers started, we provide a sample widget library that can be deployed directly in Workspaces. The sample widget
library can be downloaded here. In the sample widget library, there are several example widgets that use the features of the Widget
API.

Widget API Methods


The following section provides descriptions and examples of each method in the Widget API. The examples are provided to give a
deeper understanding on how each method behaves. Alternative javascript patterns can be used at the developers discretion.

Please note, methods marked as 'Requires Interaction' require an interaction context. Any Widget leveraging these methods
will need to be placed on an Interaction related tab (e.g. Customer Details).

Constructor
Constructor method to initialize the Widget API (see examples in the sample widget library). The constructor returns a
reference to the Widget API object which can then be used to make API calls. The params object must be passed
automatically during the initialization stage of the widgetContainer (see code examples provided in the sample widget
library).

var api = new WidgetAPI(params);

onDataEvent(event, callback)
Allows the widget to subscribe to the various data events delivered by Workspaces. See the Widget API Events section for
the list of currently supported events.

This method accepts the following parameters:

event: This is the name of the event you want to subscribe to.
callback: a callback function which is fired once the event returns data.

var api = new WidgetAPI(params);


api.onDataEvent('onInteractionEvent', function (data) {
// Do something with the event data
console.log(data);
});

sendMessage(data, id)
Broadcasts a data event to all the widgets under the same interaction context. This method can be used for widget-to-
widget communication and to exchange data.

35
Widget API Methods

This method accepts the following parameters:

data: Text string or data object.


id (optional): id of a specific widget to send data to.

Note: this data will get broadcast on the onMessageEvent. For details see Widget API Events.

// Using a text string (multicast)


api.sendMessage('Hello there!');

// Using a data object (multicast)


api.sendMessage({ name: 'Joe Doe', age: 32 });

// Send the message using the ID string 'unique-random-id' (unicast)


api.sendMessage({ account: 'ACC-8437' }, 'unique-random-id');

sendNotification(level, message)
Displays a notification message in Workspaces. This method sends and displays the message as a "toast" notification.

This method accepts the following parameters:

level: type of message (info, warning, error)


message: text string representing the notification

api.sendNotification('info', 'This is a sample notification.');

getConfiguration()
This method returns configuration information relevant to the current Workspaces session for a Workspaces User. The
following information is provided:

user ID
station ID
user
display name
user first name
user last name
user handle
user state
authentication token (JWT)
current locale
user settings
user POM settings*

Note: A Workspaces User is considered to be either an "Agent" or "Supervisor".

*user POM settings are only available to POM enabled Agents

var config = api.getConfiguration();

36
Widget API Methods

Payload

{
"agentId": "10003",
"stationId": "1003",
"displayName": "John Costello",
"firstName": "John",
"lastName": "Costello",
"handle": "johnCostello",
"token": "Bearer
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2huQ29zdGVsbG8iLCJpYXQiOjE1MDY1MT
ExOTIsImV4cCI6MTUwNjc3MDM5Mn0.eDl3y4NQfWQBeXx8R0m7uwFXE6HXdsuNr3avaBtIJhKr4pLW-
9SypDIaWNtz7TI8S-
VN9AtDlt6LIGiMm_l0hyPrcLTpO9EmT0GTXMOZlL45G5uork8FW_1tCujaCh8N4fgPZeXgkHcxjBTdnexxn
HJ1Vqriu3n_r6J7XlmOcM5nUekIy8hItKE3Z-
SsbcV7LjqG9T8oWM3nSXPYrdnWvn7i30JDQf_z4l3etBes_t_3BX1mTDhWdCMNUIBIB0qVE7SmnKqOHyyec
ilkHxCYWl-
4v73FxTcpyLI6RGD_3Uy3EFXDo60SMr7TzctmnKlTiS4lzMFeFpe12CGQDUyuSGDQDH0n5D4wESF-
Fgd8GAhvVRh1yqdwEOIxAtWDlS-
7jdjwOgc9HK0jPQCnKchlwcSPNP9HJsFGks65tZbDqmYUvvfBLmEvhhWQR36ksVDnYl1-
sq1yWDuQJGDzNPGrKFzgThfIkZSF2EmHI2qTOP959ZLibFx8jrBA1epK2o6-
F7tJ7a5SZGWCJJDL5GWGhmGa58429zk49vUS5h01j_ajvgfNxF__MFnUvRbgOjPhEfXw4-
eVEgXLe9p3FOpHdu4cKsByXL_Yew5G9NYeL9l13Wh8fokZ9OiJkhNFF7B_UboIsbbwA6gSvZ8gxWENaIm6F
MGD3Hh5EZ3Uq5KZ2Uw",
"state": "READY",
"channels": {
"VOICE": {
"state": "READY",
"stateReason": "DEFAULT",
"capabilities": {
"canSetCallForwarding": true,
"canCancelCallForwarding": true,
"canStartInteraction": true,
"canStartSupervisorInteraction": true
}
},
"WEBCHAT": {
"state": "READY",
"stateReason": "DEFAULT",
"capabilities": {
"canSetCallForwarding": false,
"canCancelCallForwarding": false,
"canStartInteraction": false,
"canStartSupervisorInteraction": false
}
},
"EMAIL": {
"state": "READY",
"stateReason": "DEFAULT",
"capabilities": {
"canSetCallForwarding": false,

37
Widget API Methods

"canCancelCallForwarding": false,
"canStartInteraction": true,
"canStartSupervisorInteraction": false
}
},
"SMS": {
"state": "READY",
"stateReason": "DEFAULT",
"capabilities": {
"canSetCallForwarding": false,
"canCancelCallForwarding": false,
"canStartInteraction": false,
"canStartSupervisorInteraction": false
}
},
"SOCIAL": {
"state": "READY",
"stateReason": "DEFAULT",
"capabilities": {
"canSetCallForwarding": false,
"canCancelCallForwarding": false,
"canStartInteraction": false,
"canStartSupervisorInteraction": false
}
},
"VIDEO": {
"state": "READY",
"stateReason": "DEFAULT",
"capabilities": {
"canSetCallForwarding": true,
"canCancelCallForwarding": true,
"canStartInteraction": true,
"canStartSupervisorInteraction": true
}
},
"GENERIC": {
"state": "READY",
"stateReason": "DEFAULT",
"capabilities": {
"canSetCallForwarding": true,
"canCancelCallForwarding": true,
"canStartInteraction": true,
"canStartSupervisorInteraction": true
}
}
},
"locale": {
"id": "en-us",
"label": "English (US)",
"textDirection": "ltr",
"textAvatar": true,

38
Widget API Methods

"stringsVersion": "1"
},
"settings": {
"awfosEnabled": true,
"coBrowseURL": "10.134.146.163",
"coBrowseFQDN": "10.134.146.163",
"contextStoreClusterIP": "ocdsFQDN",
"ocdsFQDN": "ocdsFQDN",
"customerManagementFQDN": "10.134.146.40",
"aawgFQDN": "aawgFQDN",
"ocpAddress": "10.134.146.28",
"ocpFQDN": "10.134.146.28",
"hotdesk": false,
"isWebRTC": false,
"observeIndicatorEnabled": true,
"salesforceConfiguration": {
"ApplicationName": "CC_Client",
"ConsumerKey":
"3MVG98_Psg5cppyYaaOW5FZdV8rTYZuaYxGoP4wz97OSfkLYl0EBZrXQ3B8lbWPqs5NAcPAOi5rPdpD4vP
9nd",
"ConsumerSecretKey": "3723015645493377233",
"CRMIntegrationEnabled": "true",
"ProxyServerURL": "http://10.134.138.178:9090",
"SalesforceEndpoint": "https://eu6.salesforce.com"
},
"screenPopConfiguration": {
"DisplayInternalScreenpopWidgetFirstOnAgentAccept": "false",
"EnableScreenpopWithoutAgentprompting": "false",
"LaunchExternalScreenpopsOnAgentAccept": "false"
},
"welcomePage": "assets/pages/iframe.html",
"supervisorReportingURL": "assets/pages/iframe.html",
"workspacesLoggingEnabled": false,
"workspacesLoggingLevel": "",
"workspacesLogUploadLocation": "https://10.134.138.178:8443/upload",
"websocketsEnabled": true,
"genericChannelFriendlyName": "TestChannel",
"genericChannelIcon": "aoc-custom01",
"clockDriftMillis": 155
}
},
"pomSettings": {
"widgetDownloadLocation": "https://widgetDownloadLocation/",
"widgetPrimaryAddress": "https://widgetPrimaryAddress/",
"widgetPrimaryPort": "1234",
"widgetSecondaryAddress": "https://widgetSecondaryAddress/",
"widgetSecondaryPort": "2345",
"pomOrganizations": [{
"organization": "org1",
"zones": ["zone1", "zone2"]
}, {

39
Widget API Methods

"organization": "org2",
"zones": ["zone3", "zone4"]
}]
}
}

getInteractionId()
This method returns the Interaction ID for the active interaction.

Note: Requires Interaction

// Returns the interaction ID as string, e.g. fbeca6e2-2b8c-45e6-bc54-55e2b96799b7


var id = api.getInteractionId();

getWorkCardCount()
This method returns the number of interactions.

// Returns interaction count as a number, e.g. 2


var interactionCount = api.getWorkCardCount();

getInteractionData()
This method returns the interaction related data (same as what you get using onInteractionEvent)

Note: Requires Interaction

// Best to use on your widget initialization


var data = api.getInteractionData();

See payload of sample data which would be returned by calling api.getInteractionData() :

Payload

{
"id": "f775be25-68a0-4c54-9b10-a24f6cc4b5ff",
"workRequestId": "0085617462979956890064",
"externalInteractionId": "-2694020189_9f88add7-0f0d-4708-aec9-b6cc8b740554",
"channel": "SMS",
"state": "ACTIVE",
"stateReason": "DEFAULT",
"interactionType": "CALLED",
"title": "(212) 842-5599",
"topic": "Oceana Service",
"topicId": "3007",
"skill": null,
"skillId": null,

40
Widget API Methods

"direction": "INCOMING",
"isCustomerInteraction": false,
"isWebRtcCall": false,
"userToUserInfo": null,
"isConsult": false,
"originatingAddress": "(212) 842-5599",
"destinationAddress": "1001",
"isObserved": false,
"contactId": "lHu1kWd6xBhjp7mifzcCJI"
}

See the interaction-messenger sample widget for further demonstration.

sendChatMessage(message)
Sends text message into an interaction on behalf of current agent.

This method will only execute if the capabilities.interaction.canSendMessage capability is set to true . Please see
Capabilities for more information.

Note: Requires Interaction

Note: This method is restricted to be invoked no more than once per 1 second due to security restrictions

This method accepts the following parameters:

message: the message text.

// Send a message to customer from current agent


api.sendChatMessage('Test message');

See the interaction-messenger sample widget for further demonstration.

sendEmailMessage(emailData)
Sends text message into an interaction on behalf of current agent.

This method will only execute if the capabilities.interaction.canSendMessage capability is set to true . Please see
Capabilities for more information.

Note: Requires Interaction

Note: This method is restricted to be invoked no more than once per 1 second due to security restrictions

This method accepts the following parameters:

emailData: The data object.

The emailData object passed to sendEmailMessage method can contain the following properties...

Parameter Type Required? Description

to array of strings Yes Letter recipient

message string Yes Body of email message

41
Widget API Methods

from string No Mail sender

subject string No Subject of email

cc array of strings No Carbon copy

bcc array of strings No Blind carbon copy

// Using a emailData object (multicast)


api.sendEmailMessage({to: ['user1@example.com'], message: 'Test message'});

removeEmailAttachment(attachment)
Remove email attachment by attachment id.

This method accepts the following parameters:

attachment: The data object.

The attachment object passed to removeEmailAttachment method can contain the following properties...

Parameter Type Required? Description

id of Attachment (in attachment object, field 'partId', like '7C1CA22F-B572-


id string Yes
4FF5-9DF6-01C4370C7E3D')

// Using a emailData object (multicast)


api.removeEmailAttachment({ id: '7C1CA22F-B572-4FF5-9DF6-01C4370C7E3D' });

reportChatTyping()
Sends a typing notification to other participants

Note: Requires Interaction

Note: This method is restricted to be invoked no more than once per 6 seconds due to security restrictions

Note: In order to prevent "is typing..." label flickering on side of customer, make sure to invoke this method once per 6
seconds during user is typing.

// Define api.reportChatTyping throttle (best to use!) wrapper


var reportChatTypingThrottle = _.throttle(api.reportChatTyping, 6000, {leading: true, trailing: false});

// Listen to keydown event on input and call reportChatTypingThrottle each time user presses any key
document.querySelector('input[type=text]').addEventListener('keydown', reportChatTypingThrottle);

See the interaction-messenger sample widget for further demonstration.

startVoiceInteraction(address)
Starts an outbound voice interaction.

42
Widget API Methods

This method will only execute if the capabilities.channels.canStartVoiceInteraction capability is set to true .
Please see Capabilities for more information.

This method accepts the following parameters:

address: the address that will be used to initiate the outbound voice interaction.

// Make a voice call


api.startVoiceInteraction('3156');

See the address-book sample widget for further demonstration.

acceptInteraction()
Accepts an altering interaction.

This method will only execute if the capabilities.interaction.canAccept capability is set to true . Please see
Capabilities for more information.

Note: Requires Interaction

Note: This method is only applicable in an Elite environment where the widgets are displayed while an interaction is
altering.

api.acceptInteraction();

See the interaction-operations sample widget for further demonstration.

holdInteraction()
Holds an active interaction.

This method will only execute if the capabilities.interaction.canHold capability is set to true . Please see
Capabilities for more information.

Note: Requires Interaction

api.holdInteraction();

See the interaction-operations sample widget for further demonstration.

unholdInteraction()
Unholds a held interaction.

This method will only execute if the capabilities.interaction.canUnhold capability is set to true . Please see
Capabilities for more information.

Note: Requires Interaction

api.unholdInteraction();

43
Widget API Methods

See the interaction-operations sample widget for further demonstration.

endInteraction()
Ends the active interaction.

This method will only execute if the capabilities.interaction.canEnd capability is set to true . Please see
Capabilities for more information.

Note: Requires Interaction

api.endInteraction();

See the interaction-operations sample widget for further demonstration.

singleStepTransfer(address)
Performs a single step transfer to an address.

This method will only execute if the capabilities.interaction.canSingleStepTransfer capability is set to true .
Please see Capabilities for more information.

This method accepts the following parameters:

address: The address that will be used to transfer to.

Note: Requires Interaction

// Single step transfer to an address


api.singleStepTransfer('3156');

See the single-step-transfer sample widget for further demonstration.

consult(address, uui)
Initiates a consult to an address.

This method will only execute if the capabilities.interaction.canConsult capability is set to true . Please see
Capabilities for more information.

This method accepts the following parameters:

address: The address that will be used to consult.


uui (optional): Used to update the 'User-to-User Info' while initiating a consult.

Note: Requires Interaction

// Consult an address
api.consult('3156');

// Consult an address and update the uui


api.consult('3156', 'test uui');

44
Widget API Methods

See the interaction-operations sample widget for further demonstration.

endConsult()
Ends the consultative leg of an interaction.

Note: Requires Interaction

// End the consult


api.endConsult();

See the interaction-operations sample widget for further demonstration.

completeTransfer()
Transfers the interaction to the consulted address.

This method will only execute if the capabilities.interaction.canTransferComplete capability is set to true . Please
see Capabilities for more information.

Note: Requires Interaction

// Complete the transfer


api.completeTransfer();

See the interaction-operations sample widget for further demonstration.

completeConference()
Completes the consult as a conference.

This method will only execute if the capabilities.interaction.canConferenceComplete capability is set to true .
Please see Capabilities for more information.

Note: Requires Interaction

// Complete the conference


api.completeConference();

See the interaction-operations sample widget for further demonstration.

getCapabilities()
Gets the latest capabilities for the active interaction and agent channels.

// Get all capabilities


var capabilities = api.getCapabilities();

45
Widget API Methods

// Check if a voice interaction can be initiated


var canStartVoiceInteraction = api.getCapabilities().channels.canStartVoiceInteraction;

See payload of sample data which would be returned by calling api.getCapabilities() :

Payload

{
interaction: {
canAccept: false,
canEnd: true,
canHold: true,
canUnhold: false,
canSingleStepTransfer: true,
canConsult: true,
canTransferComplete: false,
canConferenceComplete: false,
canSetDispositionCode: true,
canSetWorkCode: true,
canSendDtmf: true,
canSendMessage: true
},
channels: {
canStartVoiceInteraction: true
}
}

See the address-book sample widget for further demonstration.

setTransferToServicesList
Allows the setting of a custom list of transfer to service destinations in the Workspaces work card. This method expects an
array of services that will be displayed on the Transfer to Service dropdown list on an interaction's work card. In order for a
Transfer to work the services must already exist in UCA. It is expected that the widget developer will retrieve this list from
UCA and filter the services list inside the widget. See filtered-transfer-to-service-list sample widget for further
demonstration.

// The following list of services is only an example. In order for a Transfer to work the services must already
exist in UCA.
// In the real world this list of services will not be hardcoded, it will be retrieved from UCA and then filter
ed by the widget developer.
var services = [{
"id" : "Language.Irish|Service.TechnicalSupport",
"name" : "IrishVoiceTransferToService"
}, {
"id" : "Language.English|Service.TechnicalSupport",
"name" : "EnglishVoiceTransferToService"
}];
api.setTransferToServicesList(services);

getDispositionCodes(channelType)

46
Widget API Methods

Gets a list of all disposition codes if any are configured. By default this method will return all disposition codes configured
for all channel types. However, it is possible to receive a filtered list by passing a valid channelType as an argument. i.e
VOICE, EMAIL, CHAT, SMS, SOCIAL.

// Get all disposition codes


var dispositionCodes = api.getDispositionCodes();

// Get disposition codes for the voice channel


var dispositionCodes = api.getDispositionCodes('VOICE');

// Get disposition codes for the current channel using onInteractionEvent


api.onDataEvent('onInteractionEvent', function(data) {
scope.dispositionCodes = api.getDispositionCodes(data.channel);
});

This method accepts the following parameters:

channelType (optional): A channel type. This will result in the method returning a filtered list of disposition codes
which have been assigned to this channel type.

See payload of sample data which would be returned by calling api.getDispositionCodes() :

Payload

[
{
"code": "5645",
"friendlyName": "Report to Supervisor",
"type": "DISPOSITION",
"channels": [
"SMS",
"WEBCHAT"
]
},
{
"code": "3534",
"friendlyName": "Offer discount on next call",
"type": "DISPOSITION",
"channels": [
"VOICE",
"SMS",
"EMAIL",
"WEBCHAT"
]
}
]

See the interaction operations or hello-world sample widgets for further demonstration.

setDispositionCode(code)

47
Widget API Methods

Sets a disposition code on the interaction.

This method will only execute if the capabilities.interaction.canSetDispositionCode capability is set to true .
Please see Capabilities for more information.

This method accepts the following parameters:

code: The disposition code to set.

Note: Requires Interaction

// Set a disposition code


api.setDispositionCode('7764');

See the interaction-operations sample widget for further demonstration.

getWorkCodes(channelType)
Gets a list of all work codes if any are configured. By default this method will return all work codes configured for all
channel types. However, it is possible to receive a filtered list by passing a valid channelType as an argument. i.e VOICE,
EMAIL, CHAT, SMS, SOCIAL.

// Get all work codes


var workCodes = api.getWorkCodes();

// Get work codes for the voice channel


var workCodes = api.getWorkCodes('VOICE');

// Get work codes for the current channel using onInteractionEvent


api.onDataEvent('onInteractionEvent', function(data) {
scope.workCodes = api.getWorkCodes(data.channel);
});

This method accepts the following parameters:

channelType (optional): A channel type. This will result in the method returning a filtered list of work codes which
have been assigned to this channel type.

See payload of sample data which would be returned by calling api.getWorkCodes() :

Payload

[
{
"code": "7277",
"friendlyName": "Breakfast",
"type": "WORK",
"channels": [
"VOICE"
]
},
{
"code": "7777",
"friendlyName": "Sales",

48
Widget API Methods

"type": "WORK",
"channels": [
"VOICE",
"SMS",
"EMAIL",
"WEBCHAT"
]
},
{
"code": "8888",
"friendlyName": "Support",
"type": "WORK",
"channels": [
"EMAIL"
]
}
]

See the interaction operations or hello-world sample widgets for further demonstration.

setWorkCode(code)
Sets a work code on the interaction.

This method will only execute if the capabilities.interaction.canSetWorkCode capability is set to true . Please see
Capabilities for more information.

This method accepts the following parameters:

code: The work code to set.

Note: Requires Interaction

// Set a work code


api.setWorkCode('3633');

See the interaction-operations sample widget for further demonstration.

getNotReadyReasonCodes()
Gets a list of all Not Ready reason codes if any are configured.

// Get all Not Ready reason codes


var workCodes = api.getNotReadyReasonCodes();

See payload of sample data which would be returned by calling api.getNotReadyReasonCodes() :

Payload

[
{

49
Widget API Methods

"code": "1234",
"friendlyName": "Bathroom",
"type": "NOT_READY",
"channels": []
},
{
"code": "4567",
"friendlyName": "Break",
"type": "NOT_READY",
"channels": []
},
{
"code": "6785",
"friendlyName": "Meeting",
"type": "NOT_READY",
"channels": []
}
]

See the hello-world sample widgets for further demonstration.

getAdditionalWorkCodes()
Gets a list of all Additional Work codes if any are configured.

// Get all Not Ready reason codes


var workCodes = api.getAdditionalWorkCodes();

See payload of sample data which would be returned by calling api.getAdditionalWorkCodes() :

Payload

[
{
"code": "999",
"friendlyName": "Additional Work",
"type": "ADDITIONAL_WORK",
"channels": []
}
]

See the hello-world sample widgets for further demonstration.

sendDTMF(digit)
Sends a DTMF digit.

This method will only execute if the capabilities.interaction.canSendDtmf capability is set to true . Please see
Capabilities for more information.

50
Widget API Methods

This method accepts the following parameters:

digit: The DTMF digit to be sent. Only values 0-9 , * and # are accepted.

Note: Requires Interaction

// Set a work code


api.sendDTMF('1');

See the interaction-operations sample widget for further demonstration.

insertMessageIntoResponseArea(message)
Inserts a message into the response area (input box) located on the Chat/SMS/Social widget.

This method will only execute if the capabilities.interaction.canSendMessage capability is set to true . Please see
Capabilities for more information.

This method accepts the following parameters:

message: The message to insert.

Note: Requires Interaction

// Insert a message into the response area


var message = 'Can you please send us your policy number?'
api.insertMessageIntoResponseArea(message);

See the push-suggested-responses sample widget for further demonstration.

insertContentIntoEmailBody(encoding, content, subject)


Inserts HTML or Plain Text content into the Email body located on the Email widget.

This method will only execute if the capabilities.interaction.canSendMessage capability is set to true . Please see
Capabilities for more information.

This method accepts the following parameters:

encoding (required): The encoding of the Email. Values accepted are either 'HTML' or 'PLAIN'.
content (optional): The content to be inserted into the Email body. This is left optional so that the method can still be
called to show the Email editor screen.
subject (optional): The subject to be inserted into the Email body.

Note: Requires Interaction

scope.htmlContent = '<p>Hi Mary,</p><br><p>Can you please send me your policy number?</p>';


scope.plainTextContent = 'Here be plain text!';
scope.subject = 'Sample subject';

// Media data from chat, sms, email, social


api.onDataEvent('onMediaMessageEvent', function(data) {
encoding = data.encoding;
scope.isHTMLEmail = data.encoding === 'HTML';
});

51
Widget API Methods

// Insert HTML and a subject into the Email widget


api.insertContentIntoEmailBody('HTML', htmlContent, subject);

// Insert Plain Text with no subject into the Email widget


api.insertContentIntoEmailBody('PLAIN', plainTextContent, '');

See the push-suggested-responses sample widget for further demonstration.

Note: you can use the onMediaMessageEvent to retrieve the encoding of the current Email interaction. For details see the push-
suggested-responses sample widget.

createCustomCard(data)
This method allows 3rd party developers to create work cards that will appear in the work card area in Workspaces. These custom
cards will appear similar to existing work cards but can be customized to suit the requirements of a 3rd party widget developer
looking to integrate Workspaces with an external work provider. These custom work cards will always be displayed to the right of
Contact Center work cards. There has been a limit of 3 set on the maximum number of custom work cards that can be displayed in
Workspaces at any one time. This is configurable up to 10 in the Administrator settings. Each top-level button will have an icon
and a title. A button can define an optional property 'color' which adds a background color to the icon (green, yellow, red or
blue). An optional 'action' property can also be added to a button to trigger a callback function when the button is clicked. A
maximum of 6 top-level buttons can be displayed on the custom card at any one time. A developer can create a dropdown menu
button by setting the isContextMenu property to true and defining a list of menu items and sub-menu items. Menu items can have a
title, a tooltip, an action and an array of subMenusItems. There are some limitations with these drop-down menus. Please refer to
the 'Menu Limitations' note below. The data sent to the API to create a custom work card needs to be localised by the calling 3rd
party widget. The API will enforce validation of the JavaScript object to ensure it can be displayed in the card. It is up to the 3rd
party widget to maintain the buttons as the card changes state.

Note: For Custom Cards to work with Customer Journey, it is required that the interactionData.state property is set to 'ACTIVE'
while the card is in an active state, as Customer Journey will only be initialised if this property is set to 'ACTIVE'

Menu Limitations: For the context menu buttons, there are some limitations that a developer should be aware of. If a developer
chooses to configure the parent menu to have sub-menu items, there will be no search field on the parent menu. Searching on a
first-level dropdown menu is only supported if the menu is configured to have no sub-menus. Searching in a sub-menu is
supported. So developers can create two types of dropdown menus: A menu with no sub-menus and a search input field or a menu
with sub-menus (searching supported within the sub-menus) and no search input field. Menu items that contain sub-menus are
limited to 5 per parent menu. Sub-menus or first-level menus without sub-menus will display a maximum of 20 items at a time.
There will be searching provided on these types of menus to further refine the list.

Creates a custom Card that will be displayed in the Work Card Area in Workspaces. This method accepts the following
parameters:

data (required): A JavaScript Object used to configure the content, behaviour and look of the Custom Card

The data object passed to createCustomCard method can contain the following properties...

Parameter Type Required? Description

id string Yes Unique ID of custom card

title string Yes Title to display on Custom Card header

titleTooltip string No Text to display on hover over of title

Class name of icon to display in Custom Card


icon string Yes
header (see neo framework for possible values)

iconTooltip string No Text to display on hover over of icon in header

52
Widget API Methods

Name of color to display in Custom Card header


color string No
Possible values: ['green', 'yellow', 'red', 'blue']

summary string No Text to display in card context area

Optional text to display at top of Custom Card


legTitle string No
context area

Optional class name of icon to display beside


legTitleIcon string No
legTitle

legTitleTooltip string No Optional text to display on hover of legTitle

Date/Time of when Custom Card was established


establishedTime date No
(displays timer)

updatableTimer boolean No If timer can be restarted or not

countdownTimer boolean No Is the timer a countdown timer

Duration in milliseconds that the timer will count


countdownDuration number No
down from, if countdownTimer is set to true

Array of Buttons to display in Custom Card


buttons button[] Yes
action area

Object containing card data properties


Possible values: See onInteractionEvent payload
interactionData object No
in the Widget API Events section for possible
object properties

true/false value to determine if the card is focused


focusOnCreated boolean No
automatically on card creation

Timeout value in milliseconds for the context


menu to wait for data to be returned. Set to 8
menuTimeout number No
seconds by default. Only applicable if using
updateMenuItems API method

Array of keyboard shortcuts and associated


customShortcuts customShortcut[] No
actions to associate with the card

true/false value to determine if the default tab is


disableDefaultTabActivation boolean No
rendered automatically on card focus

Where a button object is in the following format...

Parameter Type Required Description

title string Yes Text to display on hover over of button

Class name of icon to display for button (see neo framework


icon string Yes
for possible values)

Name of color to use for button


color string Yes
Possible values: ['green', 'yellow', 'red', 'blue']

No - Property
available on Custom Card ID to give button access to which card button is
customCardId string
button callback attached to
object

Callback executed when button has been clicked. Note: Action


action function No callbacks triggered when a dropdown menu is opened only
support calls to api.updateMenuItems

Button will be a dropdown menu and should contain


isContextMenu boolean No
menuItems

53
Widget API Methods

No/ Yes if
menuItems menuItem[] isContextMenu Array of menu items to display in drop down list
is true

Input with a button icon. If set, will be placed at the top of the
inputWithButton object No
context menu. Can be used only if isContextMenu is true.

Unique index ranging from 1 to 6 used to determine position of


positionIndex string Yes button. Button will not display unless a valid index is specified.
If 2 buttons have the same index, only the first will display.

A unique ID that can be assigned to a button. Used when


uniqueIdentifier string No
defining customShortcuts to trigger a button click

Where a menuItem object is in the following format...

Parameter Type Required Description

title string Yes Text to display on menu item

tooltip string No Text to display on hover over of menu item

action function No Callback executed when menu item has been clicked

Array of subMenuItems to display in sub-menu of parent menu


subMenuItems subMenuItem[] No
item

Where a subMenuItem object is in the following format...

Parameter Type Required Description

title string Yes Text to display on sub-menu item

tooltip string No Text to display on hover over of sub-menu item

action function No Callback executed when sub-menu item has been clicked

Where an inputWithButton object is in the following format...

Parameter Type Required Description

placeholder string Yes Text to display as input placeholder

buttonIcon string Yes Icon to display as button

buttonTooltip string No Text to display on hover over of button icon

Callback executed when button has been clicked. Input value is passed as
action function Yes
callback's parameter

Where a customShortcut object is in the following format...

Parameter Type Required Description

combo string Yes A white listed keyboard shortcut i.e 'Ctrl + Shift + h'

Callback executed when button has been clicked. Cards value is passed
action function No
as callback's parameter

buttonIdentifier string No The uniqueIdentifier of the button to click

Where a keyboard shortcut is included in the following list...

Shortcut

Ctrl then a

54
Widget API Methods

Ctrl then x

Ctrl + Shift + h

Ctrl then h

Ctrl then t

Ctrl + Shift + m

Ctrl then d

Ctrl then c

Ctrl then g

Ctrl then e

Ctrl then z

Ctrl then u

Ctrl then o

Ctrl then b

Ctrl then 1

Ctrl then 2

Ctrl then 3

Ctrl then 4

Ctrl then 5

Ctrl then 6

Ctrl then 7

Ctrl then 8

Ctrl then 9

Ctrl then 0

// The following is an example of how to create a custom card


api.createCustomCard({
id: 'id',
title: 'title',
titleTooltip: 'titleTooltip',
icon: 'icon',
iconTooltip: 'iconTooltip',
summary: 'summary',
menuTimeout: 10000,
legTitle: 'legTitle',
legTitleIcon: 'legTitleIcon',
legTitleTooltip: 'legTitleTooltip',
establishedTime: new Date(),
updatableTimer: true,
countdownTimer: false,
countdownDuration: 30000,
customShortcuts:[{
combo: 'Ctrl + Shift + h',
buttonIdentifier: 'buttonToClick',
action: function (data) {
api.sendNotification('info', data.title + ' passed to callback');
}
}],

55
Widget API Methods

buttons: [{
title: 'accept',
positionIndex: '1',
icon: 'aoc-accept-call',
color: 'green',
uniqueIdentifier: 'buttonToClick',
action: function (data) {
console.log('accept clicked');
api.sendNotification('info', 'The button is attached to ' + data.customCardId);
}
},{
title: 'button-2',
positionIndex: '2',
icon: 'aoc-hold',
isContextMenu: true,
inputWithButton: {
placeholder: 'Input field',
buttonIcon: 'aoc-voice-active',
buttonTooltip: 'My purpose here is to submit the input field value',
action: function (value) {
api.sendNotification('info', value + ' submitted');
}
},
menuItems: [{
title: 'dropdown-menu-item-1',
tooltip: 'tooltip-dropdown-menu-item-1',
action: function () {console.log('dropdown-menu-item-1 clicked')}
},{
title: 'dropdown-menu-item-2',
action: function () {console.log('dropdown-menu-item-1 clicked')}
}]
}],
interactionData: {
workRequestId: '23498734598723049'
},
focusOnCreated: true
});

updateCustomCard(data)
This method allows 3rd party developers to update existing custom work cards. Throttling of one update per second is enforced on
custom card updates to ensure better rendering performance and to prevent flickering or unwanted UI artifacts.

Updates an existing custom Card that is displayed in the Work Card Area in Workspaces. This method accepts the
following parameters:

data (required): A JavaScript Object used to configure the content, behaviour and look of the Custom Card

The data object passed to updateCustomCard method can contain the following properties...

Parameter Type Required? Description

id string Yes Unique ID of custom card

title string No Title to display on Custom Card header

titleTooltip string No Text to display on hover over of title

Class name of icon to display in Custom Card header (see


icon string No
neo framework for possible values)

iconTooltip string No Text to display on hover over of icon in header

color string No Name of color to display in Custom Card header

56
Widget API Methods

color string No Possible values: ['green', 'yellow', 'red', 'blue']

summary string No Text to display in card context area

legTitle string No Optional text to display at top of Custom Card context area

legTitleIcon string No Optional class name of icon to display beside legTitle

legTitleTooltip string No Optional text to display on hover of legTitle

Date/Time of when Custom Card was established (displays


establishedTime date No
timer). Only acceptable if updatableTimer is set to true

countdownTimer boolean No Is the timer a countdown timer

Duration in milliseconds that the timer will count down


countdownDuration number No
from. Only acceptable if updatableTimer is set to true

buttons button[] No Array of Buttons to display in Custom Card action area

Object containing card data properties


interactionData object No Possible values: See onInteractionEvent payload in the
Widget API Events section for possible object properties

true/false value to determine if the card is focused


focusOnCreated boolean No
automatically on card creation

Timeout value in milliseconds for the context menu to wait


menuTimeout number No for data to be returned. Set to 8 seconds by default. Only
applicable if using updateMenuItems API method

true/false value to determine if the default tab is rendered


disableDefaultTabActivation boolean No
automatically on card focus

Where a button object is in the following format...

Parameter Type Required Description

title string Yes Text to display on hover over of button

Class name of icon to display for button (see neo framework


icon string Yes
for possible values)

Name of color to use for button


color string Yes
Possible values: ['green', 'yellow', 'red', 'blue']

No - Property
available on Custom Card ID to give button access to which card button is
customCardId string
button callback attached to
object

action function No Callback executed when button has been clicked

Button will be a dropdown menu and should contain


isContextMenu boolean No
menuItems

No/ Yes if
menuItems menuItem[] isContextMenu Array of menu items to display in drop down list
is true

Input with a button icon. If set, will be placed at the top of the
inputWithButton object No
context menu. Can be used only if isContextMenu is true.

Unique index ranging from 1 to 6 used to determine position of


positionIndex string Yes button. Button will not display unless a valid index is specified.
If 2 buttons have the same index, only the first will display.

Where a menuItem object is in the following format...

57
Widget API Methods

Parameter Type Required Description

title string Yes Text to display on menu item

tooltip string No Text to display on hover over of menu item

action function No Callback executed when menu item has been clicked

Array of subMenuItems to display in sub-menu of parent menu


subMenuItems subMenuItem[] No
item

Where a subMenuItem object is in the following format...

Parameter Type Required Description

title string Yes Text to display on sub-menu item

tooltip string No Text to display on hover over of sub-menu item

action function No Callback executed when sub-menu item has been clicked

Where an inputWithButton object is in the following format...

Parameter Type Required Description

placeholder string Yes Text to display as input placeholder

buttonIcon string Yes Icon to display as button

buttonTooltip string No Text to display on hover over of button icon

Callback executed when button has been clicked. Input value is passed as
action function Yes
callback's parameter

// The following is an example of how to update a custom card


api.updateCustomCard({
id: 'id',
buttons: [{
title: 'button-1',
icon: 'aoc-end',
color: 'red',
action: function (data) {
console.log('accept clicked');
api.sendNotification('info', 'The button is attached to ' + data.customCardId);
}
}, {
title: 'button-2',
positionIndex: '1',
icon: 'aoc-hold',
isContextMenu: true,
menuItems: [{
title: 'dropdown-menu-item-1',
tooltip: 'tooltip-dropdown-menu-item-1',
action: function () {
console.log('dropdown-menu-item-1 clicked')
}
}, {
title: 'dropdown-menu-item-2',
action: function () {
console.log('dropdown-menu-item-1 clicked')
}
}]
}, {
title: 'context-menu-button-1',
positionIndex: '2',
isContextMenu: true,
menuItems: [{

58
Widget API Methods

title: 'dropdown-menu-item-1',
tooltip: 'tooltip-dropdown-menu-item-1',
subMenuItems: [{
title: 'dropdown-submenu-item-1',
tooltip: 'tooltip-dropdown-submenu-item-1',
action: function () {
console.log('dropdown-menu-item-1-sub-menu-1 clicked')
}
}]
}, {
title: 'dropdown-menu-item-2',
subMenuItems: [{
title: 'dropdown-submenu-item-1',
action: function () {
console.log('dropdown-menu-item-2-sub-menu-1 clicked')
}
}]
}]
}]
});

deleteCustomCard(data)
Removes a custom Card from the Work Card Area in Workspaces. This method accepts the following parameters:

data (required): A JavaScript Object used to configure the content, behaviour and look of the Custom Card

The data object passed to deleteCustomCard method can contain the following properties...

Parameter Type Required? Description

id string Yes Unique ID of custom card

// The following is an example of how to delete a custom card


api.deleteCustomCard({id: 'id'});

createCustomStatePanel(data)
This method allows 3rd party developers to create a custom state panel. The custom state panel can be customized to display a
title, color and timer, with the option to add up to 5 channel icons. The custom state panel will match the display of the existing
State panel in the footer (i.e. compressed and uncompressed layouts). When a custom state panel is being displayed, the standard
state panel will not be displayed.

Creates a custom state panel that will be displayed in the footer area in Workspaces. This method accepts the following
parameters:

data (required): A JavaScript Object used to configure the content, behaviour and look of the Custom State Panel
Note: Only one instance of a Custom State Panel can exist in Workspaces at any given time.

Parameter Type Required? Description

title string Yes Text to display in Custom State Panel

color string No Class name of color to use for Custom State Panel

timer boolean No Set to true to display a timer.

59
Widget API Methods

List of reason codes presented when user attempted to move a


reasonCodes string[] No channel to a Not Ready state. Limited to a max of 20 codes.
Duplicates will be ignored

Flag to indicate if providing a reason code when moving a channel to


mandatoryCodes boolean No
a Not Ready state in mandatory

channels channel[] No The list of channels to display. Limited to a max of 5 channels

Where a channel object is in the following format...

Parameter Type Required Description

name string Yes The name of the channel

readyIcon string Yes The icon to display when the channel is ready

notReadyIcon string Yes The icon to display when the channel is not ready

ready boolean Yes State of the channel

reasonCode string No Displayed as part of the icon tooltip when the channel is not ready

Create Custom State Panel Example

api.createCustomStatePanel({
timer: true,
color: 'blue',
title: 'Awaiting Nailup Call',
reasonCodes: ['Break', 'Lunch', 'Training'],
mandatoryCodes: true,
channels : [
{readyIcon: 'aoc-chat', notReadyIcon: 'aoc-chat-missed', ready: true, name: 'Chat'},
{readyIcon: 'aoc-email', notReadyIcon: 'aoc-email-missed', ready: false, name: 'Email', reasonCode: 'Exam
ple Reason Code'}
],
});

updateCustomStatePanel(data)
Updates a custom state panel that will be displayed in the footer area in Workspaces. This method accepts the following
parameters:

data (required): A JavaScript Object used to configure the content, behaviour and look of the Custom State Panel
Note: Only one instance of a Custom State Panel can exist in Workspaces at any given time.

Parameter Type Required? Description

title string Yes Text to display in Custom State Panel

color string No Class name of color to use for Custom State Panel

timer boolean No Set to true to display a timer.

List of reason codes presented when user attempted to move a


reasonCodes string[] No channel to a Not Ready state. Limited to a max of 20 codes.
Duplicates will be ignored

Flag to indicate if providing a reason code when moving a channel to


mandatoryCodes boolean No
a Not Ready state in mandatory

channels channel[] No The list of channels to display. Limited to a max of 5 channels

60
Widget API Methods

Where a channel object is in the following format...

Parameter Type Required Description

name string Yes The name of the channel

readyIcon string Yes The icon to display when the channel is ready

notReadyIcon string Yes The icon to display when the channel is not ready

ready boolean Yes State of the channel

reasonCode string No Displayed in the icon tooltip when the channel is not ready

Update Custom State Panel Example

api.updateCustomStatePanel({
timer: true,
color: 'blue',
title: 'Awaiting Nailup Call',
reasonCodes: ['Break', 'Lunch', 'Training'],
mandatoryCodes: true,
channels : [
{readyIcon: 'aoc-chat', notReadyIcon: 'aoc-chat-missed', ready: true, name: 'Chat'},
{readyIcon: 'aoc-email', notReadyIcon: 'aoc-email-missed', ready: false, name: 'Email', reasonCode: 'Exam
ple Reason Code'}
],
});

deleteCustomStatePanel()
Removes a custom state panel from the footer area in Workspaces.

Delete Custom State Panel Example

api.deleteCustomStatePanel();

updateMenuItems(data, id)
Updates the menu items and submenu items contained inside a context menu button on a custom card. This method is
intended to be called from within an action callback on a button object. Context menu buttons get their unique id passed to
the action callback so that it can be passed to the updateMenuItems api function.

Note: There is an 8 second timeout on this update function. If the data does not get returned from the 3rd party widget
through to the widget API within 8 seconds of the button click, the menu will not load the items and will display 'Unable to
load menu items'.

This method accepts the following parameters:

data (required): An array of menu item JavaScript Objects used to configure the menu content.
id (required): The id of the context menu button that was clicked. This property is passed to the action property
function. See below example:

action: function (id) {


api.updateMenuItems(menuItemsObject, id);
}

61
Widget API Methods

Where menuItemsObject is an array of objects is in the following format...

Parameter Type Required Description

title string Yes Text to display on menu item

tooltip string No Text to display on hover over of menu item

action function No Callback executed when menu item has been clicked

Array of subMenuItems to display in sub-menu of parent menu


subMenuItems subMenuItem[] No
item

Update Menu Items Example

var data = [{
title: 'My Team',
tooltip: 'Team members',
subMenuItems: [{
title: 'Ian Power',
action: function (data) {
api.sendNotification('info', data.title + ' pressed');
}
},{
title: 'Stephen Dunphy',
action: function (data) {
api.sendNotification('info', data.title + ' pressed');
}
},{
title: 'Cathal Jackson',
action: function (data) {
api.sendNotification('info', data.title + ' pressed');
}
}],
},
{
title: 'Disposition Codes',
tooltip: 'Disposition Codes',
subMenuItems: [{
title: 'Callback Customer',
tooltip: '999',
action: function (data) {
api.sendNotification('info', data.title + ' pressed');
}
},{
title: 'Discount Offered',
tooltip: '766',
action: function (data) {
api.sendNotification('info', data.title + ' pressed');
}
}],
}
];

//action property on button object


action: function (id) {
api.updateMenuItems(data, id);
}

searchEnterpriseDirectory(text)
Searches the enterprise directory (LDAP) for contacts.

62
Widget API Methods

This method will only execute if the enterprise directory is configured correctly. See the
api.isEnterpriseContactsServiceAvailable() method, onEnterpriseServiceAvailableEvent and

onEnterpriseServiceUnvailableEvent on how to check for this.

Note: If multiple widgets using this method are added to the same layout (e.g Home, Voice, Email etc.), each widget in the
layout will receive the same onEnterpriseContactsReceivedEvent event data. However, each interaction layout will receive
unique event data. For example if I click on the one voice work card and search via a widget, then click on a seperate voice
work card, each of the two layouts will retain their own contact search state.

This method accepts the following parameters:

text: The search text. You may search by name, email address or department.

// Search for a contact


api.searchEnterpriseDirectory('Michael D Higgins');

If the search is successful the onEnterpriseContactsReceivedEvent will be raised.

See the address-book sample widget for further demonstration.

isEnterpriseContactsServiceAvailable()
Checks if the enterprise directory contacts search is available to make a search.

This will return false if the AADS url is not set in System Manager or an invalid url has been used. Otherwise it will return
true.

If this returns false the widget should react to ensure the Agent is not allowed to perform a search from the widget. i.e
search field should be disabled

This method is used in conjunction with onEnterpriseServiceAvailableEvent and onEnterpriseServiceUnvailableEvent


events to ensure that the value is accurate in the scenario where the widget misses these events while loading.

// Check if enterprise directory contacts search is available


var isEnterpriseContactsServiceAvailable = api.isEnterpriseContactsServiceAvailable();

See the address-book sample widget for further demonstration.

unregister
This method can be called during the clean-up stage to unregister and unload the current widget.

api.unregister();

startWork()
Logs in an agent and puts them into a Ready state.

This method will only execute if the capabilities.canLogin capability is set to true . Please see Capabilities for more
information.

63
Widget API Methods

// Start Work
api.startWork();

See the agent-state sample widget for further demonstration.

startWorkNotReady()
Logs in an agent and puts them into a Not Ready state.

This method will only execute if the capabilities.canLogin capability is set to true . Please see Capabilities for more
information.

// Start Work in a Not Ready state


api.startWorkNotReady();

See the agent-state sample widget for further demonstration.

setAgentReady()
Puts an agent into a Ready state

This method will only execute if the capabilities.canSetReady capability is set to true . Please see Capabilities for
more information.

// Put agent into a Ready state


api.setAgentReady();

See the agent-state sample widget for further demonstration.

setAgentACW()
Puts an agent into an After Contact Work state

Note: This is an Elite only feature and will not work on Oceana environments. The 'Enable After Contact Work' setting
must also be enabled through the Workspaces Administrator Settings for this method to execute. This method also relies on
capabilities and will only execute if the capabilities.canSetAfterContactWork capability is set to true . Please see
Capabilities for more information.

// Put agent into an After Contact Work state


api.setAgentACW();

See the agent-state sample widget for further demonstration.

finishWork()
Logs out an Agent (Does not exit Workspaces) and puts them into a Connected state

64
Widget API Methods

This method will only execute if the capabilities.canLogout capability is set to true . Please see Capabilities for more
information.

// Log out agent


api.finishWork();

See the agent-state sample widget for further demonstration.

additionalWork(code)
Puts an agent into Additional Work mode

This method will only execute if the capabilities.canSetNotReady capability is set to true . Please see Capabilities for
more information.

This method accepts the following parameters:

code: The additional work code to put agent into Additional Work mode.

// Put agent into Additional Work mode with Additional Work Code
var code = api.getAdditionalWorkCodes()[0];
api.additionalWork(code);

See the agent-state sample widget for further demonstration.

setAgentNotReady(code)
Puts an agent into a Not Ready state with a Not Ready Reason Code

This method will only execute if the capabilities.canSetNotReady capability is set to true . Please see Capabilities for
more information.

This method accepts the following parameters:

code: The reason code to set agent not ready.

// Set agent Not Ready with Reason Code


var code = api.getNotReadyReasonCodes()[0];
api.setAgentNotReady(code);

See the agent-state sample widget for further demonstration.

bidi(element)
If element is not specified, returns direction of the whole document ('ltr' or 'rtl')

Otherwise determines and returns dir applied to specified element

This method accepts the following parameters:

element: HTML node to determine direction of.

65
Widget API Methods

// Get direction of document


var dir = api.bidi(); // returns 'rtl' in case if rtl-language
// is selected by agent; returns 'ltr' otherwise

// Get direction of specific element


var el = angular.element('<div dir="ltr"><span dir="rtl"><b>Hello world!</b></span></div>');
var elDir = api.bidi(el.find('b').get(0)); // returns 'rtl'

forceReload()
This method forces page reload without showing dialog box

// Force page reload


api.forceReload();

setFocus(interactionId)
This method sets focus on interaction

interactionId: id of interaction that should be focused.

// Set focus on interaction


api.setFocus(interactionId);

66
Widget API Events

Widget API Events


The Widget API exposes the onDataEvent method to allow widgets to subscribe to various data events delivered by workspaces.

Please note, events marked as 'Requires Interaction' require an interaction context. Any Widget leveraging these events will
need to be placed on an Interaction related tab (e.g. Customer Details).

var event = 'onInteractionEvent';


api.onDataEvent(event, callback);
function callback(data) {
// do something with event data
}

onInteractionEvent
This event is triggered when a new work card (interaction) appears in Workspaces. It is also triggered each time the
interaction is updated.

The state property can be used to determine what state the interaction is currently in (e.g ALERTING, ACTIVE,
HELD).

Note: Requires Interaction

var api = new WidgetAPI(params);


api.onDataEvent('onInteractionEvent', function (data) {
// do something with the event data
console.log(data);
});

Payload

{
"id": "bffae854-9219-4cfc-9fd3-7125f2e76844",
"workRequestId": "00142002901551796576",
"externalInteractionId": "14221",
"channel": "VOICE",
"state": "ALERTING",
"stateReason": "DEFAULT",
"interactionType": "CALLED",
"title": "Stella Pavlova",
"topic": "Support",
"topicId": "3007",
"skill": "IT",
"skillId": "3009",
"direction": "INCOMING",
"isCustomerInteraction": false,
"isWebRtcCall": false,
"userToUserInfo": "172917",
"isConsult": false,
"workCode": "7277",
"originatingAddress": "14225",

67
Widget API Events

"destinationAddress": "14221",
"contactId": "00142002901551796576"
}

See the interaction-operations or interaction-messenger sample widgets for further demonstration.

onChannelStatusUpdateEvent
This event is triggered when the status of a channel on a Custom State Panel gets updated.

api.onDataEvent('onChannelStatusUpdateEvent', function (data) {


if (data.ready){
console.log(data.name + ' is ready');
} else {
console.log(data.name + ' is not ready');
}
// do something with event data
});

Payload

{
"name": "Chat"
"notReadyIcon": "aoc-chat-missed"
"ready": false
"readyIcon": "aoc-chat"
"reasonCode": "Lunch"
}

onUserTypingEvent
This event is triggered while user is typing

This event will only be triggered once every 6 seconds

Note: Requires Interaction

var api = new WidgetAPI(params);


api.onDataEvent('onUserTypingEvent', function (data) {
// do something with the event data
if (!data.isSelf) {
console.log(data.participantType + ' ' + data.participantName + ' is typing!', data);
}
});

Payload

{
"participantType": "CUSTOMER",
"participantName": "Test User",
"participantAddress": "1001",
"muted": false,
"isSelf": true

68
Widget API Events

See the interaction-messenger sample widget for further demonstration.

onFileUploadEvent
This event is triggered after a file upload to the server has been completed.

Note: Requires Interaction

var api = new WidgetAPI(params);


api.onDataEvent('onFileUploadEvent', function (data) {
// do something with the event data
console.log(data);
});

Payload

{
"attachments": [
{
"partId": "5399B8DF-7038-42B6-9F67-64B9C178D132",
"mimeType": "image/jpeg",
"name": "test_img.JPG",
"size": 8233,
"address":
"http://localhost/services/AgentControllerService/attachment/5399B8DF-7038-42B6-
9F67-64B9C178D132"
}
],
"message": {
"messageId": "09188b9c-1870-4e47-9c23-9728559d430a",
"interactionMediaId": "81a9ed17-1f1e-4b5e-bf3d-273ad638b01f",
"subject": null,
"body": "",
"arrivalDate": "1554475193536",
"lastModifiedDate": "",
"receivedFrom": {
"participantType": "AGENT",
"participantSubtype": null,
"participantName": "Test Agent",
"participantAddress": "(503) 421-9800",
"muted": false,
"isSelf": true
},
"messageEvent": null,
"flags": {
"sensitivity": "PUBLIC",
"importance": "NORMAL",
"encoding": "PLAIN",
"doNotForward": false

69
Widget API Events

},
"parts": [
{
"partId": "5399B8DF-7038-42B6-9F67-64B9C178D132",
"mimeType": "image/jpeg",
"name": "test_img.JPG",
"size": 8233,
"address":
"http://localhost/services/AgentControllerService/attachment/5399B8DF-7038-42B6-
9F67-64B9C178D132"
}
],
"sendTo": [],
"type": "WEBCHAT",
"chatMessageEvent": {
"type": null,
"subject": "",
"participants": [
{
"participantType": "AGENT",
"participantSubtype": null,
"participantName": "Test Agent",
"participantAddress": "(503) 421-9800",
"muted": false,
"isSelf": true
},
{
"participantType": "CUSTOMER",
"participantSubtype": null,
"participantName": "user test",
"participantAddress": "test@customer.com",
"muted": false,
"isSelf": false
}
],
"chatEventType": "TRANSFERRED_FILE"
},
"customData": null,
"sensitivity": "PUBLIC",
"importance": "NORMAL"
}
}

See the interaction-messenger sample widget for further demonstration.

onEmailAttachmentUploadEvent
This event is triggered after a email attachment upload to the server has been completed.

70
Widget API Events

Note: Requires Interaction

var api = new WidgetAPI(params);


api.onDataEvent('onEmailAttachmentUploadEvent', function (data) {
// do something with the event data
console.log(data);
});

Payload

{
"attachments": [
{
"partId": "5399B8DF-7038-42B6-9F67-64B9C178D132",
"mimeType": "image/jpeg",
"name": "test_img.JPG",
"size": 8233,
"address":
"http://localhost/services/AgentControllerService/attachment/5399B8DF-7038-42B6-
9F67-64B9C178D132"
}
]
}

onFileTransferInitiatedEvent
This event is triggered when the customer starts downloading the file.

Note: Requires Interaction

var api = new WidgetAPI(params);


api.onDataEvent('onFileTransferInitiatedEvent', function (data) {
// do something with the event data
console.log(data);
});

Payload

{
"attachment": {
"partId": "5399B8DF-7038-42B6-9F67-64B9C178D132",
"mimeType": "image/jpeg",
"name": "test_img.JPG",
"size": 8233,
"address":
"http://localhost/services/AgentControllerService/attachment/5399B8DF-7038-42B6-
9F67-64B9C178D132"
},
"message": {
"messageId": "04b119a8-765a-410f-bdbd-45bf00858107",
"interactionMediaId": "81a9ed17-1f1e-4b5e-bf3d-273ad638b01f",
"subject": null,

71
Widget API Events

"body": null,
"arrivalDate": "0",
"lastModifiedDate": "",
"receivedFrom": {
"participantType": "CUSTOMER",
"participantSubtype": null,
"participantName": "user test",
"participantAddress": "test@customer.com",
"muted": false,
"isSelf": false
},
"messageEvent": null,
"flags": {
"sensitivity": "PUBLIC",
"importance": "NORMAL",
"encoding": "PLAIN",
"doNotForward": false
},
"parts": [
{
"partId": "5399B8DF-7038-42B6-9F67-64B9C178D132",
"mimeType": "image/jpeg",
"name": "test_img.JPG",
"size": 8233,
"address":
"http://localhost/services/AgentControllerService/attachment/5399B8DF-7038-42B6-
9F67-64B9C178D132"
}
],
"sendTo": [],
"type": "WEBCHAT",
"chatMessageEvent": {
"type": null,
"subject": "",
"participants": [
{
"participantType": "AGENT",
"participantSubtype": null,
"participantName": "Test Agent",
"participantAddress": "(503) 421-9800",
"muted": false,
"isSelf": true
},
{
"participantType": "CUSTOMER",
"participantSubtype": null,
"participantName": "user test",
"participantAddress": "test@customer.com",
"muted": false,
"isSelf": false
}

72
Widget API Events

],
"chatEventType": "CUSTOMER_DOWNLOAD_INITIATED"
},
"customData": null,
"sensitivity": "PUBLIC",
"importance": "NORMAL"
}
}

See the interaction-messenger sample widget for further demonstration.

onFileTransferCompleteEvent
This event is triggered when the file is fully transferred.

Note: Requires Interaction

var api = new WidgetAPI(params);


api.onDataEvent('onFileTransferCompleteEvent', function (data) {
// do something with the event data
console.log(data);
});

Payload

{
"attachment": {
"partId": "19285BFC-09CA-442E-8823-AB0C9A705F71",
"mimeType": "image/jpeg",
"name": "test_img.JPG",
"size": 8233,
"address":
"http://localhost/services/AgentControllerService/attachment/19285BFC-09CA-442E-
8823-AB0C9A705F71"
},
"message": {
"messageId": "775fa9e0-71a2-44a9-8325-6eade9ceae6c",
"interactionMediaId": "81a9ed17-1f1e-4b5e-bf3d-273ad638b01f",
"subject": null,
"body": null,
"arrivalDate": "0",
"lastModifiedDate": "",
"receivedFrom": {
"participantType": "CUSTOMER",
"participantSubtype": null,
"participantName": "user test",
"participantAddress": "test@customer.com",
"muted": false,
"isSelf": false
},
"messageEvent": null,

73
Widget API Events

"flags": {
"sensitivity": "PUBLIC",
"importance": "NORMAL",
"encoding": "PLAIN",
"doNotForward": false
},
"parts": [
{
"partId": "19285BFC-09CA-442E-8823-AB0C9A705F71",
"mimeType": "image/jpeg",
"name": "test_img.JPG",
"size": 8233,
"address":
"http://localhost/services/AgentControllerService/attachment/19285BFC-09CA-442E-
8823-AB0C9A705F71"
}
],
"sendTo": [],
"type": "WEBCHAT",
"chatMessageEvent": {
"type": null,
"subject": "",
"participants": [
{
"participantType": "AGENT",
"participantSubtype": null,
"participantName": "Test Agent",
"participantAddress": "(503) 421-9800",
"muted": false,
"isSelf": true
},
{
"participantType": "CUSTOMER",
"participantSubtype": null,
"participantName": "user test",
"participantAddress": "test@customer.com",
"muted": false,
"isSelf": false
}
],
"chatEventType": "CUSTOMER_DOWNLOAD_COMPLETE"
},
"customData": null,
"sensitivity": "PUBLIC",
"importance": "NORMAL"
}
}

See the interaction-messenger sample widget for further demonstration.

74
Widget API Events

onInteractionEndedEvent
This event is triggered when a work card (interaction) has been ended. This occurs for all interaction types.

Note: Requires Interaction

Note: This event is only useful when ACW is enabled so that the widget can be used to trigger some custom logic when an
interaction has ended. Otherwise, as per usual, the widget will be destroyed once the interaction has ended.

Note: This client side only event is quite limited as the backend does not support an ENDED interaction state, only
ALERTING, ACTIVE and HELD. Therefore, you will see that the event is triggered in the following scenarios for Voice:

Agent ends the call


Customer ends the call
Call is blind transferred (single step transfer)
Agent A consults Agent B, then Agent A completes as conference (in this case the interactionType can be used to
check for a value of 'CONSULTING')
Agent A consults Agent B, then Agent A completes as transfer (same as above, the interactionType can be used if
required)

var api = new WidgetAPI(params);


api.onDataEvent('onInteractionEndedEvent', function (data) {
// do something with the event data
console.log(data);
});

Payload

{
"id": "bffae854-9219-4cfc-9fd3-7125f2e76844",
"workRequestId": "00142002901551796576",
"externalInteractionId": "14221",
"channel": "VOICE",
"state": "ACTIVE",
"stateReason": "DEFAULT",
"interactionType": "CALLED",
"title": "Stella Pavlova",
"topic": "Support",
"topicId": "3007",
"skill": "IT",
"skillId": "3009",
"direction": "INCOMING",
"isCustomerInteraction": false,
"isWebRtcCall": false,
"userToUserInfo": "172917",
"isConsult": false,
"workCode": "7277",
"originatingAddress": "14225",
"destinationAddress": "14221",
"contactId": "00142002901551796576"
}

See the hello-world sample widget for further demonstration.

75
Widget API Events

onCRMDataEvent
If CRM integration is enabled and configured in Workspaces this event is triggered when there is CRM customer data
available for the current work card interaction.

Note: Requires Interaction

api.onDataEvent('onCRMDataEvent', callback);
function callback(data) {
// do something with event data
}

Payload

{
"attributes": {
"type": "Contact",
"url": "/services/data/v34.0/sobjects/Contact/00358000001aSR2AAM"
},
"birth_date": "1951-10-18",
"created_at": "2015-12-29T22:03:13.000+0000",
"description": null,
"email": "bond_john@grandhotels.com",
"phone_fax": "(312) 596-1500",
"first_name": "John",
"phone_home": "(312) 596-1000",
"user_id": "00358000001aSR2AAM",
"last_name": "Sutherland",
"address": {
"city": null,
"country": null,
"countryCode": null,
"geocodeAccuracy": null,
"latitude": null,
"longitude": null,
"postalCode": null,
"state": null,
"stateCode": null,
"street": "2334 N. Michigan Avenue, Suite 1500\r\nChicago, IL 60601, USA"
},
"address_city": null,
"address_country": null,
"geo_latitude": null,
"geo_longitude": null,
"address_zip": null,
"address_state": null,
"address_street": "2334 N. Michigan Avenue, Suite 1500\r\nChicago, IL 60601,
USA",
"phone_mobile": "(312) 596-1563",
"name": "John Sutherland",
"phone_primary": "(312) 596-1000",
"avatar_url": "/services/images/photo/00358000001aSR2AAM",
"title": "VP, Facilities",

76
Widget API Events

"id": "6625a233-abbb-4d0d-9c08-9c421526c614",
"cases": [
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000o6e5AAA"
},
"case_number": "00001013",
"user_id": "00358000001aSR2AAM",
"created_at": "2015-12-29T22:03:13.000+0000",
"case_closed": true,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Web",
"case_priority": "Medium",
"case_reason": "Equipment Design",
"case_status": "Closed",
"case_subject": "Starting up generator consumes excessive power",
"case_type": "Other"
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000o6e6AAA"
},
"case_number": "00001014",
"user_id": "00358000001aSR2AAM",
"created_at": "2015-12-29T22:03:13.000+0000",
"case_closed": true,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Phone",
"case_priority": "High",
"case_reason": "Installation",
"case_status": "Closed",
"case_subject": "Delay in installation; spare parts unavailable",
"case_type": "Other"
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x7z1AAA"
},
"case_number": "00001044",
"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T13:34:03.000+0000",
"case_closed": false,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Email",
"case_priority": "Medium",

77
Widget API Events

"case_reason": null,
"case_status": "New",
"case_subject": "Power generation below stated level",
"case_type": null
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x84zAAA"
},
"case_number": "00001079",
"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T14:04:01.000+0000",
"case_closed": false,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Phone",
"case_priority": "High",
"case_reason": "Breakdown",
"case_status": "Escalated",
"case_subject": "Frequent mechanical breakdown",
"case_type": "Mechanical"
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x80sAAA"
},
"case_number": "00001060",
"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T13:46:30.000+0000",
"case_closed": false,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Phone",
"case_priority": "High",
"case_reason": "Equipment Design",
"case_status": "Working",
"case_subject": "Motor design hindering performance",
"case_type": "Mechanical"
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x7wbAAA"
},
"case_number": "00001037",
"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T13:22:44.000+0000",
"case_closed": false,
"case_deleted": false,

78
Widget API Events

"case_escalated": false,
"case_origin": "Phone",
"case_priority": "Low",
"case_reason": null,
"case_status": "New",
"case_subject": "Maintenance guidelines for generator unclear",
"case_type": null
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x89pAAA"
},
"case_number": "00001096",
"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T14:49:40.000+0000",
"case_closed": false,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Phone",
"case_priority": "Low",
"case_reason": null,
"case_status": "New",
"case_subject": "Customer reported another part DRP23423OD failed during
test",
"case_type": null
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x8AnAAI"
},
"case_number": "00001104",
"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T14:55:50.000+0000",
"case_closed": false,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Email",
"case_priority": "Low",
"case_reason": null,
"case_status": "Working",
"case_subject": "Component part DPR3423DOD was shipped to customer",
"case_type": null
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x7zuAAA"
},
"case_number": "00001052",

79
Widget API Events

"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T13:39:55.000+0000",
"case_closed": false,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Web",
"case_priority": "Low",
"case_reason": "Feedback",
"case_status": "New",
"case_subject": "Easy installation process",
"case_type": "Other"
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x891AAA"
},
"case_number": "00001089",
"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T14:41:54.000+0000",
"case_closed": false,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Email",
"case_priority": "Medium",
"case_reason": null,
"case_status": "New",
"case_subject": "Wrong component part ordered from manufacturer",
"case_type": null
},
{
"attributes": {
"type": "Case",
"url": "/services/data/v34.0/sobjects/Case/50058000000x83XAAQ"
},
"case_number": "00001072",
"user_id": "00358000001aSR2AAM",
"created_at": "2016-05-13T13:57:03.000+0000",
"case_closed": false,
"case_deleted": false,
"case_escalated": false,
"case_origin": "Email",
"case_priority": "Medium",
"case_reason": "Installation",
"case_status": "Escalated",
"case_subject": "Delay in installation; spare parts unavailable",
"case_type": "Other"
}
]
}

80
Widget API Events

onContextDataEvent
This event is triggered when customer and context data is available in Chat, SMS, Email and Social work cards. This event
can be used to obtain customer details and customer history data from Chat, SMS, Email and Social interactions.

Note: Here you can retrieve max allowed characters limitations (which is best to manage in your widget) using
clientValidation array passed within common data object. Depending on your interaction channel (Chat, SMS or

Social) you're going to get different validation entries with data.type field equal to WEBCHAT_MAX_CHAR , SMS_MAX_CHAR or
SOCIAL_MAX_CHAR respectively.

Note: Requires Interaction

api.onDataEvent('onContextDataEvent', callback);
function callback(data) {
// do something with event data
}

Payload

{
"clientValidation": [
{
"data": {
"type": "WEBCHAT_MAX_CHAR",
"value": 10000
},
"type": "CLIENT_VALIDATION",
"description": "",
"id": "6194c3ef-676d-4743-a2a5-a86f5591ce52"
}
]
"customerDetails": [
{
"type": "CUSTOMER_DETAILS",
"data": {
"name": "name1",
"firstName": "firstName1",
"lastName": "lastName1",
"email": "customer@companyxyz.com",
"phonePrimary": "phonePrimary1",
"phoneHome": "phoneHome1",
"phoneMobile": "phoneMobile1",
"phoneFax": "phoneFax1",
"birthDate": "birthDate1",
"address": "address1",
"addressStreet": "addressStreet1",
"addressState": "addressState1",
"addressZip": "addressZip1",
"addressCity": "addressCity1",
"addressCountry": "addressCountry1",

81
Widget API Events

"geoLatitude": "geoLatitude1",
"geoLongitude": "geoLongitude1",
"avatarUrl": "avatarUrl1",
"title": "title1",
"description": "description1",
"department": "department1",
"createdDate": "2017-09-19T12:45:10.763Z"
},
"description": "",
"id": "87e79cf5-cfee-4960-b776-fa449ae1a98e"
}
],
"customerHistory": [
{
"type": "CUSTOMER_HISTORY",
"data": {
"status": "status1",
"subject": "subject1",
"priority": "priority1",
"type": "type1",
"href":
"https://10.134.146.163/services/AgentControllerService/gila/api/customerhistory/12
234",
"createdDate": "2017-09-19T12:45:10.763Z"
},
"description": "",
"id": "f514d6eb-58c3-4750-bb26-f0840b76dd37"
},
{
"type": "CUSTOMER_HISTORY",
"data": {
"status": "status2",
"subject": "subject2",
"priority": "priority2",
"type": "type2",
"href":
"https://10.134.146.163/services/AgentControllerService/gila/api/customerhistory/12
771",
"action": "action1",
"id": "id1",
"createdDate": "2017-09-19T12:45:10.763Z"
},
"description": "",
"id": "96d633e2-9f26-40b9-bf9c-3fbf5241dec3"
}
],
"contextStore": [
{
"type": "CONTEXT_STORE",
"data": "716391",
"description": "Prompted Digits Data",

82
Widget API Events

"id": "a9a65201-0c72-4c1f-8735-9635f064a016"
}
],
"campaignScripts": [
{
"type": "CAMPAIGN_SCRIPT",
"description": "",
"id": "a98416b5-f071-415c-9dfb-5e04af2c70cf",
"data": "https://irishtimes.com"
},
],
"cobrowse": [
{
"type": "COBROWSE",
"id": "45d8c424-796c-466d-8846-41a73c0f43b5",
"data": {
"url": "http://10.134.146.71/services/cobrowse/customer/index.html",
"description": "Cobrowse welcome page"
}
},
],
"fromAddresses": [
{
"type": "ORIGINATOR",
"data": {
"address": "info@info.com",
"description": "text1"
},
"description": "",
"id": "9e9c21d6-dc9e-4603-9046-fe8678d18b8a",
},
{
"type": "ORIGINATOR",
"data": {
"address": "sales@sales.com",
"description": "text2"
},
"description": "",
"id": "863bb132-912c-4013-93e3-8c2af6062dd2",
},
"id": "3bcac1e6-bb7a-4a51-91e7-9777447b70a9",
"interactionId": "db07dc7c-11e6-4f93-9abe-7924bb90b46f"
],
"pagePushUrl": [
{
"type": "PAGE_PUSH",
"data": {
"description": "description1",
"url": "url1"
},
"id": "dcb5e8ea-0d24-42fc-97ab-524f60e1991d",

83
Widget API Events

},
{
"type": "PAGE_PUSH",
"data": {
"description": "description2",
"url": "url2"
},
"id": "3d47b685-1167-44f0-8912-1d06d6a8bc21"
}
],
"screenPop": [
{
"type": "SCREEN_POP",
"id": "b6a9bc1c-ece7-4379-8c39-aaf5d46452c7",
"data": {
"action": "NONE"
"name": "Maps"
"scope": "INTERNAL"
"trigger": "ACTIVE"
"uri": "https://www.google.com/maps/embed?
pb=!1m18!1m12!1m3!1d152660.05036353657!2d-9.188836092077002!3d53"
}
},
{
"type": "SCREEN_POP",
"id": "7eb9082e-9bcf-45a9-a033-406a16961303",
"data": {
"action": "CLOSE_ON_END"
"name": "Google"
"scope": "INTERNAL"
"trigger": "ACTIVE"
"uri": "http://www.google.com"
}
},
],
"suggestedPhrase": [
{
"type": "SUGGESTED_PHRASE",
"data": {
"name": "name1",
"text": "text1"
},
"description"": "",
"id": "962641e5-544c-4eff-9321-3546a0511f0c",
},
{
"type": "SUGGESTED_PHRASE",
"data": {
"name": "name2",
"text": "text2"
},

84
Widget API Events

"description": "",
"id": "78ccd9c3-326f-436b-adb3-3e922f9937b0",
},
],
"Agent ID": "10002"
"Station ID": "1002"
}

See the interaction-messenger sample widget for further demonstration.

onMediaEvent
This event is triggered when an incoming Chat, SMS, Email or Social interaction is accepted by the user
(Agent/Supervisor). This event can be used to obtain Chat, SMS, Email or Social related data such as participants or
previously sent media messages.

Note: Requires Interaction

api.onDataEvent('onMediaEvent', callback);
function callback(data) {
// do something with event data
}

Payload

{
"interactionId": "803cdebe-a4b9-47d7-b0f6-27fa85dc654c",
"messages": [
{
"messageId": "9DBA8D4C-3BBD-435A-BEFC-031151146AA3",
"interactionMediaId": "02dc3a4c-6bdb-410e-8424-2fc26027884e",
"subject": "",
"body": "I would like to update some details on my car insurance policy.",
"arrivalDate": "2017-12-11T12:47:27.557Z",
"lastModifiedDate": "",
"receivedFrom": {
"participantType": "CUSTOMER",
"participantName": "Josh Davis",
"participantAddress": "(503) 421-9800",
"muted": false,
"isSelf": false
},
"messageEvent": null,
"flags": {
"read": true,
"sensitivity": "CONFIDENTIAL",
"importance": "LOW"
},
"parts": [],
"sendTo": [],
"type": "WEBCHAT",

85
Widget API Events

"chatMessageEvent": {
"subject": "messageEventSubject",
"participants": [
{
"participantType": "AGENT",
"participantName": "Name Steve",
"participantAddress": "1003",
"muted": false,
"isSelf": true
},
{
"participantType": "CUSTOMER",
"participantName": "Josh Davis",
"participantAddress": "(503) 421-9800",
"muted": false,
"isSelf": false
}
],
"chatEventType": "MESSAGE"
},
"read": true,
"sensitivity": "CONFIDENTIAL",
"importance": "LOW"
}
],
"participants": [
{
"participantType": "AGENT",
"participantName": "Name Steve",
"participantAddress": "1003",
"muted": false,
"isSelf": true
},
{
"participantType": "CUSTOMER",
"participantName": "Josh Davis",
"participantAddress": "(503) 421-9800",
"muted": false,
"isSelf": false
}
]
}

onMediaMessageEvent
This event is triggered when incoming Chat, SMS, Email or Social messages are sent to the user (Agent/Supervisor). This
event can be used to obtain Chat, SMS or Social messages and pass them to the widget. In the case of Email, data is
received as a single Email message and it can contain data formatted as text or HTML.

86
Widget API Events

Note: Requires Interaction

api.onDataEvent('onMediaMessageEvent', callback);
function callback(data) {
scope.chatMessage = data.body;
}

Payload

{
"messageId": "059BB79E-FED2-42A7-9FEC-FC230904B09F",
"interactionMediaId": "67313d2d-18fe-4c4b-a457-662c71eed99a",
"subject": "",
"body": "I would like to update some details on my car insurance policy.",
"arrivalDate": "2017-09-20T12:54:08.064Z",
"lastModifiedDate": "",
"receivedFrom": {
"participantType": "CUSTOMER",
"participantName": "Stella Pavlova",
"participantAddress": "(212) 842-5500",
"muted": false,
"isSelf": false
},
"messageEvent": null,
"flags": {
"read": true,
"sensitivity": "CONFIDENTIAL",
"importance": "LOW"
},
"parts": [],
"sendTo": [],
"type": "WEBCHAT",
"chatMessageEvent": {
"subject": "messageEventSubject",
"participants": [
{
"participantType": "AGENT",
"participantName": "Name Steve",
"participantAddress": "1002",
"muted": false,
"isSelf": true
},
{
"participantType": "CUSTOMER",
"participantName": "Stella Pavlova",
"participantAddress": "(212) 842-5500",
"muted": false,
"isSelf": false
}
],
"chatEventType": "MESSAGE"
},

87
Widget API Events

"read": true,
"sensitivity": "CONFIDENTIAL",
"importance": "LOW"
}

onPagePushUrlEvent
This event is triggered when page push urls are sent from the Suggested Content widget while working on a Chat, SMS or
Social interaction.

Note: Requires Interaction

api.onDataEvent('onPagePushUrlEvent', callback);
function callback(data) {
scope.pagePushUrl = data.body;
}

Payload

{
"messageId": "0ABE338F-50E7-4A80-AA8D-CDD7C6793AFC",
"interactionMediaId": "28b07b33-f916-4be9-a07a-c7a9d0a1afd1",
"subject": "",
"body": "https://www.google.com",
"arrivalDate": "2019-02-06T15:42:43.093Z",
"lastModifiedDate": "",
"receivedFrom": {
"participantType": "AGENT",
"participantName": "Agent Chat",
"participantAddress": "1003",
"muted": false,
"isSelf": true
},
"messageEvent": null,
"flags": {
"read": true,
"sensitivity": "PUBLIC",
"importance": "LOW"
},
"parts": [],
"sendTo": [],
"type": "WEBCHAT",
"chatMessageEvent": {
"subject": "messageEventSubject",
"participants": [
{
"participantType": "AGENT",
"participantName": "Agent Chat",
"participantAddress": "1003",
"muted": false,

88
Widget API Events

"isSelf": true
},
{
"participantType": "CUSTOMER",
"participantName": "Pat Stumuller",
"participantAddress": "(014) 427-4427",
"muted": false,
"isSelf": false
}
],
"chatEventType": "PAGE_PUSH"
},
"read": true,
"sensitivity": "PUBLIC",
"importance": "LOW"
}

See the hello-world sample widget for further demonstration.

onAgentStateEvent
This event is triggered whenever the agent state changes. This event provides information to widgets on the current state
and reason codes as well as the agent's current capabilities.

api.onDataEvent('onAgentStateEvent', callback);
function callback(data) {
// do something with event data
}

Payload

{
"state": "NOT_READY_PENDING",
"reasonCode": "999",
"agent": {
"capabilities": {
"canDeactivate": false,
"canLogin": false,
"canLogout": true,
"canMentorChat": false,
"canMentorSMS": false,
"canSetAfterContactWork": false,
"canSetNotReady": false,
"canSetWorkMode": false
}
}
}

89
Widget API Events

onNavigationEvent
This event is triggered whenever an icon in the sidebar is clicked. This event can inform widgets whenever the user
navigates or selects a sidebar icon.

api.onDataEvent('onNavigationEvent', callback);
function callback(data) {
// do something with event data
}

Payload

{
"viewName": "voice",
"context": {
"id": "d4286f6c-c6da-4e96-87e7-297b8d7679db",
"tabId": "aoc-warning-filled",
"userType": "AGENT"
},
"tab": "tab__ddf8bfc6-2604-4113-b7f1-63ba33c1da9b"
}

onLocaleUpdatedEvent
This event is triggered whenever the language setting changes in Workspaces.

api.onDataEvent('onLocaleUpdatedEvent', callback);
function callback(data) {
// do something with event data
}

Payload

{
"locale": "EN"
}

onBeforeTextDirectionChangedEvent
This event is triggered immediately before the document text direction changes (e.g. in case Agent switched from English
to Arabic language).

This event is triggered when the text direction in Workspaces changes.

Document text direction is set on \ element with dir property

api.onDataEvent('onBeforeTextDirectionChangedEvent', callback);
function callback(data) {
console.log('Text direction is going to be changed from ', data.from, ' to ', data.to);
}

90
Widget API Events

Payload

{
"from": "ltr",
"to": "rtl"
}

onStylesheetsReadyEvent
This event is triggered whenever the bidi-alternative stylesheets (re)loading has completed.

This event is triggered only when actual document text direction changes, i.e. when agent switches from any LTR language
(EN, FR, RU) to any RTL language (AR, HE) and vice-versa. It won't be triggered if text direction of considered languages
remains the same.

Note: this event is triggered even if your widget doesn't use separated styles for LTR and RTL as far as Workspaces itself
has built-in bidi-alternative stylesheets.

api.onDataEvent('onStylesheetsReadyEvent', callback);
function callback() {
console.log('All bidi-alternative stylesheets are loaded!');
}

onObserveEvent
This event is triggered to indicate that the current interaction is being observed. This is limited to AWFOS and not to be
confused with supervisor observing of chats / sms.

Note: Requires Interaction

api.onDataEvent('onObserveEvent', callback);
function callback(data) {
// do something with event data
}

Payload

{
id: '3ef1d1b9-a19a-485e-be17-94a16f523b75',
channel: 'Voice'
}

onCapabilitiesEvent
This event is triggered when the agent or interaction capabilities have been updated.

Note: The getCapabilities API method can also be used to retrieve the latest capabilities at any time.

api.onDataEvent('onCapabilitiesEvent', callback);
function callback(data) {

91
Widget API Events

// do something with event data


}

Payload

{
interaction: {
canAccept: false,
canEnd: true,
canHold: true,
canUnhold: false,
canSingleStepTransfer: true,
canConsult: true,
canTransferComplete: false,
canConferenceComplete: false,
canSetDispositionCode: true,
canSetWorkCode: true,
canSendDtmf: true,
canSendMessage: true,
},
channels: {
canStartVoiceInteraction: true
}
}

See the address-book sample widget for further demonstration.

onRequestServicesEvent
This event is triggered when an interaction requests its transfer to service list.

api.onDataEvent('onRequestServicesEvent', callback);
function callback() {
// do something when event is triggered
}

onMessageEvent
This event is triggered when other widgets broadcast a data message by using the sendMessage API method. This event is
used primarily for inter-widget communication.

This event will return anything that is sent via the sendMessage API method

api.onDataEvent('onMessageEvent', callback);
function callback(data) {
// do something with event data
}

92
Widget API Events

onTeamMemberEvent
This event is triggered when an agent is expanded in the supervisor dashboard. The object that is returned from this event
is the expanded agent object.

api.onDataEvent('onTeamMemberEvent', callback);
function callback(data) {
// do something with team member data
}

Payload

{
"userHandle":"mRuane",
"state":"READY",
"capabilities":{
"canLogin":false,
"canSetNotReady":true,
"canLogout":true,
"canSetReady":false,
"canDeactivate":false,
"canSupervisorSetReady":false,
"canSupervisorSetNotReady":true,
"canSupervisorLogout":true
},
"interactions":[
{
"id":"738fbd59-3e07-47fd-af4e-a280c8a08c7a",
"state":"ACTIVE",
"channel":"WEBCHAT",
"direction":"INCOMING",
"created":"2018-05-01T12:39:58.901Z",
"establishedTime":"2018-05-01T12:39:58.901Z",
"topic":"Oceana Service",
"isCustomerInteraction":true,
"originatingAddress":"(014) 427-4427",
"destinationAddress":"1001",
"workRequestId":"0074518545435242185724",
"capabilities":{
"canReject":false,
"canSetUui":true,
"canConsult":false,
"canTransferComplete":false,
"canEnd":true,
"canConferenceComplete":false,
"canSetWorkCode":true,
"canSetDispositionCode":true,
"canExtendACW":false,
"canSingleStepTransfer":true,
"canSingleStepTransferToService":true,
"canUnmute":false,
"canUnhold":false,

93
Widget API Events

"canCompleteACW":false,
"canMute":false,
"canSetACW":true,
"canHold":false,
"canIgnore":false,
"canAccept":false,
"canSendDtmf":false,
"canForward":true,
"canSendMessage":true,
"canObserve":true,
"canBarge":false,
"canCoach":false,
"canReply":true,
"canSingleStepConference":false,
"canDefer":false
},
"isObserved":false
}
],
"channels":[
{
"state":"READY",
"stateReason":"DEFAULT",
"reasonCode":"",
"providerName":"ngdemc",
"capabilities":{
"canSetCallForwarding":true,
"canCancelCallForwarding":true,
"canStartInteraction":true,
"canStartSupervisorInteraction":true
},
"channelType":"VOICE",
"id":"ad1cbec8-fe15-482b-8085-7d9c7f13f761",
"$$hashKey":"object:644"
},
{
"state":"READY",
"stateReason":"DEFAULT",
"reasonCode":"",
"providerName":"ngdemc",
"capabilities":{
"canSetCallForwarding":false,
"canCancelCallForwarding":false,
"canStartInteraction":false,
"canStartSupervisorInteraction":false
},
"channelType":"WEBCHAT",
"id":"0aeed53d-a50d-46bf-8e7d-681164d90746",
"$$hashKey":"object:645"
},
{

94
Widget API Events

"state":"READY",
"stateReason":"DEFAULT",
"reasonCode":"",
"providerName":"ngdemc",
"capabilities":{
"canSetCallForwarding":false,
"canCancelCallForwarding":false,
"canStartInteraction":true,
"canStartSupervisorInteraction":false,
"canRetrieveInteractions":false
},
"channelType":"EMAIL",
"id":"8cc86248-c214-4b27-81b7-c4ae103b637b",
"$$hashKey":"object:639"
},
{
"state":"READY",
"stateReason":"DEFAULT",
"reasonCode":"",
"providerName":"ngdemc",
"capabilities":{
"canSetCallForwarding":false,
"canCancelCallForwarding":false,
"canStartInteraction":false,
"canStartSupervisorInteraction":false
},
"channelType":"SMS",
"id":"2872a9e0-0edc-4126-9b1c-05b22b2c8beb",
"$$hashKey":"object:641"
},
{
"state":"READY",
"stateReason":"DEFAULT",
"reasonCode":"",
"providerName":"ngdemc",
"capabilities":{
"canSetCallForwarding":false,
"canCancelCallForwarding":false,
"canStartInteraction":false,
"canStartSupervisorInteraction":false
},
"channelType":"SOCIAL",
"id":"bb58757e-6115-4ca8-bb57-9075d32fa697",
"$$hashKey":"object:642"
},
{
"state":"READY",
"stateReason":"DEFAULT",
"reasonCode":"",
"providerName":"ngdemc",
"capabilities":{

95
Widget API Events

"canSetCallForwarding":true,
"canCancelCallForwarding":true,
"canStartInteraction":true,
"canStartSupervisorInteraction":true
},
"channelType":"VIDEO",
"id":"fefef219-05b0-4a46-9ad9-681e8e941edf",
"$$hashKey":"object:643"
},
{
"state":"READY",
"stateReason":"DEFAULT",
"reasonCode":"",
"providerName":"ngdemc",
"capabilities":{
"canSetCallForwarding":true,
"canCancelCallForwarding":true,
"canStartInteraction":true,
"canStartSupervisorInteraction":true
},
"channelType":"GENERIC",
"id":"dc3ad786-adef-4acb-8c56-8689e05dba72",
"$$hashKey":"object:640"
}
]
}

onEnterpriseContactsReceivedEvent
This event is triggered when an Enterprise Directory search has completed and contacts have been received.

Note: This event will return a maximum of 26 results. The Agent must refine in order to find a better match.

api.onDataEvent('onEnterpriseContactsReceivedEvent', callback);
function callback(data) {
scope.contacts = data.contacts;
}

Payload

[
{
id: '123456',
displayName: 'Joe Bloggs',
firstName: 'Joe',
lastName: 'Bloggs',
department: 'Sales',
isFavorite: true,
defaultNumber: '09156761334',
phones: [{

96
Widget API Events

number: '0044568413',
type: 'PHONE_NUMBER_WORK',
isDefault: true
},
{
number: '096879136',
type: 'PHONE_NUMBER_WORK',
isDefault: false
},
{
number: '0871234567',
type: 'PHONE_NUMBER_MOBILE',
isDefault: false
}],
emails: [{
address: 'jbloggs@company.com',
type: 'EMAIL_ADDRESS_WORK',
isDefault: true
}],
address: {
street: 'Rossaveel',
city: 'Galway',
state: 'Galway',
country: 'Ireland',
postalCode: 'H9189918'
}
},
{
id: '56789',
displayName: 'Mo Salah',
firstName: 'Mo',
lastName: 'Salah',
department: 'Sports',
isFavorite: true,
defaultNumber: '0916979143',
phones: [{
number: '0916979143',
type: 'PHONE_NUMBER_WORK',
isDefault: true
}],
emails: [{
address: 'mosalah@lfc.com',
type: 'EMAIL_ADDRESS_WORK',
isDefault: true
}],
address: {
street: 'Anfield Road',
city: 'Liverpool',
state: 'Liverpool',
country: 'UK',
postalCode: 'L40TH'

97
Widget API Events

}
}
]

See the address-book sample widget for further demonstration.

onEnterpriseServiceAvailableEvent
This event is triggered when the Enterprise Directory service becomes available. Only when this is available should the
Agent be allowed to perform a search.

api.onDataEvent('onEnterpriseServiceAvailableEvent', callback);
function callback() {
// We can now perform a search of the enterprise directory
scope.isEnterpriseContactsServiceAvailable = true;
}

See the address-book sample widget for further demonstration.

onEnterpriseServiceUnavailableEvent
This event is triggered when the Enterprise Directory service becomes unavailable. When this occurs the Agent should not
be allowed to perform a search from the widget. i.e search field should be disabled

api.onDataEvent('onEnterpriseServiceUnavailableEvent', callback);
function callback() {
// Search of the enterprise directory is no longer available
scope.isEnterpriseContactsServiceAvailable = false;
}

See the address-book sample widget for further demonstration.

onCustomCardDeletedEvent
This event is triggered when a custom card has been deleted

api.onDataEvent('onCustomCardDeletedEvent', callback);
function callback() {
// do something with the event data
console.log(data);
}

See the hello-world sample widget for further demonstration.

onCardFocusedEvent
This event is triggered when the interaction is focused

98
Widget API Events

api.onDataEvent('onCardFocusedEvent', callback);
function callback(data) {
// We can do something when an interaction is focused
}

See the hello-world sample widget for further demonstration.

onSSOTokenRefreshEvent
This event is triggered when the SSO token is refreshed

api.onDataEvent('onSSOTokenRefreshEvent', callback);
function callback(data) {
// We can do something here with the new token
}

99
Widget Build Tools

Using the Build Tools


Requirements
NodeJS v6.11.3 TLS (or higher)
NPM 5.3.0 (or higher)
Grunt task runner

Install
Download and unzip the sample-project.zip file:

unzip sample-project.zip

Install the Grunt task runner:

npm install -g grunt-cli

Install the NPM package dependencies:

npm install

Usage

Create a widget
Use the following Grunt task to create a new widget:

grunt create_widget --name="my-widget" --library="My library"

The widget will be created in a folder called: library .

Build a widget
Use the following Grunt task to build and bundle the widget:

grunt --build="my-widget"

The widget will be created in a folder called: bundle .

Import a widget
Please see the Widget Manager section for information on how to import a widget.

Clear bundle folder


Use the following Grunt task to clean and remove all the files in the bundle folder:

grunt clean

100
Widget Build Tools

101
Using Sample Library

Using the Sample Widget Library


Requirements
NodeJS v6.11.3 TLS (or higher)
NPM 5.3.0 (or higher)
Grunt task runner

Install
Download and unzip the sample-library.zip file:

unzip sample-library.zip

Install the Grunt task runner:

npm install -g grunt-cli

Install the NPM package dependencies:

npm install

Note: The following commands must be running in your terminal/console.

Usage

Build a sample widget


Use the following Grunt task to build any of the sample widgets in the library:

grunt --build="hello-world"

The hello-world widget will be built in a folder called: bundle .

Import a sample widget


After you have built the hello-world widget, you can navigate to the bundle folder and import the hello-world.json
configuration file using the Widget Manager in the Workspaces Administrator UI.

Note: The hello-world.json file is located in the bundle/hello-world/ folder.

Import Sample Library


To import all the widgets in the sample library you will have to import the library.json file inside the bundle folder using the
Widget Manager in the Workspaces Administrator UI. This will import all widgets in bulk.

102
Using Sample Library

103
Hosting Widgets

Hosting Widgets
Hosting the Sample Widget Library
To test your widgets, you need to host the sample widget library using a web server. You can use any standard web server (e.g.
http-server, nginx). You will need to deploy the web server using HTTPS and configure the security certificates appropriately.

If using self-signed certificates, you have to make sure the certificates are installed and trusted on the browser or OS environment.
Otherwise the browser will not trust the self-signed certificate and prevent Workspaces from loading the widgets.

It is also very important that the server is enabled with CORS. You can check how to enable CORS on your web server.

Here are some links of to CORS configuration instructions:

If you host the library on Breeze Snap-in, please refer to 'Administering HTTP CORS security' section in Administering
Avaya Breeze® platform document
If you host the library on Tomcat server, please refer to this instruction: https://tomcat.apache.org/tomcat-7.0-
doc/config/filter.html#CORS_Filter
You can also find more information for different servers on https://www.w3.org/wiki/CORS_Enabled

It is important that the directory hosted is the bundle directory. This is the output destination of the build process used to build the
sample library.

Here is an example using http-server which is a simple web server that can be installed via NodeJS:

# install http-server via NPM


npm install -g http-server

# run the web server over HTTPS on port 8443 with CORS enabled
http-server ./sample-library/bundle -p 8443 --cors -S -C cert.pem -K key.pem

By default, http-server will start the server using your local IP address on port 8443. Once running, you should see something like
this:

Starting up http-server, serving sample-library/bundle/


Available on:
https://127.0.0.1:8443
https://192.168.60.100:8443
Hit CTRL-C to stop the server

Web Server Requirements when hosting widgets in production


1. The web server should be hosted on the same network as the Avaya Workspaces Solution.
2. The web server should have a network RTT of less than 120ms.
3. The web server should be configured for CORS
4. The web server should be configured with HTTPS

104
Hosting Widgets

105
Widget Server Configuration

ACM Configuration (Oceana & Elite)


Enable the Widget Library URL
To allow Workspaces to load your sample widget library you will need to enable and configure the Library URL in ACM (Avaya
Control Manager).

CCMM Configuration (AACC)


Enable the Widget Library URL
To allow Workspaces to load your sample widget library you will need to enable and configure the Library URL in CCMM
(Contact Center Multimedia Manager).

106
Widget Server Configuration

107
Capabilities

Capabilities
The Widget Framework uses the concept of capabilities to indicate the current capability of an Agent to perform an operation.

For example:

Interaction Capabilities
canAccept, canHold, canUnhold, canSendMessage etc.

Agent Capabilities
canLogin, canSetReady, canSetNotReady, canLogout, canSetAdditionalWork etc.

Capabilities are set by the Server, and should be taken as an indication that the operation will succeed if attempted. Please see the
getCapabilities method and onCapabilitiesChangedEvent event for usage.

108
Using Web Components

Using Web Components as Widgets in Workspaces


As an alternative to using the AngularJS directive created by the widget framework CLI tool, Web Components can be used
instead. Workspaces will accept a Web Component developed using any framework provided it conforms to Web Component
standards. This allows developers to use whatever framework they are comfortable with while still utilizing the Workspaces
Widget API.

Building Web Components for Workspaces


Creating an instance of the Widget API for use within a web component slightly differs from creating an instance of the widget
API for use within the AngularJS directive created by the Widget Framework CLI.

The attributes that will be applied to your Web Component by Workspaces need to be parsed and passed to the Widget API
constructor.

class AgentComponent extends HTMLElement {


constructor() {
super();
}

connectedCallback() {
// Get parameters passed to the web component as attributes by workspaces.
const interactionId = this.getAttribute("interaction-id");
const workRequestId = this.getAttribute("work-request-id");
const externalInteractionId = this.getAttribute("external-interaction-id");

// Create widget API passing in parameters


// Note: it is important the keys in the JSON passed to this method are as given
const api = window.NewAvayaWidgetAPI({
interactionId,
workRequestId,
externalInteractionId
});

// Use API As per documentation

// Code excluded for brevity......


}
}
// Define Web Component
customElements.define("agent-web-component", AgentComponent);

The widget API is created by calling the globally available method NewAvayaWidgetAPI . This method returns a new instance of
the Widget API for use by the calling widget. Once the instance of the widget API has been created using the example above the
widget API can be used as it would normally be used within the AngularJS directive generated by the Widget Framework CLI.

Web Component Config Example


Below is an example of a Widget JSON for a web component. Note that the files array here is used to refer to the location of the
Web Component and not to dependant files. Unlike the files array for the AngularJS directive based widgets, this URL does not
depend on the configured widget library URL detailed in the Widget Server Configuration section of this documentation. This
means Web Components, unlike AngularJS based widgets, can be served from different locations, irrespective of the configured
Widget Library URL in ACM

The same rules apply to the below definition as listed here with the following additions:

configuration.files array should contain a single URL pointing to the Web Component source code

109
Using Web Components

The configuration.element property must match what the web component defines in its call to customElements.define

{
"metadata": {
"name": "Agent Component Test",
"description": "This is to test web component for agent state",
"tags": "agent, customer, details, salesforce, CRM, voice",
"version": "",
"date": "2017-01-24T12:01:51.684Z",
"id": "c79c964b-7427-4d5f-9384-ad316e9a3e21"
},
"configuration": {
"external": true,
"enabled": true,
"name": "c79c964b-7427-4d5f-9384-ad316e9a3e21",
"icon": "aoc-home",
"element": "<agent-web-component></agent-web-component>",
"permissions": [],
"shortcuts": [],
"localisation": [],
"files": ["http://localhost:4003/agent-web-component.js"]
}
}

Full Web Component Example code


This widget displays Agent Details in a table by subscribing to the widget API onDataEvent.

class AgentComponent extends HTMLElement {


constructor() {
super();
}

connectedCallback() {
// Get parameters passed to the web component as attributes by context canvas.
const interactionId = this.getAttribute("interaction-id");
const workRequestId = this.getAttribute("work-request-id");
const externalInteractionId = this.getAttribute("external-interaction-id");

// Create widget API passing in parameters


const api = window.NewAvayaWidgetAPI({
interactionId,
workRequestId,
externalInteractionId
});

api.onDataEvent("onAgentStateEvent", data => {


this.replaceTemplate(data);
});
const div = document.createElement("div");

div.innerHTML = this.getTemplate();
div.style.height = "100%";
this.style.width = "100%";
this.style.height = "100%";
this.appendChild(div);
}

// Returns html to use in component


getTemplate(message) {
return `
<div class="neo-widget" style="height:100%;">
<div class="neo-widget__header neo-icon-home">Agent Details</div>
<div class="neo-widget__content neo-widget__content--indented">
<div class="neo-empty-state">
<div id="simpleTemplateDiv">${message}</div>

110
Using Web Components

</div>

</div>
</div>
</div>`;
}

replaceTemplate(data) {
const templateDiv = this.querySelector("#simpleTemplateDiv");
let innerHTML = `<table class="neo-table"><thead>
<th>Attribute</th>
<th>Value</th>
</thead>
<tbody>
<tr>
<td>
State
</td>
<td>
${data.state}
</td>
</tr>
<tr>
<td>
Reason Code
</td>
<td>
${data.reasonCode}
</td>
</tr>`;

for (let prop in data.agent.capabilities) {


innerHTML += `<tr><td>${prop}</td><td>${
data.agent.capabilities[prop]
}</td></tr>`;
}

innerHTML += `</tbody></table>`;
templateDiv.innerHTML = innerHTML;
}
}
// Define Web Component
customElements.define("agent-web-component", AgentComponent);

111
Hello World

Hello World
The hello-world widget demonstrates the Widget API and Widget API Events triggered when a work card appears.

angular.module('a04a5141-9a48-4dc5-a7b6-ecb913671060', [
'core.services.WidgetAPI'
]).directive('helloWorld', widgetComponent);

function widgetComponent(WidgetAPI) {

function widgetContainer(scope, element, params) {


var api = new WidgetAPI(params);

scope.sayHello = function(message) {
api.sendMessage(message, 'random-id');
api.sendNotification('info', 'Widget: ' + message);
};

// interaction event fired when a new interaction comes in or has been updated
api.onDataEvent('onInteractionEvent', function(data) {
scope.interaction = data;
});

// interaction ended event fired when the interaction card has ended
api.onDataEvent('onInteractionEndedEvent', function(data) {
scope.interactionEnded = data;
});

// customer data from CRM (voice only)


api.onDataEvent('onCRMDataEvent', function(data) {
scope.customer = data;
});

// interaction context data


api.onDataEvent('onContextDataEvent', function(data) {
scope.context = data;
});

// media data from chat, sms, email and social interactions


api.onDataEvent('onMediaEvent', function(data) {
scope.media = data;
});

// media message data from chat, sms, email and social interactions
api.onDataEvent('onMediaMessageEvent', function(data) {
scope.media = data;
});

// page push url message data from chat, sms, social


api.onDataEvent('onPagePushUrlEvent', function(data) {
scope.pagePushUrl = data;
});

// triggered on agent state changes


api.onDataEvent('onAgentStateEvent', function(data) {
scope.agent = data;
});

// triggered when the widget receives a message from another widget


api.onDataEvent('onMessageEvent', function(data) {
scope.message = data;
});

// triggered on navigation change


api.onDataEvent('onNavigationEvent', function(data) {

112
Hello World

scope.navigation = data;
});

// triggered on language change


api.onDataEvent('onLocaleUpdatedEvent', function(data) {
scope.locale = data;
api.sendNotification('info', 'Widget: Locale was changed');
});

// event fired when a custom card is deleted


api.onDataEvent('onCustomCardDeletedEvent', function(data) {
scope.customCardDeleted = data;
});

// called when widget is destroyed


element.on('$destroy', function() {
api.unregister();
scope.$destroy();
});

return {
scope: {},
replace: true,
template: template,
link: widgetContainer
};
}

113
Widget Communication

Widget Communication
The Widget Framework has a feature to allow widgets to communicate with each other. Widget to widget communication is
intended so that two or more widgets can communicate with each other within a single instance of Workspaces and only when the
agent is presented a work card.

For example, when an agent receives a call and accepts the work card, two or more widgets can communicate and access details
about the call and perform actions such as querying a remote database or loading web page, etc.

Widget communication only occurs within the context of the work card, which means that if an agent has several work cards,
widgets can only communicate with each other and only within the bounds of their own work card type (voice, chat, email, etc.).

Widget to widget communication can be implemented by using the sendMessage() Widget API method. There are two modes
that widgets can use to communicate with each other: unicast and multicast.

Multicast widget communication


Here is an example of how multicast widget to widget communication can be implemented.

// Widget A sends a message to Widget B


angular.module('a04a5141-9a48-4dc5-a7b6-ecb913671060', [
'core.services.WidgetAPI'
]).directive('aliceWidget', widgetComponent);

// Widget A sends a message to Widget B


function widgetComponent(WidgetAPI) {
function widgetContainer(scope, element, params) {
var api = new WidgetAPI(params);
// send the string message 'This is a message from Alice' to Widget B
api.sendMessage('This is a message from Alice');
// you can also send data objects
api.sendMessage({ name: 'Alice', email: 'alice@email.com'});
}
return {
scope: {},
replace: true,
template: template,
link: widgetContainer
};
}

In this example, we use the sendMessage() Widget API method to broadcast to all the widgets listening on the onMessageEvent
Widget API event.

// Widget B listens and receives message from Widget A


angular.module('4fb7cac3-a96b-44ae-93f0-1fc97f387062', [
'core.services.WidgetAPI'
]).directive('bobWidget', widgetComponent);

function widgetComponent(WidgetAPI) {
function widgetContainer(scope, element, params) {
var api = new WidgetAPI(params);
// listen for a message event
api.onDataEvent('onMessageEvent', function(message) {
// do something with the message
console.log(message);
});
}
return {

114
Widget Communication

scope: {},
replace: true,
template: template,
link: widgetContainer
};
}

Unicast widget communication


Here is an example of how unicast widget to widget communication can be implemented.

// Widget A sends a message to Widget B


angular.module('a04a5141-9a48-4dc5-a7b6-ecb913671060', [
'core.services.WidgetAPI'
]).directive('aliceWidget', widgetComponent);

// Widget A sends a message to Widget B


function widgetComponent(WidgetAPI) {
function widgetContainer(scope, element, params) {
var api = new WidgetAPI(params);
// send the message using the ID string 'unique-random-id'
api.sendMessage('Hello Bob, this is Alice!', 'unique-random-id');
}
return {
scope: {},
replace: true,
template: template,
link: widgetContainer
};
}

In this code example above, we use the sendMessage() Widget API method and use an unique identifier string as the second
argument.

The unique identifier string is used to send the message data to a specific widget that is listening for it, in this case Widget B. The
code example below, shows how Widget B listens for the onMessageEvent using the unique-random-id as the identifier for
receiving data.

// Widget B listens and receives message from Widget A


angular.module('4fb7cac3-a96b-44ae-93f0-1fc97f387062', [
'core.services.WidgetAPI'
]).directive('bobWidget', widgetComponent);

function widgetComponent(WidgetAPI) {
function widgetContainer(scope, element, params) {
var api = new WidgetAPI(params);
// listen for a message event with ID 'unique-random-id'
api.onDataEvent('onMessageEvent:unique-random-id', function(message) {
// do something with the message
console.log(message);
});
}
return {
scope: {},
replace: true,
template: template,
link: widgetContainer
};
}

115
Widget Communication

Note: You can select any unique identifier as long as it is passed as a string.

To see a live code example, you can use the hello-world and message-echo widgets to send and receive messages. These
widgets are part of the Sample Widget Library included in the Widget Framework documentation.

116
Prompted Digits

Prompted Digits
Prompted digits can be obtained from Context Store data using the widget API. These digits can then be used to trigger behaviour
in workspaces such as opening a PDF relating to a customer ID as demonstrated in the prompt-digits sample widget.

The context store information is retrieved by subscribing to the 'onConextDataEvent' as shown below.

The prompt-digits widget subscribes to the onContextDataEvent and passes a url to an iFrame hosted by the widget that will
retrieve a pdf corresponding to the prompt digits retrieved from context store.

var api = new WidgetAPI(params);

scope.trustAsResourceUrl = function(url) {
return $sce.trustAsResourceUrl(url);
};

api.onDataEvent('onContextDataEvent', function(data) {
scope.context = data.contextStore[0].data;
scope.pdfUrl = localStorage.getItem('_cc.libraryUrl') + '/prompt-digits/assets/' + data.contextStore[0].d
ata + '.pdf';
});

<div class="neo-widget">

<div class="neo-widget__header aoc-home">Prompt Digits</div>

<div class="neo-widget__content">
<iframe src="{% raw %}{{ ::pdfUrl }}{% endraw %}" width="100%" height="100%" frameborder="0" allowfullscreen
></iframe>
</div>

</div>

117
Localisation

Localisation of Widgets
The Widget Framework does not provide widget developers with a built-in facility for localising their widgets. You can use the
angular-gettext package or other packages to localise your widgets.

The angular-gettext package is the same package that Workspaces uses to perform localisation.

The angular-gettext package uses the gettext format (.po) which is commonly used in many web applications and Linux OS
distributions. You can read about some of the advantages of using the gettext format here.

The steps to localise your widgets are as follows:

Write your widget in English


Annotate the strings that should be translated
Use the angular-gettext tools to extract those strings to a translation template
Use any of the angular-gettext recommended tools to translate your strings
Once translated, use the same tools to embed the JSON file translations back into your widget

In addition you may also want to implement Right-to-Left language support in your widget

Localisation Example
Here is a code example of a widget that angular-gettext package for localisation.

angular.module('831e9ed6-2416-427c-8f04-ccee6e89790a', [
'gettext',
'core.services.WidgetAPI'
]).directive('localisedWidget', widgetComponent);

function widgetComponent(WidgetAPI) {
function widgetContainer(scope, element, params) {
// widget API constructor
var api = new WidgetAPI(params);
}

return {
scope: {},
replace: true,
template: template,
link: widgetContainer
};
}

You need to use Angular's dependency injection (DI) system and include 'gettext' as a module in your widget (see code
above).

To perform the string annotations, angular-gettext uses the translate directive. You need to add the translate directive
to HTML elements you want angular-gettext to translate.

The HTML template below shows several examples on how to use the translate directive to annotate strings for translation.

<div class="neo-widget">
<div class="neo-widget__header aoc-home" translate>Localised Widget</div>
<div class="neo-widget__content neo-widget__content--indented">
<div class="row">
<div class="col-medium-12 col-large-12">
<p translate>This string will be translated</p>
<p translate>You can also use string interpolation, for example: {{ hello }}</p>
<p translate>Input attributes can also be translated: </p>

118
Localisation

<input type="text" placeholder="{% raw %}{{ 'Username' | translate }}{% endraw %}" />
</div>
</div>
</div>
</div>

You also need to include the angular-gettext JavaScript library in your widget's JSON configuration file so that angular-
gettext is loaded by your widget.

Here is an example of how your widget's JSON configuration should look like:

{
"metadata": {
"name": "Localised Widget",
"description": "Please add widget description here",
"tags": "demo, widget, example, other",
"library": "My Library",
"version": "1.0.0",
"date": "2017-09-26T12:32:15.618Z",
"id": "831e9ed6-2416-427c-8f04-ccee6e89790a"
},
"configuration": {
"external": true,
"timeout": 5000,
"serie": true,
"name": "831e9ed6-2416-427c-8f04-ccee6e89790a",
"element": "<localised-widget></localised-widget>",
"icon": "aoc-home",
"files": [
"localised-widget/libs/angular-gettext.min.js",
"localised-widget/localised-widget.css",
"localised-widget/localised-widget.js"]
}
}

Extracting strings
Now that you have annotated your widget. You can use the following Grunt plugin to extract the strings automatically from your
widget HML templates.

Follow the instructions on how to install and use the Grunt plugin.
Follow the instructions on how translate your strings (.po) files using the recommended tools.
Include the translations.js file to your widget's JSON configuration file.

For more information please refer to the angular-gettext developer guide.

Implementing Right-To-Left support

In stylesheets
In order to support Right-To-Left languages you may need to change something in your widget stylesheets to prevent incorrect
widget rendering.

Here you have at least two different options:

To write all the necessary RTL styles in the same stylesheet file using the [dir="rtl"] root selector

.my-widget-button {
margin-left: 15px;
}

119
Localisation

// Everything will render correctly for both LTR and RTL


[dir="rtl"] .my-widget-button {
margin-left: 0;
margin-right: 15px;
}

Or to split stylesheets for LTR and RTL into two different stylesheet files, like localised-widget.css and localised-
widget.rtl.css , so Workspaces will be able to lazy-load necessary stylesheet files of your widget when agent switches

between locales. Such an approach implies you to explicitly specify "bidi-alternative" stylesheet files in widget's JSON
configuration by surrounding these in sub-array (first filename entry stands for LTR, second - for RTL) as follows:

{
"metadata": {
"name": "Localised Widget",
"description": "Please add widget description here",
"tags": "demo, widget, example, other",
"library": "My Library",
"version": "1.0.0",
"date": "2017-09-26T12:32:15.618Z",
"id": "831e9ed6-2416-427c-8f04-ccee6e89790a"
},
"configuration": {
"external": true,
"timeout": 5000,
"serie": true,
"name": "831e9ed6-2416-427c-8f04-ccee6e89790a",
"element": "<localised-widget></localised-widget>",
"icon": "aoc-home",
"files": [
"localised-widget/libs/angular-gettext.min.js",
["localised-widget/localised-widget.css", "localised-widget/localised-widget.rtl.css"],
"localised-widget/localised-widget.js"]
}
}

In the 2nd case please note: executing grunt --build="..." command will concatenate all your stylesheet files into the
single one. In order to prevent LTR and RTL styles collision, just make sure that all your stylesheets for RTL have
.rtl.css in the filename ending. Thus all your stylesheets will be separately concatenated into localised-widget.css

and localised-widget.rtl.css depending on corresponding filenames.

In JavaScript code
Checkout the following WidgetAPI documentation entries to handle RTL issues in your JavaScript code:

bidi method
onLocaleUpdatedEvent event
onBeforeTextDirectionChangedEvent event
onStylesheetsReadyEvent event

120

You might also like