Skip to content

Commit 8197531

Browse files
jonaphaelGitHub Enterprise
authored and
GitHub Enterprise
committed
FLEXSDK-265: Fix types for fetchWorker and fetchWorkers in workspace env (#442)
* FLEXSDK-265: Fix types for fetchWorker and fetchWorkers in workspace env * FLEXSDK-265: improve WorkerInfo description * FLEXSDK-265: deprecated fetchWorker(s) and add fetchWorker(s)Info * FLEXSDK-265: call correct method and remove unused code * FLEXSDK-265: sample app consuming new method * FLEXSDK-265: bump @babel/runtime to fix vulnerability * FLEXSDK-265: trigger pipeline * FLEXSDK-265: fix yarn.lock * FLEXSDK-265: fix typo * FLEXSDK-265: remove space after axios version
1 parent 3f1c9ae commit 8197531

File tree

9 files changed

+263
-49
lines changed

9 files changed

+263
-49
lines changed

lib/Workspace.js

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Request from './util/Request.js';
44
import Configuration from './util/Configuration.js';
55
import jwtDecode from 'jwt-decode';
66
import Logger from './util/Logger';
7+
import './types.jsdoc';
78

89

910
/**
@@ -61,7 +62,8 @@ class Workspace {
6162
}
6263

6364
/**
64-
* Fetch worker of this {@link Workspace} by given sid
65+
* @deprecated use {@link Workspace#fetchWorkerInfo}
66+
* @description Fetch worker of this {@link Workspace} by given sid
6567
* @param {string} workerSid - the sid of the worker to fetch
6668
* @returns {Promise<import('./Worker')>} - A worker with given sid
6769
*/
@@ -70,14 +72,33 @@ class Workspace {
7072
}
7173

7274
/**
73-
* Fetch workers of this {@link Workspace}
75+
* Fetch worker info of this {@link Workspace} by given sid
76+
* @param {string} workerSid - the sid of the worker to fetch
77+
* @returns {Promise<WorkerInfo>} - A worker with given sid
78+
*/
79+
fetchWorkerInfo(workerSid) {
80+
return this.workspaceEntity.fetchWorker(workerSid);
81+
}
82+
83+
/**
84+
* @deprecated use {@link Workspace#fetchWorkersInfo}
85+
* @description Fetch workers of this {@link Workspace}
7486
* @param {FetchWorkersParams} [params]
7587
* @returns {Promise<Map<string, import('./Worker')>>} - A map with the workers
7688
*/
7789
fetchWorkers(params) {
7890
return this.workspaceEntity.fetchWorkers(params).then(() => this.workspaceEntity.Workers);
7991
}
8092

93+
/**
94+
* Fetch workers info of this {@link Workspace}
95+
* @param {FetchWorkerInfoParams} [params]
96+
* @returns {Promise<Map<string, WorkerInfo>>} - A map with the workers info
97+
*/
98+
fetchWorkersInfo(params) {
99+
return this.workspaceEntity.fetchWorkers(params).then(() => this.workspaceEntity.Workers);
100+
}
101+
81102
/**
82103
* Fetch task queue of this {@link Workspace} by given sid
83104
* @param {string} queueSid - the sid of the task queue to fetch
@@ -158,29 +179,3 @@ class Workspace {
158179

159180
export default Workspace;
160181

161-
/**
162-
* @typedef {Object} WorkspaceOptions
163-
* @property {string} [region] - the realm for connections (ex. "stage-us1")
164-
* @property {number} [pageSize] - The number of items returned in each request
165-
* @property {string} [logLevel='error'] - The level of logging to enable
166-
* ['error', 'warn', 'info', 'debug', 'trace', 'silent']
167-
*/
168-
169-
/**
170-
* @typedef {Object} FetchWorkersParams
171-
* @property {string} [AfterSid]
172-
* @property {string} [FriendlyName]
173-
* @property {string} [ActivitySid]
174-
* @property {string} [ActivityName]
175-
* @property {string} [TargetWorkersExpression]
176-
* @property {"DateStatusChanged:asc" | "DateStatusChanged:desc"} [Ordering]
177-
* @property {number} [MaxWorkers]
178-
*/
179-
180-
/**
181-
* @typedef {Object} FetchTaskQueuesParams
182-
* @property {string} [AfterSid]
183-
* @property {string} [FriendlyName]
184-
* @property {"DateUpdated:asc" | "DateUpdated:desc"} [Ordering]
185-
* @property {string} [WorkerSid]
186-
*/

lib/data/WorkspaceEntity.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import path from 'path';
1313
/**
1414
* A data entity which represents a Workspace
1515
* @classdesc A collection representing the {@link Worker}s and {@link TaskQueue}s available to a Workspace.
16-
* @param {Worker} worker - The {@link Worker}
16+
* @param {String} workspaceSid - The sid of the workspace
1717
* @param {Request} request - The {@link Request}
1818
* @param {import('Workspace').WorkspaceOptions} [options]
19-
* @property {Map<string, Worker>} Workers - The list of {@link Worker}s available to a {@link Workspace}
19+
* @property {Map<string, WorkerInfo>} Workers - The list of {@link WorkerInfo}s available to a {@link Workspace}
2020
* @property {Map<string, TaskQueue>} TaskQueues - The list of {@link TaskQueue}s available to a {@link Workspace}
2121
*/
2222
export default class WorkspaceEntity {
@@ -68,7 +68,7 @@ export default class WorkspaceEntity {
6868
}
6969

7070
/**
71-
* @returns {Map<string, Worker>}
71+
* @returns {Map<string, WorkerInfo>}
7272
*/
7373
get Workers() {
7474
return this._Workers;
@@ -84,7 +84,7 @@ export default class WorkspaceEntity {
8484
/**
8585
* @public
8686
* @param {string} workerSid
87-
* @returns {Promise<Worker>}
87+
* @returns {Promise<WorkerInfo>}
8888
*/
8989
fetchWorker(workerSid) {
9090
const requestURL = path.join(this._routes.getRoute(WORKER_LIST).path, workerSid);
@@ -98,7 +98,7 @@ export default class WorkspaceEntity {
9898
* Retrieve all the {@link Worker}s for the {@link Workspace}
9999
* @public
100100
* @param {import('Workspace').FetchWorkersParams} params
101-
* @returns {Promise<Map<string, Worker>>}
101+
* @returns {Promise<Map<string, WorkerInfo>>}
102102
*/
103103
fetchWorkers(params) {
104104
this._Workers = new Map();
@@ -147,7 +147,7 @@ export default class WorkspaceEntity {
147147
* @private
148148
* @param {Paginator} page
149149
* @param {number} maxWorkers
150-
* @returns {Promise<Map<string, Worker>>}
150+
* @returns {Promise<Map<string, WorkerInfo>>}
151151
*/
152152
_getAllWorkers(page, maxWorkers = DEFAULT_MAX_WORKERS) {
153153
return page.then(async(paginator) => {
@@ -174,7 +174,7 @@ export default class WorkspaceEntity {
174174
* Helper method to make a request to TaskRouter to fetch a particular page of {@link Workspace} objects
175175
* @private
176176
* @param {Object} args
177-
* @returns {Promise<Map<string, Worker>>}
177+
* @returns {Promise<Map<string, WorkerInfo>>}
178178
*/
179179
_getWorkerPage(args) {
180180
args = args || {};

lib/types.jsdoc.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @typedef {Object} WorkspaceOptions
3+
* @property {string} [region] - the realm for connections (ex. "stage-us1")
4+
* @property {number} [pageSize] - The number of items returned in each request
5+
* @property {string} [logLevel='error'] - The level of logging to enable
6+
* ['error', 'warn', 'info', 'debug', 'trace', 'silent']
7+
*/
8+
9+
/**
10+
* @deprecated
11+
* @typedef {Object} FetchWorkersParams
12+
* @property {string} [AfterSid]
13+
* @property {string} [FriendlyName]
14+
* @property {string} [ActivitySid]
15+
* @property {string} [ActivityName]
16+
* @property {string} [TargetWorkersExpression]
17+
* @property {"DateStatusChanged:asc" | "DateStatusChanged:desc"} [Ordering]
18+
* @property {number} [MaxWorkers]
19+
*/
20+
21+
/**
22+
* @typedef {FetchWorkersParams} FetchWorkerInfoParams
23+
*/
24+
25+
/**
26+
* @typedef {Object} FetchTaskQueuesParams
27+
* @property {string} [AfterSid]
28+
* @property {string} [FriendlyName]
29+
* @property {"DateUpdated:asc" | "DateUpdated:desc"} [Ordering]
30+
* @property {string} [WorkerSid]
31+
*/
32+
33+
34+
/**
35+
* @typedef {Object} WorkerInfo
36+
* @property {string} accountSid - The SID of the owning account of the Worker
37+
* @property {string} activityName - The name of the current activity
38+
* @property {string} activitySid - The SID of the current activity
39+
* @property {Object} attributes - Custom attributes describing the Worker
40+
* @property {boolean} available - Whether the Worker is available to take on Tasks
41+
* @property {Date} dateCreated - When the Worker was created
42+
* @property {Date} dateStatusChanged - When the Worker’s state last changed
43+
* @property {Date} dateUpdated - When the Worker was last updated
44+
* @property {string} name - The friendly name of the Worker
45+
* @property {string} sid - The SID of the Worker
46+
* @property {string} workspaceSid - The SID of the Workspace the Worker belongs to
47+
* @property {string} version - The version of this Worker
48+
* @property {string} workerSid - [Duplicate] sid of the Worker
49+
* @property {string} workerActivitySid - [Duplicate] activitySid of the Worker
50+
* @property {Date} dateActivityChanged - [Duplicate] dateStatusChanged of the Worker
51+
* @property {string} friendlyName - [Duplicate] name of the Worker
52+
*/

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@
5656
"url": "https://github.com/twilio/twilio-taskrouter.js.git"
5757
},
5858
"dependencies": {
59-
"@babel/runtime": "^7.16.3",
60-
"axios": "^1.8.2 ",
59+
"@babel/runtime": "7.26.10",
60+
"axios": "^1.8.2",
6161
"events": "3.3.0",
6262
"graphql": "^14",
6363
"graphql-ws": "^5.16.2",

sample-app/src/app/components/worker.client.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { Supervisor, Workspace } from 'twilio-taskrouter';
3+
import { Supervisor, WorkerInfo, Workspace } from 'twilio-taskrouter';
44
import { LogContextType, useLogContext } from '@/lib/log-context';
55
import React, { useEffect, useState } from 'react';
66
import Logger from './logger.client';
@@ -55,14 +55,14 @@ const WorkerWorkspace = ({ token, environment = 'stage' }: { token: string; envi
5555
}
5656
};
5757

58-
const handleFetchWorkers = async () => {
58+
const handleFetchWorkersInfo = async () => {
5959
try {
60-
const fetchWorkersReq = await workSpace?.fetchWorkers();
61-
if (fetchWorkersReq) {
62-
const workers = Array.from(fetchWorkersReq.values());
60+
const fetchWorkersInfoReq = await workSpace?.fetchWorkersInfo();
61+
if (fetchWorkersInfoReq) {
62+
const workers = Array.from(fetchWorkersInfoReq.values());
6363
appendLogs('======================================================');
6464
appendLogs('Workers fetched');
65-
workers.forEach((worker: any) => {
65+
workers.forEach((worker: WorkerInfo) => {
6666
appendLogs('Workers sid: ' + worker.sid);
6767
appendLogs('Workers friendlyName: ' + worker.friendlyName);
6868
appendLogs('Workers activity: ' + worker.activityName);
@@ -267,7 +267,7 @@ const WorkerWorkspace = ({ token, environment = 'stage' }: { token: string; envi
267267
Disconnect
268268
</button>
269269
<button
270-
onClick={handleFetchWorkers}
270+
onClick={handleFetchWorkersInfo}
271271
className="bg-[#0263e0] enabled:hover:bg-[#06033a] text-white py-2 px-4 mb-5 rounded-sm disabled:opacity-75 disabled:pointer-events-none font-medium"
272272
>
273273
Fetch Workers

scripts/docs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const fs = require('fs');
99
const docs = process.argv[2];
1010

1111
const publicClasses = [
12+
'lib/types.jsdoc.js',
1213
'lib/Activity.js',
1314
'lib/Channel.js',
1415
'lib/core/transfer/OutgoingTransfer.js',

test/unit/spec/Workspace.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ describe('Workspace', () => {
133133
});
134134
});
135135

136+
/**
137+
* Deprecated method - replaced by fetchWorkersInfo
138+
*/
136139
describe('#fetchWorkers', () => {
137140
const requestURL = 'Workspaces/WSxxx/Workers';
138141

@@ -251,7 +254,132 @@ describe('Workspace', () => {
251254
expect(stub.withArgs(url, API_V1).calledOnce).to.be.true;
252255
});
253256
});
257+
});
258+
259+
describe('#fetchWorkersInfo', () => {
260+
const requestURL = 'Workspaces/WSxxx/Workers';
261+
262+
let sandbox;
263+
beforeEach(() => {
264+
sandbox = sinon.sandbox.create();
265+
});
266+
267+
afterEach(() => sandbox.restore());
268+
269+
it('should fetch workers info', () => {
270+
const workspace = new Workspace(adminToken);
271+
const requestParams = { PageSize: 1000 };
272+
const stub = sandbox.stub(Request.prototype, 'get').withArgs(requestURL, API_V1, requestParams).returns(Promise.resolve(workerList));
273+
274+
return workspace.fetchWorkersInfo().then(workers => {
275+
expect(stub.withArgs(requestURL, API_V1, requestParams).calledOnce).to.be.true;
276+
expect(workers.size).to.equal(workerList.contents.length);
277+
for (const worker of workers.values()) {
278+
expect(worker).to.be.instanceOf(WorkerContainer);
279+
}
280+
});
281+
});
282+
283+
it('should fetch workers info with args', () => {
284+
const workspace = new Workspace(adminToken);
285+
const requestParams = { 'PageSize': 1000, 'FriendlyName': 'test', 'ActivitySid': 'WAxxx', 'ActivityName': 'Idle', 'Ordering': 'DateUpdated:asc', 'TargetWorkersExpression': 'name IN [\'Alice\']' };
286+
const stub = sandbox.stub(Request.prototype, 'get').withArgs(requestURL, API_V1, requestParams).returns(Promise.resolve(workerList));
287+
288+
return workspace.fetchWorkersInfo(requestParams).then(workers => {
289+
expect(workers.size).to.equal(workerList.contents.length);
290+
expect(stub.withArgs(requestURL, API_V1, requestParams).calledOnce).to.be.true;
291+
for (const worker of workers.values()) {
292+
expect(worker).to.be.instanceOf(WorkerContainer);
293+
}
294+
});
295+
});
296+
297+
it('should paginate for the next page if needed', () => {
298+
const requestParamsPage0 = { 'PageSize': 1, 'FriendlyName': 'test' };
299+
const requestParamsPage1 = { 'PageSize': 1, 'AfterSid': 'WKxx1', 'FriendlyName': 'test' };
300+
301+
const stub = sandbox.stub(Request.prototype, 'get');
302+
stub.withArgs(requestURL, API_V1, requestParamsPage0).returns(Promise.resolve(workerListPage0));
303+
stub.withArgs(requestURL, API_V1, requestParamsPage1).returns(Promise.resolve(workerListPage1));
304+
const workspace = new Workspace(adminToken, { pageSize: 1 });
254305

306+
return workspace.fetchWorkersInfo(requestParamsPage0).then((workers) => {
307+
expect(workers.size).to.equal(workerListPage0.total);
308+
expect(stub.withArgs(requestURL, API_V1, requestParamsPage0).calledOnce).to.be.true;
309+
expect(stub.withArgs(requestURL, API_V1, requestParamsPage1).calledOnce).to.be.true;
310+
});
311+
});
312+
313+
it('should paginate with ordering parameter', () => {
314+
const requestParamsPage0 = { 'PageSize': 1, 'FriendlyName': 'test', 'Ordering': 'DateUpdated:asc' };
315+
const requestParamsPage1 = { 'PageSize': 1, 'NextToken': 'WKxx1/2022-08-09T19:09:10.763Z', 'FriendlyName': 'test', 'Ordering': 'DateUpdated:asc' };
316+
317+
const stub = sandbox.stub(Request.prototype, 'get');
318+
stub.withArgs(requestURL, API_V1, requestParamsPage0).returns(Promise.resolve(workerListPage0));
319+
stub.withArgs(requestURL, API_V1, requestParamsPage1).returns(Promise.resolve(workerListPage1));
320+
const workspace = new Workspace(adminToken, { pageSize: 1 });
321+
322+
return workspace.fetchWorkersInfo(requestParamsPage0).then((workers) => {
323+
expect(workers.size).to.equal(workerListPage0.total);
324+
expect(stub.withArgs(requestURL, API_V1, requestParamsPage0).calledOnce).to.be.true;
325+
expect(stub.withArgs(requestURL, API_V1, requestParamsPage1).calledOnce).to.be.true;
326+
});
327+
});
328+
329+
it('should fetch max workers', async() => {
330+
const requestParamsPage0 = { 'PageSize': 1 };
331+
const requestParamsPage1 = { 'PageSize': 1, 'AfterSid': 'WKxx1' };
332+
333+
const stub = sandbox.stub(Request.prototype, 'get');
334+
stub.withArgs(requestURL, API_V1, requestParamsPage0).returns(Promise.resolve(workerListPage0));
335+
stub.withArgs(requestURL, API_V1, requestParamsPage1).returns(Promise.resolve(workerListPage1));
336+
const workspace = new Workspace(adminToken, { pageSize: 1 });
337+
const maxWorkers = 1;
338+
339+
const partOfWorkers = await workspace.fetchWorkersInfo({ MaxWorkers: maxWorkers });
340+
341+
expect(stub.withArgs(requestURL, API_V1, requestParamsPage0).calledOnce).to.be.true;
342+
expect(stub.withArgs(requestURL, API_V1, requestParamsPage1).calledOnce).to.be.false;
343+
344+
const allWorkers = await workspace.fetchWorkersInfo();
345+
346+
expect(partOfWorkers.size).to.equal(maxWorkers);
347+
expect(partOfWorkers.size).to.be.lessThan(allWorkers.size);
348+
});
349+
350+
it('should fetch max workers and split the page if needed', async() => {
351+
const requestParamsPage0 = { 'PageSize': 2 };
352+
const requestParamsPage1 = { 'PageSize': 2, 'AfterSid': 'Wkxx2' };
353+
354+
const stub = sandbox.stub(Request.prototype, 'get');
355+
stub.withArgs(requestURL, API_V1, requestParamsPage0).returns(Promise.resolve(workerList2Page0));
356+
stub.withArgs(requestURL, API_V1, requestParamsPage1).returns(Promise.resolve(workerList2Page1));
357+
const workspace = new Workspace(adminToken, { pageSize: 2 });
358+
const maxWorkers = 1;
359+
360+
const partOfWorkers = await workspace.fetchWorkersInfo({ MaxWorkers: maxWorkers });
361+
362+
expect(stub.withArgs(requestURL, API_V1, requestParamsPage0).calledOnce).to.be.true;
363+
expect(stub.withArgs(requestURL, API_V1, requestParamsPage1).calledOnce).to.be.false;
364+
365+
const allWorkers = await workspace.fetchWorkersInfo();
366+
367+
expect(partOfWorkers.size).to.equal(maxWorkers);
368+
expect(partOfWorkers.size).to.be.lessThan(allWorkers.size);
369+
});
370+
371+
it('should fetch worker with sid', () => {
372+
const workspace = new Workspace(adminToken);
373+
const workerInstance = workerList.contents[0];
374+
const url = path.join(requestURL, workerInstance.sid);
375+
const stub = sandbox.stub(Request.prototype, 'get').withArgs(url, API_V1).returns(Promise.resolve(workerInstance));
376+
377+
return workspace.fetchWorkerInfo(workerInstance.sid).then(queue => {
378+
expect(queue.sid).to.equal(workerInstance.sid);
379+
expect(queue).to.be.instanceOf(WorkerContainer);
380+
expect(stub.withArgs(url, API_V1).calledOnce).to.be.true;
381+
});
382+
});
255383
});
256384

257385
describe('#fetchTasks', () => {

0 commit comments

Comments
 (0)