The largest single change in this migration. CC Widgets currently computes all call control button visibility/enabled states in task-util.ts::getControlsVisibility() (~650 lines). The new SDK provides task.uiControls as a pre-computed TaskUIControls object driven by the state machine, making the widget-side computation redundant.
File: packages/contact-center/task/src/Utils/task-util.ts
Function: getControlsVisibility(deviceType, featureFlags, task, agentId, conferenceEnabled, logger)
- Widget calls
getControlsVisibility()on every render/task update - Function inspects raw
task.data.interactionto derive:- Media type (telephony, chat, email)
- Device type (browser, agentDN, extension)
- Consult status (via
getConsultStatus()from store utils) - Hold status (via
findHoldStatus()from store utils) - Conference status (via
task.data.isConferenceInProgress) - Participant counts (via
getConferenceParticipantsCount())
- Each control has a dedicated function that returns
{ isVisible, isEnabled } - Result includes both control visibility AND state flags (e.g.,
isHeld,consultCallHeld)
| Old Control Name | Type |
|---|---|
accept |
Visibility |
decline |
Visibility |
end |
Visibility |
muteUnmute |
Visibility |
holdResume |
Visibility |
pauseResumeRecording |
Visibility |
recordingIndicator |
Visibility |
transfer |
Visibility |
conference |
Visibility |
exitConference |
Visibility |
mergeConference |
Visibility |
consult |
Visibility |
endConsult |
Visibility |
consultTransfer |
Visibility |
consultTransferConsult |
Visibility |
mergeConferenceConsult |
Visibility |
muteUnmuteConsult |
Visibility |
switchToMainCall |
Visibility |
switchToConsult |
Visibility |
wrapup |
Visibility |
| State flags | |
isConferenceInProgress |
boolean |
isConsultInitiated |
boolean |
isConsultInitiatedAndAccepted |
boolean |
isConsultReceived |
boolean |
isConsultInitiatedOrAccepted |
boolean |
isHeld |
boolean |
consultCallHeld |
boolean |
SDK Property: task.uiControls (getter on ITask)
SDK Event: task:ui-controls-updated (emitted when controls change)
SDK File: packages/@webex/contact-center/src/services/task/state-machine/uiControlsComputer.ts
- SDK state machine transitions on every event (hold, consult, conference, etc.)
- After each transition,
computeUIControls(currentState, context)is called - If controls changed (
haveUIControlsChanged()), emitstask:ui-controls-updated - Widget reads
task.uiControls— no computation needed on widget side
| New Control Name | Type |
|---|---|
accept |
{ isVisible, isEnabled } |
decline |
{ isVisible, isEnabled } |
hold |
{ isVisible, isEnabled } |
mute |
{ isVisible, isEnabled } |
end |
{ isVisible, isEnabled } |
transfer |
{ isVisible, isEnabled } |
consult |
{ isVisible, isEnabled } |
consultTransfer |
{ isVisible, isEnabled } |
endConsult |
{ isVisible, isEnabled } |
recording |
{ isVisible, isEnabled } |
conference |
{ isVisible, isEnabled } |
wrapup |
{ isVisible, isEnabled } |
exitConference |
{ isVisible, isEnabled } |
transferConference |
{ isVisible, isEnabled } |
mergeToConference |
{ isVisible, isEnabled } |
switchToMainCall |
{ isVisible, isEnabled } |
switchToConsult |
{ isVisible, isEnabled } |
| Old Widget Control | New SDK Control | Notes |
|---|---|---|
accept |
accept |
Same |
decline |
decline |
Same |
end |
end |
Same |
muteUnmute |
mute |
Renamed |
holdResume |
hold |
Renamed (hold state still togglable) |
pauseResumeRecording |
recording |
Renamed |
recordingIndicator |
recording |
Merged into recording control |
transfer |
transfer |
Same |
conference |
conference |
Same |
exitConference |
exitConference |
Same |
mergeConference |
mergeToConference |
Renamed |
consult |
consult |
Same |
endConsult |
endConsult |
Same |
consultTransfer |
consultTransfer |
Same (always hidden in new SDK) |
consultTransferConsult |
transfer |
Removed — transfer button handles consult transfer |
mergeConferenceConsult |
mergeToConference |
Merged into mergeToConference |
muteUnmuteConsult |
mute |
Merged into mute |
switchToMainCall |
switchToMainCall |
Same |
switchToConsult |
switchToConsult |
Same |
wrapup |
wrapup |
Same |
The following state flags were returned by getControlsVisibility() but are no longer needed:
| Old State Flag | Replacement |
|---|---|
isConferenceInProgress |
Derive from task.uiControls.exitConference.isVisible if needed |
isConsultInitiated |
Derive from task.uiControls.endConsult.isVisible if needed |
isConsultInitiatedAndAccepted |
No longer needed — SDK handles via controls |
isConsultReceived |
No longer needed — SDK handles via controls |
isConsultInitiatedOrAccepted |
No longer needed — SDK handles via controls |
isHeld |
Derive from task.uiControls.hold state or SDK task state |
consultCallHeld |
No longer needed — SDK handles switch controls |
// helper.ts — old approach
const controls = getControlsVisibility(
store.deviceType,
store.featureFlags,
store.currentTask,
store.agentId,
conferenceEnabled,
store.logger
);
// Pass 22 controls + 7 state flags to component
return {
...controls,
// additional hook state
};// helper.ts — new approach
const task = store.currentTask;
const uiControls = task?.uiControls ?? getDefaultUIControls();
// Subscribe to UI control updates
useEffect(() => {
if (!task) return;
const handler = () => {
// MobX or setState to trigger re-render
};
task.on('task:ui-controls-updated', handler);
return () => task.off('task:ui-controls-updated', handler);
}, [task]);
// Pass SDK-computed controls directly to component
return {
controls: uiControls,
// additional hook state (timers, mute state, etc.)
};| File | Action |
|---|---|
task/src/Utils/task-util.ts |
DELETE or reduce to findHoldTimestamp() only |
task/src/helper.ts (useCallControl) |
Remove getControlsVisibility() call, use task.uiControls |
task/src/task.types.ts |
Import TaskUIControls from SDK, remove old control types |
cc-components/src/components/task/task.types.ts |
Align ControlProps with new control names |
cc-components/src/components/task/CallControl/call-control.tsx |
Update prop names (holdResume → hold, etc.) |
cc-components/src/components/task/CallControl/call-control.utils.ts |
Simplify/remove old control derivation |
store/src/task-utils.ts |
Remove getConsultStatus, findHoldStatus if no longer consumed |
| All test files for above | Update to test new contract |
- All 17 SDK controls map correctly to widget UI buttons
- No widget-side computation of control visibility remains
-
task:ui-controls-updatedevent drives re-renders - All existing call control scenarios work identically (hold, consult, transfer, conference, wrapup)
- Digital channel controls work (accept, end, transfer, wrapup only)
- Default controls shown when no task is active
- Error boundary still catches failures gracefully
Parent: 001-migration-overview.md