@webex/contact-center 3.12.0-llmrefactor.2 → 3.12.0-llmrefactor.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.sdd/manifest.json +5 -4
- package/ai-docs/ARCHITECTURE.md +1 -1
- package/ai-docs/CONTRACTS.md +5 -1
- package/ai-docs/SECURITY.md +1 -1
- package/ai-docs/contact-center-spec.md +22 -4
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/dist/cc.js +440 -10
- package/dist/cc.js.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +10 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +13 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +18 -15
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/AnswerCallOnWebexService.js +174 -0
- package/dist/services/AnswerCallOnWebexService.js.map +1 -0
- package/dist/services/EntryPoint.js +46 -68
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +27 -22
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/WebexCrossClientService.js +171 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +93 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/config/Util.js +3 -0
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +10 -6
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +4 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/WebexRequest.js +6 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +28 -14
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/task/Task.js +73 -7
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskFactory.js +8 -4
- package/dist/services/task/TaskFactory.js.map +1 -1
- package/dist/services/task/TaskManager.js +176 -20
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/WebexCallingUtils.js +70 -0
- package/dist/services/task/WebexCallingUtils.js.map +1 -0
- package/dist/services/task/constants.js +4 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +29 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/digital/Digital.js +3 -2
- package/dist/services/task/digital/Digital.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +135 -37
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +6 -1
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +38 -11
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/types.js.map +1 -1
- package/dist/services/task/state-machine/uiControlsComputer.js +118 -18
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/services/task/types.js +16 -1
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +350 -14
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/services/task/voice/WebRTC.js +4 -1
- package/dist/services/task/voice/WebRTC.js.map +1 -1
- package/dist/services/task/voice/wxAppVoiceMethods.js +201 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppTelephonyUtils.js +19 -0
- package/dist/services/wxAppTelephonyUtils.js.map +1 -0
- package/dist/types/cc.d.ts +77 -4
- package/dist/types/config.d.ts +7 -0
- package/dist/types/constants.d.ts +8 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/services/AddressBook.d.ts +2 -1
- package/dist/types/services/AnswerCallOnWebexService.d.ts +37 -0
- package/dist/types/services/EntryPoint.d.ts +7 -5
- package/dist/types/services/Queue.d.ts +5 -3
- package/dist/types/services/WebexCrossClientService.d.ts +28 -0
- package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
- package/dist/types/services/config/constants.d.ts +8 -5
- package/dist/types/services/config/types.d.ts +17 -4
- package/dist/types/services/core/Err.d.ts +2 -0
- package/dist/types/services/core/WebexRequest.d.ts +1 -0
- package/dist/types/services/core/types.d.ts +2 -0
- package/dist/types/services/task/Task.d.ts +20 -2
- package/dist/types/services/task/TaskFactory.d.ts +2 -1
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +3 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/digital/Digital.d.ts +2 -2
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +260 -56
- package/dist/types/services/task/state-machine/guards.d.ts +6 -5
- package/dist/types/services/task/state-machine/types.d.ts +9 -1
- package/dist/types/services/task/types.d.ts +81 -4
- package/dist/types/services/task/voice/Voice.d.ts +48 -9
- package/dist/types/services/task/voice/WebRTC.d.ts +2 -2
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +52 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +14 -8
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types.js +7 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +19 -5
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/cc.ts +506 -9
- package/src/config.ts +7 -0
- package/src/constants.ts +8 -0
- package/src/index.ts +2 -0
- package/src/metrics/ai-docs/metrics-spec.md +9 -3
- package/src/metrics/behavioral-events.ts +14 -0
- package/src/metrics/constants.ts +2 -0
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +206 -0
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/WebexCrossClientService.ts +212 -0
- package/src/services/WxAppTelephonyMercurySync.ts +115 -0
- package/src/services/ai-docs/AGENTS.md +10 -10
- package/src/services/ai-docs/services-spec.md +6 -1
- package/src/services/config/Util.ts +3 -0
- package/src/services/config/ai-docs/AGENTS.md +1 -1
- package/src/services/config/ai-docs/ARCHITECTURE.md +2 -2
- package/src/services/config/ai-docs/config-spec.md +6 -0
- package/src/services/config/constants.ts +10 -6
- package/src/services/config/types.ts +16 -4
- package/src/services/core/Err.ts +1 -0
- package/src/services/core/WebexRequest.ts +3 -1
- package/src/services/core/ai-docs/core-spec.md +5 -1
- package/src/services/core/aqm-reqs.ts +30 -15
- package/src/services/core/types.ts +2 -0
- package/src/services/task/Task.ts +79 -8
- package/src/services/task/TaskFactory.ts +8 -3
- package/src/services/task/TaskManager.ts +254 -15
- package/src/services/task/WebexCallingUtils.ts +136 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +1 -0
- package/src/services/task/ai-docs/task-spec.md +117 -2
- package/src/services/task/constants.ts +3 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/digital/Digital.ts +4 -2
- package/src/services/task/state-machine/TaskStateMachine.ts +210 -63
- package/src/services/task/state-machine/actions.ts +5 -2
- package/src/services/task/state-machine/ai-docs/AGENTS.md +8 -4
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +17 -8
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +46 -22
- package/src/services/task/state-machine/guards.ts +64 -11
- package/src/services/task/state-machine/types.ts +16 -1
- package/src/services/task/state-machine/uiControlsComputer.ts +206 -32
- package/src/services/task/types.ts +114 -4
- package/src/services/task/voice/Voice.ts +462 -12
- package/src/services/task/voice/WebRTC.ts +5 -1
- package/src/services/task/voice/wxAppVoiceMethods.ts +307 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +33 -9
- package/src/utils/AGENTS.md +21 -10
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +21 -11
- package/test/unit/spec/cc.ts +1274 -0
- package/test/unit/spec/metrics/behavioral-events.ts +18 -0
- package/test/unit/spec/services/AddressBook.ts +37 -6
- package/test/unit/spec/services/AnswerCallOnWebexService.ts +223 -0
- package/test/unit/spec/services/EntryPoint.ts +87 -40
- package/test/unit/spec/services/Queue.ts +123 -12
- package/test/unit/spec/services/WebexCrossClientService.ts +261 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +113 -0
- package/test/unit/spec/services/config/Util.ts +85 -0
- package/test/unit/spec/services/core/WebexRequest.ts +3 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
- package/test/unit/spec/services/task/Task.ts +200 -0
- package/test/unit/spec/services/task/TaskFactory.ts +39 -2
- package/test/unit/spec/services/task/TaskManager.ts +653 -1
- package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
- package/test/unit/spec/services/task/contact.ts +33 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +854 -72
- package/test/unit/spec/services/task/state-machine/guards.ts +210 -8
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +445 -7
- package/test/unit/spec/services/task/voice/Voice.ts +874 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +459 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -240,6 +240,7 @@ All event names are defined in `METRIC_EVENT_NAMES` (`constants.ts`). Events fol
|
|
|
240
240
|
| `TASK_CONFERENCE_END_SUCCESS` / `FAILED` | `'Task Conference End ...'` | Conference end result |
|
|
241
241
|
| `TASK_CONFERENCE_TRANSFER_SUCCESS` / `FAILED` | `'Task Conference Transfer ...'` | Conference transfer result |
|
|
242
242
|
| `TASK_CONFERENCE_EXIT_SUCCESS` / `FAILED` | `'Task Conference Exit ...'` | Conference exit result |
|
|
243
|
+
| `TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS` / `FAILED` | `'Task Conference Participant Drop ...'` | Participant Drop result |
|
|
243
244
|
| `TASK_SWITCH_CALL_SUCCESS` / `FAILED` | `'Task Switch Call ...'` | Switch call result |
|
|
244
245
|
| `WEBSOCKET_REGISTER_SUCCESS` / `FAILED` | `'Websocket Register ...'` | WebSocket registration result |
|
|
245
246
|
| `WEBSOCKET_DEREGISTER_SUCCESS` / `FAIL` | `'Websocket Deregister ...'` | WebSocket deregistration result |
|
|
@@ -277,6 +278,7 @@ All event names are defined in `constants.ts` as `METRIC_EVENT_NAMES`. Events fo
|
|
|
277
278
|
| Conference End | `TASK_CONFERENCE_END_SUCCESS` | `TASK_CONFERENCE_END_FAILED` |
|
|
278
279
|
| Conference Transfer | `TASK_CONFERENCE_TRANSFER_SUCCESS` | `TASK_CONFERENCE_TRANSFER_FAILED` |
|
|
279
280
|
| Conference Exit | `TASK_CONFERENCE_EXIT_SUCCESS` | `TASK_CONFERENCE_EXIT_FAILED` |
|
|
281
|
+
| Conference Participant Drop | `TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS` | `TASK_CONFERENCE_PARTICIPANT_DROP_FAILED` |
|
|
280
282
|
| Switch Call | `TASK_SWITCH_CALL_SUCCESS` | `TASK_SWITCH_CALL_FAILED` |
|
|
281
283
|
| Outdial | `TASK_OUTDIAL_SUCCESS` | `TASK_OUTDIAL_FAILED` |
|
|
282
284
|
| Upload Logs | `UPLOAD_LOGS_SUCCESS` | `UPLOAD_LOGS_FAILED` |
|
|
@@ -297,11 +299,11 @@ Special events (no success/failure pair):
|
|
|
297
299
|
|
|
298
300
|
- `WEBSOCKET_EVENT_RECEIVED` — **no** behavioral taxonomy (not in `eventTaxonomyMap`)
|
|
299
301
|
|
|
300
|
-
Of the
|
|
302
|
+
Of the 82 defined metric names, 73 have behavioral taxonomy and 9 do not. Events **without** an `eventTaxonomyMap` entry are the six `AI_ASSISTANT_*` names plus `WEBSOCKET_DEREGISTER_SUCCESS`, `WEBSOCKET_DEREGISTER_FAIL`, and `WEBSOCKET_EVENT_RECEIVED`.
|
|
301
303
|
|
|
302
304
|
### Complete METRIC_EVENT_NAMES catalog
|
|
303
305
|
|
|
304
|
-
This table contains all
|
|
306
|
+
This table contains all 82 names from `src/metrics/constants.ts`; taxonomy presence is checked against `src/metrics/behavioral-events.ts`: 73 mapped and 9 unmapped.
|
|
305
307
|
|
|
306
308
|
| Constant | Emitted name | Behavioral taxonomy? |
|
|
307
309
|
|---|---|---|
|
|
@@ -354,6 +356,8 @@ This table contains all 80 names from `src/metrics/constants.ts`; taxonomy prese
|
|
|
354
356
|
| `TASK_CONFERENCE_TRANSFER_FAILED` | `Task Conference Transfer Failed` | yes |
|
|
355
357
|
| `TASK_CONFERENCE_EXIT_SUCCESS` | `Task Conference Exit Success` | yes |
|
|
356
358
|
| `TASK_CONFERENCE_EXIT_FAILED` | `Task Conference Exit Failed` | yes |
|
|
359
|
+
| `TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS` | `Task Conference Participant Drop Success` | yes |
|
|
360
|
+
| `TASK_CONFERENCE_PARTICIPANT_DROP_FAILED` | `Task Conference Participant Drop Failed` | yes |
|
|
357
361
|
| `TASK_SWITCH_CALL_SUCCESS` | `Task Switch Call Success` | yes |
|
|
358
362
|
| `TASK_SWITCH_CALL_FAILED` | `Task Switch Call Failed` | yes |
|
|
359
363
|
| `TASK_OUTDIAL_SUCCESS` | `Task Outdial Success` | yes |
|
|
@@ -463,6 +467,8 @@ Example: `wxcc_sdk.user.station_login.complete`
|
|
|
463
467
|
|
|
464
468
|
The mapping is defined in `behavioral-events.ts` via `eventTaxonomyMap` and accessed through `getEventTaxonomy(name)`.
|
|
465
469
|
|
|
470
|
+
Participant Drop uses target `task_conference_participant_drop` with `complete` for success and `fail` for failure. Its metric payload is limited to task/request correlation and standard AQM tracking fields; participant IDs, numbers, names, URLs, headers, and raw routing payloads are excluded.
|
|
471
|
+
|
|
466
472
|
```mermaid
|
|
467
473
|
flowchart LR
|
|
468
474
|
A[timeEvent keys] --> B[runningEvents stores startTime + key Set]
|
|
@@ -728,7 +734,7 @@ MetricsManager holds three pending queues, running timing entries, a readiness f
|
|
|
728
734
|
|
|
729
735
|
## Business Rules & Invariants
|
|
730
736
|
- `timeEvent` and every tracking method return immediately while metrics are disabled.
|
|
731
|
-
- Only names present in `eventTaxonomyMap` receive behavioral taxonomy;
|
|
737
|
+
- Only names present in `eventTaxonomyMap` receive behavioral taxonomy; 73 of 82 names are mapped and the six AI Assistant plus three WebSocket names are intentionally catalogued as unmapped.
|
|
732
738
|
- `submittingEvents` prevents overlapping queue-drain executions.
|
|
733
739
|
- Authentication is inherited from the host Webex SDK's metrics client; MetricsManager owns no credentials, tokens, or authorization policy.
|
|
734
740
|
|
|
@@ -366,6 +366,20 @@ const eventTaxonomyMap: Record<string, BehavioralEventTaxonomy> = {
|
|
|
366
366
|
verb: 'fail',
|
|
367
367
|
},
|
|
368
368
|
|
|
369
|
+
// Conference Participant Drop
|
|
370
|
+
[METRIC_EVENT_NAMES.TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS]: {
|
|
371
|
+
product,
|
|
372
|
+
agent: 'user',
|
|
373
|
+
target: 'task_conference_participant_drop',
|
|
374
|
+
verb: 'complete',
|
|
375
|
+
},
|
|
376
|
+
[METRIC_EVENT_NAMES.TASK_CONFERENCE_PARTICIPANT_DROP_FAILED]: {
|
|
377
|
+
product,
|
|
378
|
+
agent: 'user',
|
|
379
|
+
target: 'task_conference_participant_drop',
|
|
380
|
+
verb: 'fail',
|
|
381
|
+
},
|
|
382
|
+
|
|
369
383
|
// Switch Call
|
|
370
384
|
[METRIC_EVENT_NAMES.TASK_SWITCH_CALL_SUCCESS]: {
|
|
371
385
|
product,
|
package/src/metrics/constants.ts
CHANGED
|
@@ -131,6 +131,8 @@ export const METRIC_EVENT_NAMES = {
|
|
|
131
131
|
TASK_CONFERENCE_TRANSFER_FAILED: 'Task Conference Transfer Failed',
|
|
132
132
|
TASK_CONFERENCE_EXIT_SUCCESS: 'Task Conference Exit Success',
|
|
133
133
|
TASK_CONFERENCE_EXIT_FAILED: 'Task Conference Exit Failed',
|
|
134
|
+
TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS: 'Task Conference Participant Drop Success',
|
|
135
|
+
TASK_CONFERENCE_PARTICIPANT_DROP_FAILED: 'Task Conference Participant Drop Failed',
|
|
134
136
|
TASK_SWITCH_CALL_SUCCESS: 'Task Switch Call Success',
|
|
135
137
|
TASK_SWITCH_CALL_FAILED: 'Task Switch Call Failed',
|
|
136
138
|
|
|
@@ -74,7 +74,8 @@ export class AddressBook {
|
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
76
|
* Fetches address book entries for a specific address book using the entry API
|
|
77
|
-
* @param {AddressBookEntrySearchParams} [params] - Search and
|
|
77
|
+
* @param {AddressBookEntrySearchParams} [params] - Search, pagination, and optional sort parameters
|
|
78
|
+
* including addressBookId. Sorting defaults to name ascending.
|
|
78
79
|
* @returns {Promise<AddressBookEntriesResponse>} Promise resolving to address book entries
|
|
79
80
|
* @throws {Error} If the API call fails
|
|
80
81
|
* @public
|
|
@@ -102,12 +103,21 @@ export class AddressBook {
|
|
|
102
103
|
search,
|
|
103
104
|
filter,
|
|
104
105
|
attributes,
|
|
106
|
+
sortBy = 'name',
|
|
107
|
+
sortOrder = 'asc',
|
|
105
108
|
} = params;
|
|
106
109
|
|
|
107
110
|
// Use provided addressBookId or fall back to agent's address book
|
|
108
111
|
const bookId = addressBookId || this.getAddressBookId();
|
|
109
112
|
const orgId = this.webex.credentials.getOrgId();
|
|
110
|
-
const
|
|
113
|
+
const hasCustomSort = sortBy !== 'name' || sortOrder !== 'asc';
|
|
114
|
+
const isSearchRequest = !!(search || filter || attributes || hasCustomSort);
|
|
115
|
+
const canUseCache = this.pageCache.canUseCache({
|
|
116
|
+
search,
|
|
117
|
+
filter,
|
|
118
|
+
attributes,
|
|
119
|
+
sortBy: hasCustomSort ? sortBy : undefined,
|
|
120
|
+
});
|
|
111
121
|
|
|
112
122
|
LoggerProxy.info('Fetching address book entries', {
|
|
113
123
|
module: 'AddressBook',
|
|
@@ -121,8 +131,8 @@ export class AddressBook {
|
|
|
121
131
|
},
|
|
122
132
|
});
|
|
123
133
|
|
|
124
|
-
//
|
|
125
|
-
if (
|
|
134
|
+
// Default name-ascending pagination is cache-compatible; result-changing overrides are not.
|
|
135
|
+
if (canUseCache) {
|
|
126
136
|
const cacheKey = this.pageCache.buildCacheKey(bookId, page, pageSize);
|
|
127
137
|
const cachedPage = this.pageCache.getCachedPage(cacheKey);
|
|
128
138
|
|
|
@@ -190,6 +200,7 @@ export class AddressBook {
|
|
|
190
200
|
if (filter) queryParams.append('filter', filter);
|
|
191
201
|
if (attributes) queryParams.append('attributes', attributes);
|
|
192
202
|
if (search) queryParams.append('search', search);
|
|
203
|
+
if (sortBy) queryParams.append('sort', `${sortBy},${sortOrder.toUpperCase()}`);
|
|
193
204
|
|
|
194
205
|
const resource = endPointMap.addressBookEntries(orgId, bookId, queryParams.toString());
|
|
195
206
|
|
|
@@ -244,8 +255,8 @@ export class AddressBook {
|
|
|
244
255
|
);
|
|
245
256
|
}
|
|
246
257
|
|
|
247
|
-
// Cache the
|
|
248
|
-
if (
|
|
258
|
+
// Cache only the invariant default-order pagination shape.
|
|
259
|
+
if (canUseCache && response.body?.data) {
|
|
249
260
|
const cacheKey = this.pageCache.buildCacheKey(bookId, page, pageSize);
|
|
250
261
|
this.pageCache.cachePage(cacheKey, response.body.data, response.body.meta);
|
|
251
262
|
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import LoggerProxy from '../logger-proxy';
|
|
2
|
+
import {CC_FILE, METHODS} from '../constants';
|
|
3
|
+
import {HTTP_METHODS, IHttpResponse, WebexSDK} from '../types';
|
|
4
|
+
import {getErrorDetails} from './core/Utils';
|
|
5
|
+
import {isWxAppCallNotFoundError} from './wxAppTelephonyUtils';
|
|
6
|
+
|
|
7
|
+
const ANSWER_CALL_ON_WEBEX_FILE = 'AnswerCallOnWebexService';
|
|
8
|
+
|
|
9
|
+
export type WxAppTelephonyError = Error & {
|
|
10
|
+
isWxAppTelephonyError: true;
|
|
11
|
+
trackingId?: string;
|
|
12
|
+
status?: number | string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const markWxAppTelephonyError = (error: Error, source: unknown): WxAppTelephonyError => {
|
|
16
|
+
const marked = error as WxAppTelephonyError;
|
|
17
|
+
marked.isWxAppTelephonyError = true;
|
|
18
|
+
const sourceObj = source as {
|
|
19
|
+
details?: {trackingId?: string; status?: number | string};
|
|
20
|
+
statusCode?: number;
|
|
21
|
+
status?: number | string;
|
|
22
|
+
};
|
|
23
|
+
const trackingId = sourceObj?.details?.trackingId;
|
|
24
|
+
if (trackingId) {
|
|
25
|
+
marked.trackingId = trackingId;
|
|
26
|
+
}
|
|
27
|
+
const status = sourceObj?.statusCode ?? sourceObj?.details?.status ?? sourceObj?.status;
|
|
28
|
+
if (status !== undefined) {
|
|
29
|
+
marked.status = status;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return marked;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type AnswerCallParams = {
|
|
36
|
+
callId: string;
|
|
37
|
+
endpointId: string;
|
|
38
|
+
lineOwnerId?: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type CallIdParams = {
|
|
42
|
+
callId: string;
|
|
43
|
+
lineOwnerId?: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type TransmitDtmfParams = CallIdParams & {
|
|
47
|
+
dtmf: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type CallDetailsResponse = {
|
|
51
|
+
muted?: boolean;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* REST telephony client for wxApp thick-client answer (WXCC-6026).
|
|
56
|
+
* Separate from WebCallingService (WebRTC/Mobius).
|
|
57
|
+
*/
|
|
58
|
+
export default class AnswerCallOnWebexService {
|
|
59
|
+
private webex: WebexSDK;
|
|
60
|
+
|
|
61
|
+
constructor(webex: WebexSDK) {
|
|
62
|
+
this.webex = webex;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private getTelephonyBaseUrl(): string {
|
|
66
|
+
const services = this.webex.internal.services;
|
|
67
|
+
const hydraUrl = services._serviceUrls?.hydra || services.get('hydra');
|
|
68
|
+
|
|
69
|
+
if (!hydraUrl) {
|
|
70
|
+
throw new Error('Telephony base URL is unavailable');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return `${hydraUrl.replace(/\/$/, '')}/telephony/calls`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private async telephonyRequest(
|
|
77
|
+
resource: string,
|
|
78
|
+
method: HTTP_METHODS,
|
|
79
|
+
body: Record<string, unknown>,
|
|
80
|
+
logMethod: string
|
|
81
|
+
): Promise<IHttpResponse> {
|
|
82
|
+
try {
|
|
83
|
+
const uri = `${this.getTelephonyBaseUrl()}${resource}`;
|
|
84
|
+
|
|
85
|
+
LoggerProxy.info(`AnswerCallOnWebexService.${logMethod} request`, {
|
|
86
|
+
module: ANSWER_CALL_ON_WEBEX_FILE,
|
|
87
|
+
method: logMethod,
|
|
88
|
+
data: {uri, bodyKeys: Object.keys(body)},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return (await this.webex.request({
|
|
92
|
+
uri,
|
|
93
|
+
method,
|
|
94
|
+
body,
|
|
95
|
+
addAuthHeader: true,
|
|
96
|
+
})) as IHttpResponse;
|
|
97
|
+
} catch (error) {
|
|
98
|
+
LoggerProxy.error(`AnswerCallOnWebexService.${logMethod} failed: ${error}`, {
|
|
99
|
+
module: ANSWER_CALL_ON_WEBEX_FILE,
|
|
100
|
+
method: logMethod,
|
|
101
|
+
});
|
|
102
|
+
const {error: detailedError} = getErrorDetails(error, logMethod, CC_FILE);
|
|
103
|
+
throw markWxAppTelephonyError(detailedError, error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public answerCall(params: AnswerCallParams): Promise<IHttpResponse> {
|
|
108
|
+
const {callId, endpointId, lineOwnerId} = params;
|
|
109
|
+
|
|
110
|
+
return this.telephonyRequest(
|
|
111
|
+
'/answer',
|
|
112
|
+
HTTP_METHODS.POST,
|
|
113
|
+
{
|
|
114
|
+
callId,
|
|
115
|
+
endpointId,
|
|
116
|
+
...(lineOwnerId ? {lineOwnerId} : {}),
|
|
117
|
+
},
|
|
118
|
+
METHODS.ACCEPT
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public rejectCall(params: CallIdParams): Promise<IHttpResponse> {
|
|
123
|
+
const {callId, lineOwnerId} = params;
|
|
124
|
+
|
|
125
|
+
return this.telephonyRequest(
|
|
126
|
+
'/reject',
|
|
127
|
+
HTTP_METHODS.POST,
|
|
128
|
+
{callId, ...(lineOwnerId ? {lineOwnerId} : {})},
|
|
129
|
+
METHODS.REJECT
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public muteCall(params: CallIdParams): Promise<IHttpResponse> {
|
|
134
|
+
const {callId, lineOwnerId} = params;
|
|
135
|
+
|
|
136
|
+
return this.telephonyRequest(
|
|
137
|
+
'/mute',
|
|
138
|
+
HTTP_METHODS.POST,
|
|
139
|
+
{callId, ...(lineOwnerId ? {lineOwnerId} : {})},
|
|
140
|
+
METHODS.TOGGLE_MUTE
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public unmuteCall(params: CallIdParams): Promise<IHttpResponse> {
|
|
145
|
+
const {callId, lineOwnerId} = params;
|
|
146
|
+
|
|
147
|
+
return this.telephonyRequest(
|
|
148
|
+
'/unmute',
|
|
149
|
+
HTTP_METHODS.POST,
|
|
150
|
+
{callId, ...(lineOwnerId ? {lineOwnerId} : {})},
|
|
151
|
+
METHODS.TOGGLE_MUTE
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public transmitDtmf(params: TransmitDtmfParams): Promise<IHttpResponse> {
|
|
156
|
+
const {callId, dtmf, lineOwnerId} = params;
|
|
157
|
+
|
|
158
|
+
return this.telephonyRequest(
|
|
159
|
+
'/transmitDtmf',
|
|
160
|
+
HTTP_METHODS.POST,
|
|
161
|
+
{callId, dtmf, ...(lineOwnerId ? {lineOwnerId} : {})},
|
|
162
|
+
METHODS.TRANSMIT_DTMF
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public async getCallDetails(params: CallIdParams): Promise<CallDetailsResponse> {
|
|
167
|
+
const {callId, lineOwnerId} = params;
|
|
168
|
+
const lineOwnerIdQuery = lineOwnerId ? `?lineOwnerId=${encodeURIComponent(lineOwnerId)}` : '';
|
|
169
|
+
const uri = `${this.getTelephonyBaseUrl()}/${callId}${lineOwnerIdQuery}`;
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
LoggerProxy.info('AnswerCallOnWebexService.getCallDetails request', {
|
|
173
|
+
module: ANSWER_CALL_ON_WEBEX_FILE,
|
|
174
|
+
method: METHODS.GET_CALL_DETAILS_ON_WEBEX,
|
|
175
|
+
data: {callId},
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const response = (await this.webex.request({
|
|
179
|
+
uri,
|
|
180
|
+
method: HTTP_METHODS.GET,
|
|
181
|
+
addAuthHeader: true,
|
|
182
|
+
})) as IHttpResponse;
|
|
183
|
+
|
|
184
|
+
return (response.body ?? {}) as CallDetailsResponse;
|
|
185
|
+
} catch (error) {
|
|
186
|
+
if (isWxAppCallNotFoundError(error)) {
|
|
187
|
+
const err =
|
|
188
|
+
error instanceof Error
|
|
189
|
+
? error
|
|
190
|
+
: new Error(String((error as {message?: string})?.message ?? error));
|
|
191
|
+
throw markWxAppTelephonyError(err, error);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
LoggerProxy.error(`AnswerCallOnWebexService.getCallDetails failed: ${error}`, {
|
|
195
|
+
module: ANSWER_CALL_ON_WEBEX_FILE,
|
|
196
|
+
method: METHODS.GET_CALL_DETAILS_ON_WEBEX,
|
|
197
|
+
});
|
|
198
|
+
const {error: detailedError} = getErrorDetails(
|
|
199
|
+
error,
|
|
200
|
+
METHODS.GET_CALL_DETAILS_ON_WEBEX,
|
|
201
|
+
CC_FILE
|
|
202
|
+
);
|
|
203
|
+
throw markWxAppTelephonyError(detailedError, error);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -2,12 +2,40 @@ import {HTTP_METHODS, WebexSDK} from '../types';
|
|
|
2
2
|
import type {EntryPointRecord, EntryPointListResponse, EntryPointSearchParams} from '../types';
|
|
3
3
|
import LoggerProxy from '../logger-proxy';
|
|
4
4
|
import WebexRequest from './core/WebexRequest';
|
|
5
|
-
import
|
|
5
|
+
import {PAGINATION_DEFAULTS} from '../utils/PageCache';
|
|
6
6
|
import MetricsManager from '../metrics/MetricsManager';
|
|
7
7
|
import {WCC_API_GATEWAY} from './constants';
|
|
8
8
|
import {endPointMap} from './config/constants';
|
|
9
9
|
import {METRIC_EVENT_NAMES} from '../metrics/constants';
|
|
10
10
|
|
|
11
|
+
const DEFAULT_ENTRY_POINT_ATTRIBUTES = 'id,dialledNumber,entryPointId,entryPointName';
|
|
12
|
+
const DEFAULT_ENTRY_POINT_SORT_FIELD = 'entryPointName';
|
|
13
|
+
|
|
14
|
+
type DialNumberEntryPointRecord = {
|
|
15
|
+
id: string;
|
|
16
|
+
dialledNumber?: string;
|
|
17
|
+
entryPointId: string;
|
|
18
|
+
entryPointName: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const mergeEntryPointAttributes = (attributes?: string): string => {
|
|
22
|
+
const mergedAttributes = new Set(DEFAULT_ENTRY_POINT_ATTRIBUTES.split(','));
|
|
23
|
+
|
|
24
|
+
attributes
|
|
25
|
+
?.split(',')
|
|
26
|
+
.map((attribute) => attribute.trim())
|
|
27
|
+
.filter(Boolean)
|
|
28
|
+
.forEach((attribute) => mergedAttributes.add(attribute));
|
|
29
|
+
|
|
30
|
+
return Array.from(mergedAttributes).join(',');
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const mapDialNumberEntryPoint = (item: DialNumberEntryPointRecord): EntryPointRecord => ({
|
|
34
|
+
id: item.entryPointId,
|
|
35
|
+
name: item.entryPointName,
|
|
36
|
+
...(item.dialledNumber ? {number: item.dialledNumber} : {}),
|
|
37
|
+
});
|
|
38
|
+
|
|
11
39
|
/**
|
|
12
40
|
* EntryPoint class for managing Webex Contact Center entry points.
|
|
13
41
|
* Provides functionality to fetch, search, and paginate through entry points.
|
|
@@ -35,7 +63,7 @@ import {METRIC_EVENT_NAMES} from '../metrics/constants';
|
|
|
35
63
|
* });
|
|
36
64
|
*
|
|
37
65
|
* // Search for specific entry points
|
|
38
|
-
* const searchResults = await entryPointAPI.
|
|
66
|
+
* const searchResults = await entryPointAPI.getEntryPoints({
|
|
39
67
|
* search: 'support',
|
|
40
68
|
* filter: 'type=="voice"'
|
|
41
69
|
* });
|
|
@@ -46,9 +74,6 @@ export class EntryPoint {
|
|
|
46
74
|
private webex: WebexSDK;
|
|
47
75
|
private metricsManager: MetricsManager;
|
|
48
76
|
|
|
49
|
-
// Page cache using the common utility
|
|
50
|
-
private pageCache: PageCache<EntryPointRecord>;
|
|
51
|
-
|
|
52
77
|
/**
|
|
53
78
|
* Creates an instance of EntryPoint
|
|
54
79
|
* @param {WebexSDK} webex - The Webex SDK instance
|
|
@@ -57,19 +82,21 @@ export class EntryPoint {
|
|
|
57
82
|
constructor(webex: WebexSDK) {
|
|
58
83
|
this.webex = webex;
|
|
59
84
|
this.webexRequest = WebexRequest.getInstance({webex});
|
|
60
|
-
this.pageCache = new PageCache<EntryPointRecord>('EntryPoint');
|
|
61
85
|
this.metricsManager = MetricsManager.getInstance({webex});
|
|
62
86
|
}
|
|
63
87
|
|
|
64
88
|
/**
|
|
65
|
-
* Fetches entry
|
|
66
|
-
*
|
|
89
|
+
* Fetches entry-point dial-number mappings for the organization with pagination support. By
|
|
90
|
+
* default, returns the agent's desktop-profile-filtered mappings in backend entry-point-name order.
|
|
91
|
+
* Search, filter, attribute, and sort parameters can customize the request while desktop-profile
|
|
92
|
+
* scoping and required mapping fields remain SDK-owned.
|
|
93
|
+
* @param {EntryPointSearchParams} [params] - Search, pagination, and compatible override parameters.
|
|
67
94
|
* @returns {Promise<EntryPointListResponse>} Promise resolving to paginated entry points
|
|
68
95
|
* @throws {Error} If the API call fails
|
|
69
96
|
* @public
|
|
70
97
|
* @example
|
|
71
98
|
* ```typescript
|
|
72
|
-
* // Get first page
|
|
99
|
+
* // Get the first page using the default entry-point policy
|
|
73
100
|
* const response = await entryPointAPI.getEntryPoints();
|
|
74
101
|
*
|
|
75
102
|
* // Get specific page with custom page size
|
|
@@ -89,12 +116,14 @@ export class EntryPoint {
|
|
|
89
116
|
search,
|
|
90
117
|
filter,
|
|
91
118
|
attributes,
|
|
92
|
-
sortBy,
|
|
119
|
+
sortBy = 'name',
|
|
93
120
|
sortOrder = 'asc',
|
|
94
121
|
} = params;
|
|
95
122
|
|
|
96
123
|
const orgId = this.webex.credentials.getOrgId();
|
|
97
|
-
const
|
|
124
|
+
const hasCustomSort = sortBy !== 'name' || sortOrder !== 'asc';
|
|
125
|
+
const isSearchRequest = !!(search || filter || attributes || hasCustomSort);
|
|
126
|
+
const effectiveSortBy = sortBy === 'name' ? DEFAULT_ENTRY_POINT_SORT_FIELD : sortBy;
|
|
98
127
|
|
|
99
128
|
LoggerProxy.info(
|
|
100
129
|
`Fetching entry points - orgId: ${orgId}, page: ${page}, pageSize: ${pageSize}, isSearchRequest: ${isSearchRequest}`,
|
|
@@ -104,51 +133,24 @@ export class EntryPoint {
|
|
|
104
133
|
}
|
|
105
134
|
);
|
|
106
135
|
|
|
107
|
-
// Check if we can use cache for simple pagination (no search/filter/attributes/sort)
|
|
108
|
-
if (this.pageCache.canUseCache({search, filter, attributes, sortBy})) {
|
|
109
|
-
const cacheKey = this.pageCache.buildCacheKey(orgId, page, pageSize);
|
|
110
|
-
const cachedPage = this.pageCache.getCachedPage(cacheKey);
|
|
111
|
-
|
|
112
|
-
if (cachedPage) {
|
|
113
|
-
const duration = Date.now() - startTime;
|
|
114
|
-
|
|
115
|
-
LoggerProxy.log(
|
|
116
|
-
`Returning page ${page} from cache - cacheHit: true, duration: ${duration}ms, recordCount: ${cachedPage.data.length}, pageSize: ${pageSize}`,
|
|
117
|
-
{
|
|
118
|
-
module: 'EntryPoint',
|
|
119
|
-
method: 'getEntryPoints',
|
|
120
|
-
}
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
data: cachedPage.data,
|
|
125
|
-
meta: {
|
|
126
|
-
page,
|
|
127
|
-
pageSize,
|
|
128
|
-
totalPages: cachedPage.totalMeta?.totalPages,
|
|
129
|
-
totalRecords: cachedPage.totalMeta?.totalRecords,
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Start timing only for actual API calls (not cache hits)
|
|
136
136
|
this.metricsManager.timeEvent(METRIC_EVENT_NAMES.ENTRYPOINT_FETCH_SUCCESS);
|
|
137
137
|
|
|
138
138
|
try {
|
|
139
|
-
// Build query parameters
|
|
140
139
|
const queryParams = new URLSearchParams({
|
|
141
140
|
page: page.toString(),
|
|
142
141
|
pageSize: pageSize.toString(),
|
|
143
|
-
|
|
142
|
+
attributes: mergeEntryPointAttributes(attributes),
|
|
144
143
|
});
|
|
145
144
|
|
|
146
145
|
if (search) queryParams.append('search', search);
|
|
147
146
|
if (filter) queryParams.append('filter', filter);
|
|
148
|
-
if (
|
|
149
|
-
|
|
147
|
+
if (effectiveSortBy) {
|
|
148
|
+
queryParams.append('sort', `${effectiveSortBy},${sortOrder.toUpperCase()}`);
|
|
149
|
+
}
|
|
150
|
+
queryParams.append('desktopProfileFilter', 'true');
|
|
151
|
+
queryParams.append('includeEntryPointName', 'true');
|
|
150
152
|
|
|
151
|
-
const resource = endPointMap.
|
|
153
|
+
const resource = endPointMap.entryPointDialNumberList(orgId, queryParams.toString());
|
|
152
154
|
|
|
153
155
|
LoggerProxy.log(
|
|
154
156
|
`Making API request to fetch entry points - resource: ${resource}, service: ${WCC_API_GATEWAY}`,
|
|
@@ -162,12 +164,21 @@ export class EntryPoint {
|
|
|
162
164
|
service: WCC_API_GATEWAY,
|
|
163
165
|
resource,
|
|
164
166
|
method: HTTP_METHODS.GET,
|
|
167
|
+
headers: {
|
|
168
|
+
'X-ORGANIZATION-ID': orgId,
|
|
169
|
+
'x-ignore-internal-data': 'false',
|
|
170
|
+
},
|
|
165
171
|
});
|
|
166
172
|
|
|
173
|
+
const responseBody: EntryPointListResponse = {
|
|
174
|
+
...response.body,
|
|
175
|
+
data: (response.body?.data ?? []).map(mapDialNumberEntryPoint),
|
|
176
|
+
};
|
|
177
|
+
|
|
167
178
|
const duration = Date.now() - startTime;
|
|
168
179
|
|
|
169
|
-
const recordCount =
|
|
170
|
-
const totalRecords =
|
|
180
|
+
const recordCount = responseBody.data.length;
|
|
181
|
+
const totalRecords = responseBody.meta?.totalRecords;
|
|
171
182
|
|
|
172
183
|
LoggerProxy.log(`Successfully retrieved ${recordCount} entry points`, {
|
|
173
184
|
module: 'EntryPoint',
|
|
@@ -199,19 +210,7 @@ export class EntryPoint {
|
|
|
199
210
|
);
|
|
200
211
|
}
|
|
201
212
|
|
|
202
|
-
|
|
203
|
-
if (this.pageCache.canUseCache({search, filter, attributes, sortBy}) && response.body?.data) {
|
|
204
|
-
const cacheKey = this.pageCache.buildCacheKey(orgId, page, pageSize);
|
|
205
|
-
this.pageCache.cachePage(cacheKey, response.body.data, response.body.meta);
|
|
206
|
-
|
|
207
|
-
LoggerProxy.log('Cached entry points data for future requests', {
|
|
208
|
-
module: 'EntryPoint',
|
|
209
|
-
method: 'getEntryPoints',
|
|
210
|
-
data: {cacheKey, recordCount},
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return response.body;
|
|
213
|
+
return responseBody;
|
|
215
214
|
} catch (error) {
|
|
216
215
|
const errorData = {
|
|
217
216
|
orgId,
|
package/src/services/Queue.ts
CHANGED
|
@@ -70,14 +70,16 @@ export class Queue {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
* Fetches contact service queues for the organization
|
|
74
|
-
*
|
|
73
|
+
* Fetches contact service queues for the organization. By default, returns active inbound
|
|
74
|
+
* telephony queues in backend name-ascending order using the agent's desktop profile views.
|
|
75
|
+
* Existing filter, sort, and desktop-profile parameters override those defaults.
|
|
76
|
+
* @param {ContactServiceQueueSearchParams} [params] - Search, pagination, and override parameters
|
|
75
77
|
* @returns {Promise<ContactServiceQueuesResponse>} Promise resolving to contact service queues
|
|
76
78
|
* @throws {Error} If the API call fails
|
|
77
79
|
* @public
|
|
78
80
|
* @example
|
|
79
81
|
* ```typescript
|
|
80
|
-
* // Get
|
|
82
|
+
* // Get queues using the default list policy and pagination
|
|
81
83
|
* const response = await queueAPI.getQueues();
|
|
82
84
|
*
|
|
83
85
|
* // Get queues with specific pagination
|
|
@@ -101,17 +103,29 @@ export class Queue {
|
|
|
101
103
|
page = PAGINATION_DEFAULTS.PAGE,
|
|
102
104
|
pageSize = PAGINATION_DEFAULTS.PAGE_SIZE,
|
|
103
105
|
search,
|
|
104
|
-
filter,
|
|
106
|
+
filter = 'queueType==INBOUND;channelType==TELEPHONY;active==true',
|
|
105
107
|
attributes,
|
|
106
|
-
sortBy,
|
|
107
|
-
sortOrder,
|
|
108
|
-
desktopProfileFilter,
|
|
108
|
+
sortBy = 'name',
|
|
109
|
+
sortOrder = 'asc',
|
|
110
|
+
desktopProfileFilter = true,
|
|
109
111
|
provisioningView,
|
|
110
112
|
singleObjectResponse,
|
|
111
113
|
} = params;
|
|
114
|
+
const agentView = desktopProfileFilter;
|
|
115
|
+
const firstLevelView = desktopProfileFilter;
|
|
112
116
|
|
|
113
117
|
const orgId = this.webex.credentials.getOrgId();
|
|
114
|
-
const
|
|
118
|
+
const effectiveSortBy = sortBy ?? (sortOrder ? 'name' : undefined);
|
|
119
|
+
const isSearchRequest = !!(search || filter || attributes || effectiveSortBy);
|
|
120
|
+
const canUseCache = this.pageCache.canUseCache({
|
|
121
|
+
search,
|
|
122
|
+
filter,
|
|
123
|
+
attributes,
|
|
124
|
+
sortBy: effectiveSortBy,
|
|
125
|
+
desktopProfileFilter,
|
|
126
|
+
provisioningView,
|
|
127
|
+
singleObjectResponse,
|
|
128
|
+
});
|
|
115
129
|
|
|
116
130
|
LoggerProxy.info('Fetching contact service queues', {
|
|
117
131
|
module: 'Queue',
|
|
@@ -125,7 +139,7 @@ export class Queue {
|
|
|
125
139
|
});
|
|
126
140
|
|
|
127
141
|
// Check if we can use cache for simple pagination (no search/filter/attributes/sort)
|
|
128
|
-
if (
|
|
142
|
+
if (canUseCache) {
|
|
129
143
|
const cacheKey = this.pageCache.buildCacheKey(orgId, page, pageSize);
|
|
130
144
|
const cachedPage = this.pageCache.getCachedPage(cacheKey);
|
|
131
145
|
|
|
@@ -170,14 +184,17 @@ export class Queue {
|
|
|
170
184
|
if (filter) queryParams.append('filter', filter);
|
|
171
185
|
if (attributes) queryParams.append('attributes', attributes);
|
|
172
186
|
if (search) queryParams.append('search', search);
|
|
173
|
-
if (
|
|
174
|
-
|
|
187
|
+
if (effectiveSortBy)
|
|
188
|
+
queryParams.append('sort', `${effectiveSortBy},${(sortOrder ?? 'asc').toUpperCase()}`);
|
|
175
189
|
if (desktopProfileFilter !== undefined)
|
|
176
190
|
queryParams.append('desktopProfileFilter', desktopProfileFilter.toString());
|
|
177
191
|
if (provisioningView !== undefined)
|
|
178
192
|
queryParams.append('provisioningView', provisioningView.toString());
|
|
179
193
|
if (singleObjectResponse !== undefined)
|
|
180
194
|
queryParams.append('singleObjectResponse', singleObjectResponse.toString());
|
|
195
|
+
if (agentView !== undefined) queryParams.append('agentView', agentView.toString());
|
|
196
|
+
if (firstLevelView !== undefined)
|
|
197
|
+
queryParams.append('firstLevelView', firstLevelView.toString());
|
|
181
198
|
|
|
182
199
|
const resource = endPointMap.queueList(orgId, queryParams.toString());
|
|
183
200
|
|
|
@@ -232,7 +249,7 @@ export class Queue {
|
|
|
232
249
|
}
|
|
233
250
|
|
|
234
251
|
// Cache the page data for simple pagination (no search/filter/attributes/sort)
|
|
235
|
-
if (
|
|
252
|
+
if (canUseCache && response.body?.data) {
|
|
236
253
|
const cacheKey = this.pageCache.buildCacheKey(orgId, page, pageSize);
|
|
237
254
|
this.pageCache.cachePage(cacheKey, response.body.data, response.body.meta);
|
|
238
255
|
|