Skip to content

Commit ac80f34

Browse files
committed
Merge branch 'next' of github.com:webex/webex-js-sdk into MULTI_PARTY_CONFERENCE
2 parents ce038aa + 8bb550b commit ac80f34

File tree

95 files changed

+2459
-215
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+2459
-215
lines changed

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
lts/gallium
1+
lts/jod

docs/samples/contact-center/app.js

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ let consultationData = null; // Track who we consulted with for conference
1515
let entryPointId = '';
1616
let stateTimer;
1717
let currentConsultQueueId;
18+
let outdialANIId; // Store outdial ANI ID from agent profile
1819

1920
const authTypeElm = document.querySelector('#auth-type');
2021
const credentialsFormElm = document.querySelector('#credentials');
@@ -95,6 +96,7 @@ const agentLoginInputError = document.getElementById('agent-login-input-error');
9596
const applyupdateAgentProfileBtn = document.querySelector('#applyupdateAgentProfile');
9697
const autoWrapupTimerElm = document.getElementById('autoWrapupTimer');
9798
const timerValueElm = autoWrapupTimerElm.querySelector('.timer-value');
99+
const outdialAniSelectElm = document.querySelector('#outdialAniSelect');
98100
deregisterBtn.style.backgroundColor = 'red';
99101

100102
function isIncomingTask(task, agentId) {
@@ -897,28 +899,84 @@ function updateConferenceButtonState(task, isConsultationInProgress) {
897899
}
898900
}
899901

902+
// Function to load outdial ANI entries
903+
async function loadOutdialAniEntries(outdialANIId) {
904+
905+
try {
906+
console.log('Using outdial ANI ID:', outdialANIId);
907+
// Call the getOutdialAniEntries method from the SDK
908+
const aniResponse = await webex.cc.getOutdialAniEntries({
909+
outdialANI: outdialANIId
910+
});
911+
console.log('The request to get outdial ANI entries was successful, the response is:', aniResponse)
912+
913+
// Clear existing options except the first one
914+
outdialAniSelectElm.innerHTML = '<option value="">Select Outdial Ani...</option>';
915+
916+
// Get the ANI list from the response - it's directly an array
917+
const aniList = aniResponse || [];
918+
if (aniList.length === 0) {
919+
const option = document.createElement('option');
920+
option.value = '';
921+
option.text = 'No ANI numbers available';
922+
option.disabled = true;
923+
outdialAniSelectElm.add(option);
924+
console.log('No outdial ANI entries found');
925+
return;
926+
}
927+
928+
// Map and populate the select with ANI options
929+
aniList.forEach((ani) => {
930+
const option = document.createElement('option');
931+
option.value = ani.number; // Use number as value
932+
option.text = ani.name; // Use name as display text
933+
outdialAniSelectElm.add(option);
934+
});
935+
936+
console.log(`Loaded ${aniList.length} outdial ANI entries`);
937+
938+
} catch (error) {
939+
console.error('Failed to load outdial ANI entries:', error);
940+
alert('Failed to load outdial ANI entries', error)
941+
// Add error option to select
942+
outdialAniSelectElm.innerHTML = '<option value="">Select Caller ID...</option>';
943+
const errorOption = document.createElement('option');
944+
errorOption.value = '';
945+
errorOption.text = 'Error loading ANI numbers';
946+
errorOption.disabled = true;
947+
outdialAniSelectElm.add(errorOption);
948+
}
949+
}
900950
// Function to start an outdial call.
901951
async function startOutdial() {
902952

903953
const destination = document.getElementById('outBoundDialNumber').value;
954+
const selectedAni = outdialAniSelectElm.value;
904955

905956
if (!destination || !destination.trim()) {
906957
alert('Destination number is required');
907958
return;
908959
}
909960

910-
if (!entryPointId) {
911-
alert('Entry point ID is not configured');
961+
if (!entryPointId || !entryPointId.trim()) {
962+
alert('Entry Point ID is required for outdial');
912963
return;
913964
}
914965

915966
try {
916967
console.log('Making an outdial call');
917-
await webex.cc.startOutdial(destination);
918-
console.log('Outdial call initiated successfully');
968+
console.log('Destination:', destination);
969+
console.log('Selected ANI:', selectedAni || 'None selected');
970+
971+
// Use selected ANI as the origin parameter
972+
if (selectedAni) {
973+
await webex.cc.startOutdial(destination, selectedAni);
974+
console.log('Outdial call initiated successfully with ANI:', selectedAni);
975+
}
976+
919977
} catch (error) {
920978
console.error('Failed to initiate outdial call', error);
921-
alert('Failed to initiate outdial call');
979+
alert('Failed to initiate outdial call: ' + (error.message || error));
922980
}
923981
}
924982

@@ -1444,6 +1502,11 @@ function register() {
14441502
wrapupCodes = agentProfile.wrapupCodes;
14451503
agentDeviceType = agentProfile.deviceType;
14461504
populateWrapupCodesDropdown();
1505+
outdialANIId = agentProfile.outdialANIId;
1506+
loadOutdialAniEntries(agentProfile.outdialANIId).catch(error => {
1507+
console.warn('Failed to load ANI entries during registration:', error);
1508+
})
1509+
14471510
listTeams.forEach((team) => {
14481511
const option = document.createElement('option');
14491512
option.value = team.id;
@@ -1557,7 +1620,6 @@ function register() {
15571620
dialNumber.disabled = false;
15581621
dialNumber.value = data.dn || '';
15591622
}
1560-
15611623
const auxId = data.auxCodeId?.trim() || '0';
15621624
const idx = [...idleCodesDropdown.options].findIndex(o => o.value === auxId);
15631625
idleCodesDropdown.selectedIndex = idx >= 0 ? idx : 0;
@@ -1716,6 +1778,10 @@ function logoutAgent() {
17161778
logoutAgentElm.classList.add('hidden');
17171779
agentLogin.selectedIndex = 0;
17181780
timerElm.innerHTML = '00:00:00';
1781+
1782+
// Clear outdial ANI select
1783+
outdialAniSelectElm.innerHTML = '<option value="">Select Caller ID...</option>';
1784+
17191785
updateUnregisterButtonState();
17201786
}, 1000);
17211787

docs/samples/contact-center/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,12 @@ <h2 class="collapsible">
271271
<fieldset>
272272
<legend>Outdial Call</legend>
273273
<div class="keypad">
274+
<div style="margin-bottom: 10px;">
275+
<label for="outdialAniSelect">Caller ID (ANI):</label>
276+
<select id="outdialAniSelect" style="width: 100%; margin-bottom: 10px;">
277+
<option value="">Select Outdial Ani...</option>
278+
</select>
279+
</div>
274280
<input id="outBoundDialNumber" placeholder="Enter number to dial">
275281
<div class="keys">
276282
<div class="key" onclick="pressKey('1')">1</div>

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
"license": "Cisco's General Terms (https://www.cisco.com/site/us/en/about/legal/contract-experience/index.html)",
2121
"author": "[email protected]",
2222
"engines": {
23-
"node": "16.x",
24-
"npm": ">=6.x"
23+
"node": "18.x",
24+
"npm": ">=10.5"
2525
},
2626
"main": "src/index.js",
2727
"repository": {
@@ -82,7 +82,7 @@
8282
},
8383
"devDependencies": {
8484
"@babel/cli": "^7.17.10",
85-
"@babel/core": "^7.17.10",
85+
"@babel/core": "^7.27.1",
8686
"@babel/eslint-parser": "^7.17.0",
8787
"@babel/generator": "^7.24.7",
8888
"@babel/node": "^7.14.9",

packages/@webex/common-evented/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"directory": "packages/@webex/common-evented"
1111
},
1212
"engines": {
13-
"node": ">=16"
13+
"node": ">=18"
1414
},
1515
"browserify": {
1616
"transform": [

packages/@webex/common-timers/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"directory": "packages/@webex/common-timers"
1111
},
1212
"engines": {
13-
"node": ">=16"
13+
"node": ">=18"
1414
},
1515
"browserify": {
1616
"transform": [

packages/@webex/contact-center/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"lodash": "^4.17.21"
5757
},
5858
"devDependencies": {
59+
"@babel/core": "^7.22.11",
5960
"@babel/preset-typescript": "7.22.11",
6061
"@types/jest": "27.4.1",
6162
"@typescript-eslint/eslint-plugin": "5.38.1",

packages/@webex/contact-center/src/cc.ts

Lines changed: 132 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,20 @@ import {
3838
MERCURY_DISCONNECTED_SUCCESS,
3939
METHODS,
4040
} from './constants';
41+
import {AGENT_STATE_AVAILABLE, AGENT_STATE_AVAILABLE_ID} from './services/config/constants';
4142
import {AGENT, WEB_RTC_PREFIX} from './services/constants';
4243
import Services from './services';
4344
import WebexRequest from './services/core/WebexRequest';
4445
import LoggerProxy from './logger-proxy';
4546
import {StateChange, Logout, StateChangeSuccess, AGENT_EVENTS} from './services/agent/types';
4647
import {getErrorDetails, isValidDialNumber} from './services/core/Utils';
47-
import {Profile, WelcomeEvent, CC_EVENTS} from './services/config/types';
48-
import {AGENT_STATE_AVAILABLE, AGENT_STATE_AVAILABLE_ID} from './services/config/constants';
48+
import {
49+
Profile,
50+
WelcomeEvent,
51+
CC_EVENTS,
52+
OutdialAniEntriesResponse,
53+
OutdialAniParams,
54+
} from './services/config/types';
4955
import {ConnectionLostDetails} from './services/core/websocket/types';
5056
import TaskManager from './services/task/TaskManager';
5157
import WebCallingService from './services/WebCallingService';
@@ -1330,6 +1336,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
13301336
* Makes an outbound call to a specified phone number.
13311337
*
13321338
* @param {string} destination - The phone number to dial (e.g., '+1234567890').
1339+
* @param {string} origin - The contact center number that will be used while making a call to the customer.
13331340
* Should include country code and be in E.164 format.
13341341
* @returns {Promise<TaskResponse>} Resolves with the task response containing:
13351342
* - interactionId: Unique identifier for the outbound call
@@ -1365,7 +1372,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
13651372
*
13661373
* // Start the outbound call
13671374
* const destination = '+1234567890';
1368-
* const task = await cc.startOutdial(destination);
1375+
* const task = await cc.startOutdial(destination, origin);
13691376
*
13701377
* // Listen for all relevant task events
13711378
* task.on('task:ringing', () => {
@@ -1433,7 +1440,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
14331440
* }
14341441
* ```
14351442
*/
1436-
public async startOutdial(destination: string): Promise<TaskResponse> {
1443+
public async startOutdial(destination: string, origin: string): Promise<TaskResponse> {
14371444
LoggerProxy.info('Starting outbound dial', {
14381445
module: CC_FILE,
14391446
method: METHODS.START_OUTDIAL,
@@ -1447,6 +1454,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
14471454
// Construct the outdial payload.
14481455
const outDialPayload: DialerPayload = {
14491456
destination,
1457+
origin,
14501458
entryPointId: this.agentConfig.outDialEp,
14511459
direction: OUTDIAL_DIRECTION,
14521460
attributes: ATTRIBUTES,
@@ -1461,6 +1469,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
14611469
{
14621470
...MetricsManager.getCommonTrackingFieldForAQMResponse(result),
14631471
destination,
1472+
origin,
14641473
mediaType: OUTDIAL_MEDIA_TYPE,
14651474
},
14661475
['behavioral', 'business', 'operational']
@@ -1481,6 +1490,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
14811490
{
14821491
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failure),
14831492
destination,
1493+
origin,
14841494
mediaType: OUTDIAL_MEDIA_TYPE,
14851495
},
14861496
['behavioral', 'business', 'operational']
@@ -1490,6 +1500,124 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
14901500
}
14911501
}
14921502

1503+
/**
1504+
* Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
1505+
*
1506+
* This method retrieves the list of phone numbers that can be used as caller ID when making
1507+
* outbound calls. The ANI data is associated with an outdial ANI ID and can be filtered
1508+
* and paginated as needed.
1509+
*
1510+
* @param {string} outdialANI - The outdial ANI ID to fetch ANI data for
1511+
* @param {number} [page] - Optional page number for pagination (0-based)
1512+
* @param {number} [pageSize] - Optional number of items per page
1513+
* @param {string} [search] - Optional search term to filter results by name or number
1514+
* @param {string} [filter] - Optional filter string
1515+
* @param {string} [attributes] - Optional attributes to include in response
1516+
* @returns {Promise<OutdialAniEntriesResponse>} Promise resolving to outdial ANI response containing:
1517+
* - data: Array of ANI entries with number and name
1518+
* - meta: Pagination metadata
1519+
* @throws {Error} If the operation fails or agent is not registered
1520+
* @public
1521+
* @example
1522+
* ```typescript
1523+
* const cc = webex.cc;
1524+
* await cc.register();
1525+
*
1526+
* // Get agent profile to obtain outdial ANI ID
1527+
* const agentProfile = cc.agentConfig;
1528+
* const outdialANI = agentProfile.outdialANIId;
1529+
*
1530+
* // Basic usage - get all ANI data for an outdial ANI ID
1531+
* const aniData = await cc.getOutdialAniEntries({ outdialANI });
1532+
*
1533+
* // With pagination and search
1534+
* const paginatedAni = await cc.getOutdialAniEntries({
1535+
* outdialANI,
1536+
* page: 0,
1537+
* pageSize: 50,
1538+
* search: '555' // search for numbers containing '555'
1539+
* });
1540+
*
1541+
* // Process the results
1542+
* paginatedAni.forEach(ani => {
1543+
* console.log(`ANI: ${ani.number} - ${ani.name}`);
1544+
* });
1545+
* ```
1546+
*/
1547+
public async getOutdialAniEntries(params: OutdialAniParams): Promise<OutdialAniEntriesResponse> {
1548+
const {outdialANI, page, pageSize, search, filter, attributes} = params;
1549+
1550+
LoggerProxy.info('Fetching outdial ANI entries', {
1551+
module: CC_FILE,
1552+
method: METHODS.GET_OUTDIAL_ANI_ENTRIES,
1553+
});
1554+
1555+
const orgId = this.$webex.credentials.getOrgId();
1556+
1557+
if (!orgId) {
1558+
LoggerProxy.error('Org ID not found.', {
1559+
module: CC_FILE,
1560+
method: METHODS.GET_OUTDIAL_ANI_ENTRIES,
1561+
});
1562+
1563+
throw new Error('Org ID not found.');
1564+
}
1565+
1566+
try {
1567+
const result = await this.services.config.getOutdialAniEntries(orgId, {
1568+
outdialANI,
1569+
page,
1570+
pageSize,
1571+
search,
1572+
filter,
1573+
attributes,
1574+
});
1575+
1576+
this.metricsManager.trackEvent(
1577+
METRIC_EVENT_NAMES.OUTDIAL_ANI_EP_FETCH_SUCCESS,
1578+
{
1579+
outdialANI,
1580+
resultCount: result?.length || 0,
1581+
},
1582+
['behavioral', 'business', 'operational']
1583+
);
1584+
1585+
LoggerProxy.log(`Successfully retrieved outdial ANI entries for ANI ID ${outdialANI}`, {
1586+
module: CC_FILE,
1587+
method: METHODS.GET_OUTDIAL_ANI_ENTRIES,
1588+
});
1589+
1590+
return result;
1591+
} catch (error) {
1592+
const failure = error.details as Failure;
1593+
this.metricsManager.trackEvent(
1594+
METRIC_EVENT_NAMES.OUTDIAL_ANI_EP_FETCH_FAILED,
1595+
{
1596+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failure),
1597+
outdialANI,
1598+
error,
1599+
},
1600+
['behavioral', 'business', 'operational']
1601+
);
1602+
1603+
LoggerProxy.error(
1604+
`Failed to fetch outdial ANI entries for ANI ID ${outdialANI} due to: ${error}`,
1605+
{
1606+
module: CC_FILE,
1607+
method: METHODS.GET_OUTDIAL_ANI_ENTRIES,
1608+
trackingId: failure.trackingId,
1609+
}
1610+
);
1611+
1612+
const {error: detailedError} = getErrorDetails(
1613+
error,
1614+
METHODS.GET_OUTDIAL_ANI_ENTRIES,
1615+
CC_FILE
1616+
);
1617+
throw detailedError;
1618+
}
1619+
}
1620+
14931621
/**
14941622
* Uploads logs to help troubleshoot SDK issues.
14951623
*

0 commit comments

Comments
 (0)