@morgan-stanley/composeui-fdc3 0.1.0-alpha.11 → 0.1.0-alpha.12
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/dist/fdc3-iife-bundle.js +149 -63
- package/package.json +11 -11
- package/src/ComposeUIContextListener.spec.ts +10 -3
- package/src/ComposeUIDesktopAgent.spec.ts +6 -3
- package/src/ComposeUIDesktopAgent.ts +46 -46
- package/src/{ComposeUIMessagingChannelFactory.spec.ts → ComposeUIMessagingChannelHandler.spec.ts} +10 -10
- package/src/index.ts +31 -0
- package/src/infrastructure/{ChannelFactory.ts → ChannelHandler.ts} +38 -1
- package/src/infrastructure/ChannelItem.ts +3 -0
- package/src/infrastructure/ComposeUIChannel.ts +1 -1
- package/src/infrastructure/ComposeUIContextListener.ts +8 -1
- package/src/infrastructure/ComposeUIIntentResolution.ts +5 -5
- package/src/infrastructure/ComposeUIPrivateChannel.ts +1 -1
- package/src/infrastructure/ComposeUITopic.ts +8 -0
- package/src/infrastructure/{MessagingChannelFactory.ts → MessagingChannelHandler.ts} +78 -15
- package/src/infrastructure/MessagingIntentsClient.ts +7 -7
package/dist/fdc3-iife-bundle.js
CHANGED
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
/**
|
|
136
136
|
* @license
|
|
137
137
|
* author: Morgan Stanley
|
|
138
|
-
* composeui-messaging-abstractions.js v0.1.0-alpha.
|
|
138
|
+
* composeui-messaging-abstractions.js v0.1.0-alpha.12
|
|
139
139
|
* Released under the Apache-2.0 license.
|
|
140
140
|
*/
|
|
141
141
|
|
|
@@ -402,6 +402,12 @@
|
|
|
402
402
|
static joinUserChannel() {
|
|
403
403
|
return `${this.topicRoot}/${this.joinUserChannelSuffix}`;
|
|
404
404
|
}
|
|
405
|
+
static channelSelectorFromUI(instanceId) {
|
|
406
|
+
return `${this.topicRoot}/channelSelector/UI/${instanceId}`;
|
|
407
|
+
}
|
|
408
|
+
static channelSelectorFromAPI(instanceId) {
|
|
409
|
+
return `${this.topicRoot}/channelSelector/API/${instanceId}`;
|
|
410
|
+
}
|
|
405
411
|
static getInfo() {
|
|
406
412
|
return `${this.topicRoot}/${this.getInfoSuffix}`;
|
|
407
413
|
}
|
|
@@ -520,6 +526,7 @@
|
|
|
520
526
|
}
|
|
521
527
|
async subscribe(channelId, channelType) {
|
|
522
528
|
await this.registerContextListener(channelId, channelType);
|
|
529
|
+
console.debug("Subscribed context listener with id: ", this.id, ", to channel: ", channelId, ", of type: ", channelType, ", for context type: ", this.contextType);
|
|
523
530
|
const subscribeTopic = ComposeUITopic.broadcast(channelId, channelType);
|
|
524
531
|
this.unsubscribable = await this.jsonMessaging.subscribeJson(subscribeTopic, async (context) => {
|
|
525
532
|
if (!this.contextType || this.contextType == context.type) {
|
|
@@ -531,6 +538,7 @@
|
|
|
531
538
|
}
|
|
532
539
|
}
|
|
533
540
|
});
|
|
541
|
+
console.log("Registered context listener with id: ", this.id, ", to topic: ", subscribeTopic);
|
|
534
542
|
this.isSubscribed = true;
|
|
535
543
|
}
|
|
536
544
|
async handleContextMessage(context) {
|
|
@@ -562,15 +570,17 @@
|
|
|
562
570
|
}
|
|
563
571
|
async unsubscribe() {
|
|
564
572
|
if (!this.unsubscribable || !this.isSubscribed) {
|
|
573
|
+
console.debug("The current listener is not subscribed.");
|
|
565
574
|
return;
|
|
566
575
|
}
|
|
567
576
|
try {
|
|
568
577
|
await this.leaveChannel();
|
|
578
|
+
console.debug("Unsubscribed context listener with id: ", this.id);
|
|
569
579
|
}
|
|
570
580
|
catch (err) {
|
|
571
581
|
console.log(err);
|
|
572
582
|
}
|
|
573
|
-
this.unsubscribable.unsubscribe();
|
|
583
|
+
await this.unsubscribable.unsubscribe();
|
|
574
584
|
this.isSubscribed = false;
|
|
575
585
|
if (this.unsubscribeCallback) {
|
|
576
586
|
this.unsubscribeCallback(this);
|
|
@@ -591,6 +601,7 @@
|
|
|
591
601
|
this.id = response.id;
|
|
592
602
|
}
|
|
593
603
|
async leaveChannel() {
|
|
604
|
+
console.debug("Removing context listener with id: ", this.id);
|
|
594
605
|
const request = new Fdc3RemoveContextListenerRequest(window.composeui.fdc3.config?.instanceId, this.id, this.contextType);
|
|
595
606
|
const response = await this.jsonMessaging.invokeJsonService(ComposeUITopic.removeContextListener(), request);
|
|
596
607
|
if (!response) {
|
|
@@ -652,7 +663,7 @@
|
|
|
652
663
|
this.jsonMessaging = jsonMessaging;
|
|
653
664
|
this.displayMetadata = displayMetadata;
|
|
654
665
|
}
|
|
655
|
-
//Broadcasting on the composeui/fdc3/v2.0
|
|
666
|
+
//Broadcasting on the composeui/fdc3/v2.0/<channel>/broadcast topic
|
|
656
667
|
async broadcast(context) {
|
|
657
668
|
//Setting the last published context message.
|
|
658
669
|
this.lastContexts.set(context.type, context);
|
|
@@ -1218,13 +1229,23 @@
|
|
|
1218
1229
|
* and limitations under the License.
|
|
1219
1230
|
*
|
|
1220
1231
|
*/
|
|
1221
|
-
class
|
|
1232
|
+
class MessagingChannelHandler {
|
|
1222
1233
|
jsonMessaging;
|
|
1223
1234
|
fdc3instanceId;
|
|
1235
|
+
channelSelector = undefined;
|
|
1224
1236
|
constructor(jsonMessaging, fdc3instanceId) {
|
|
1225
1237
|
this.jsonMessaging = jsonMessaging;
|
|
1226
1238
|
this.fdc3instanceId = fdc3instanceId;
|
|
1227
1239
|
}
|
|
1240
|
+
[Symbol.asyncDispose]() {
|
|
1241
|
+
return this.channelSelector
|
|
1242
|
+
? this.channelSelector[Symbol.asyncDispose]()
|
|
1243
|
+
: Promise.resolve();
|
|
1244
|
+
}
|
|
1245
|
+
async configureChannelSelectorFromUI() {
|
|
1246
|
+
this.channelSelector = await this.jsonMessaging.registerService(ComposeUITopic.channelSelectorFromUI(this.fdc3instanceId), this.selectUserChannelFromUIHandler);
|
|
1247
|
+
console.debug("Configured channel selector for module: ", this.fdc3instanceId);
|
|
1248
|
+
}
|
|
1228
1249
|
async getChannel(channelId, channelType) {
|
|
1229
1250
|
const topic = ComposeUITopic.findChannel();
|
|
1230
1251
|
const message = new Fdc3FindChannelRequest(channelId, channelType);
|
|
@@ -1283,20 +1304,37 @@
|
|
|
1283
1304
|
return new ComposeUIChannel(channelId, "app", this.jsonMessaging);
|
|
1284
1305
|
}
|
|
1285
1306
|
async joinUserChannel(channelId) {
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1307
|
+
try {
|
|
1308
|
+
const topic = ComposeUITopic.joinUserChannel();
|
|
1309
|
+
const request = new Fdc3JoinUserChannelRequest(channelId, this.fdc3instanceId);
|
|
1310
|
+
const response = await this.jsonMessaging.invokeJsonService(topic, request);
|
|
1311
|
+
console.debug("Received joinUserChannel response: ", response);
|
|
1312
|
+
if (!response) {
|
|
1313
|
+
throw new Error(ChannelError.CreationFailed);
|
|
1314
|
+
}
|
|
1315
|
+
if (response.error) {
|
|
1316
|
+
throw new Error(response.error);
|
|
1317
|
+
}
|
|
1318
|
+
if (!response.success) {
|
|
1319
|
+
throw new Error(ChannelError.CreationFailed);
|
|
1320
|
+
}
|
|
1321
|
+
var channel = new ComposeUIChannel(channelId, "user", this.jsonMessaging, response.displayMetadata);
|
|
1322
|
+
this.triggerChannelJoinedEvent(channel.id);
|
|
1323
|
+
return channel;
|
|
1291
1324
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1325
|
+
catch (error) {
|
|
1326
|
+
console.error("Error joining user channel: ", error);
|
|
1327
|
+
throw error;
|
|
1294
1328
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1329
|
+
}
|
|
1330
|
+
async triggerChannelJoinedEvent(id) {
|
|
1331
|
+
try {
|
|
1332
|
+
var result = await this.jsonMessaging.invokeService(ComposeUITopic.channelSelectorFromAPI(this.fdc3instanceId), id);
|
|
1333
|
+
console.debug("Triggered channel selector of container: ", this.fdc3instanceId, ", with: ", id, ", and got result:", result);
|
|
1334
|
+
}
|
|
1335
|
+
catch (error) {
|
|
1336
|
+
console.error("Error triggering channel joined event for module: ", this.fdc3instanceId, ", with channel id: ", id, ", error: ", error);
|
|
1297
1337
|
}
|
|
1298
|
-
var channel = new ComposeUIChannel(channelId, "user", this.jsonMessaging, response.displayMetadata);
|
|
1299
|
-
return channel;
|
|
1300
1338
|
}
|
|
1301
1339
|
async getUserChannels() {
|
|
1302
1340
|
var request = new Fdc3GetUserChannelsRequest(this.fdc3instanceId);
|
|
@@ -1343,6 +1381,31 @@
|
|
|
1343
1381
|
const listener = new ComposeUIContextListener(openHandled, this.jsonMessaging, handler, contextType ?? undefined);
|
|
1344
1382
|
return listener;
|
|
1345
1383
|
}
|
|
1384
|
+
async leaveCurrentChannel() {
|
|
1385
|
+
await this.triggerChannelJoinedEvent(undefined);
|
|
1386
|
+
}
|
|
1387
|
+
async selectUserChannelFromUIHandler(request) {
|
|
1388
|
+
try {
|
|
1389
|
+
if (!request) {
|
|
1390
|
+
console.debug("Empty request received when the user channel selection was requested from UI.");
|
|
1391
|
+
return null;
|
|
1392
|
+
}
|
|
1393
|
+
var objectRequest = JSON.parse(request);
|
|
1394
|
+
var joinUserChannelRequest = objectRequest;
|
|
1395
|
+
console.debug("Parsed the request from the UI when user selected a user channel to join: ", joinUserChannelRequest);
|
|
1396
|
+
if (!joinUserChannelRequest || !joinUserChannelRequest.channelId) {
|
|
1397
|
+
console.debug("Invalid request received when user selected a user channel to join to from the UI: ", request);
|
|
1398
|
+
return null;
|
|
1399
|
+
}
|
|
1400
|
+
//We should join the channel requested by the user from the UI. -> this will trigger the handler of the module/container to show which channel the app is joined to.
|
|
1401
|
+
await window.fdc3.joinUserChannel(joinUserChannelRequest.channelId);
|
|
1402
|
+
return joinUserChannelRequest.channelId;
|
|
1403
|
+
}
|
|
1404
|
+
catch (error) {
|
|
1405
|
+
console.error("Error processing request when channel selector was invoked: ", request, ", error: ", error);
|
|
1406
|
+
return null;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1346
1409
|
}
|
|
1347
1410
|
|
|
1348
1411
|
/*
|
|
@@ -1372,16 +1435,16 @@
|
|
|
1372
1435
|
|
|
1373
1436
|
class ComposeUIIntentResolution {
|
|
1374
1437
|
jsonMessaging;
|
|
1375
|
-
|
|
1438
|
+
channelHandler;
|
|
1376
1439
|
source;
|
|
1377
1440
|
intent;
|
|
1378
1441
|
messageId;
|
|
1379
|
-
constructor(messageId, jsonMessaging,
|
|
1442
|
+
constructor(messageId, jsonMessaging, channelHandler, intent, source) {
|
|
1380
1443
|
this.messageId = messageId;
|
|
1381
1444
|
this.intent = intent;
|
|
1382
1445
|
this.source = source;
|
|
1383
1446
|
this.jsonMessaging = jsonMessaging;
|
|
1384
|
-
this.
|
|
1447
|
+
this.channelHandler = channelHandler;
|
|
1385
1448
|
}
|
|
1386
1449
|
async getResult() {
|
|
1387
1450
|
const intentResolutionRequest = new Fdc3GetIntentResultRequest(this.messageId, this.intent, this.source, this.source.version);
|
|
@@ -1393,7 +1456,7 @@
|
|
|
1393
1456
|
throw new Error(result.error);
|
|
1394
1457
|
}
|
|
1395
1458
|
if (result.channelId && result.channelType) {
|
|
1396
|
-
const channel = this.
|
|
1459
|
+
const channel = this.channelHandler.getChannel(result.channelId, result.channelType);
|
|
1397
1460
|
return channel;
|
|
1398
1461
|
}
|
|
1399
1462
|
else if (result.context) {
|
|
@@ -1508,13 +1571,13 @@
|
|
|
1508
1571
|
*
|
|
1509
1572
|
*/
|
|
1510
1573
|
class MessagingIntentsClient {
|
|
1511
|
-
|
|
1574
|
+
channelHandler;
|
|
1512
1575
|
jsonMessaging;
|
|
1513
1576
|
constructor(jsonMessaging, channelFactory) {
|
|
1514
1577
|
if (!window.composeui.fdc3.config || !window.composeui.fdc3.config.instanceId) {
|
|
1515
1578
|
throw new Error(ComposeUIErrors.InstanceIdNotFound);
|
|
1516
1579
|
}
|
|
1517
|
-
this.
|
|
1580
|
+
this.channelHandler = channelFactory;
|
|
1518
1581
|
this.jsonMessaging = jsonMessaging;
|
|
1519
1582
|
}
|
|
1520
1583
|
async findIntent(intent, context, resultType) {
|
|
@@ -1542,7 +1605,7 @@
|
|
|
1542
1605
|
return message.appIntents;
|
|
1543
1606
|
}
|
|
1544
1607
|
async getIntentResolution(messageId, intent, source) {
|
|
1545
|
-
return new ComposeUIIntentResolution(messageId, this.jsonMessaging, this.
|
|
1608
|
+
return new ComposeUIIntentResolution(messageId, this.jsonMessaging, this.channelHandler, intent, source);
|
|
1546
1609
|
}
|
|
1547
1610
|
async raiseIntent(intent, context, app) {
|
|
1548
1611
|
if (typeof app == 'string') {
|
|
@@ -1557,7 +1620,7 @@
|
|
|
1557
1620
|
if (response.error) {
|
|
1558
1621
|
throw new Error(response.error);
|
|
1559
1622
|
}
|
|
1560
|
-
const intentResolution = new ComposeUIIntentResolution(response.messageId, this.jsonMessaging, this.
|
|
1623
|
+
const intentResolution = new ComposeUIIntentResolution(response.messageId, this.jsonMessaging, this.channelHandler, response.intent, response.appMetadata);
|
|
1561
1624
|
return intentResolution;
|
|
1562
1625
|
}
|
|
1563
1626
|
async raiseIntentForContext(context, app) {
|
|
@@ -1573,7 +1636,7 @@
|
|
|
1573
1636
|
if (response.error) {
|
|
1574
1637
|
throw new Error(response.error);
|
|
1575
1638
|
}
|
|
1576
|
-
const intentResolution = new ComposeUIIntentResolution(response.messageId, this.jsonMessaging, this.
|
|
1639
|
+
const intentResolution = new ComposeUIIntentResolution(response.messageId, this.jsonMessaging, this.channelHandler, response.intent, response.appMetadata);
|
|
1577
1640
|
return intentResolution;
|
|
1578
1641
|
}
|
|
1579
1642
|
}
|
|
@@ -1802,30 +1865,43 @@
|
|
|
1802
1865
|
*
|
|
1803
1866
|
*/
|
|
1804
1867
|
class ComposeUIDesktopAgent {
|
|
1805
|
-
appChannels = [];
|
|
1806
|
-
userChannels = [];
|
|
1807
|
-
privateChannels = [];
|
|
1808
1868
|
currentChannel;
|
|
1809
1869
|
topLevelContextListeners = [];
|
|
1810
1870
|
intentListeners = [];
|
|
1811
|
-
|
|
1871
|
+
channelHandler;
|
|
1812
1872
|
intentsClient;
|
|
1813
1873
|
metadataClient;
|
|
1814
1874
|
openClient;
|
|
1815
1875
|
openedAppContext;
|
|
1816
1876
|
openedAppContextHandled = false;
|
|
1817
1877
|
//TODO: we should enable passing multiple channelId to the ctor.
|
|
1818
|
-
constructor(messaging,
|
|
1878
|
+
constructor(messaging, channelHandler, intentsClient, metadataClient, openClient) {
|
|
1819
1879
|
if (!window.composeui.fdc3.config || !window.composeui.fdc3.config.instanceId) {
|
|
1820
1880
|
throw new Error(ComposeUIErrors.InstanceIdNotFound);
|
|
1821
1881
|
}
|
|
1822
1882
|
const jsonMessaging = new JsonMessaging(messaging);
|
|
1823
1883
|
// TODO: inject this directly instead of the messageRouter
|
|
1824
|
-
this.
|
|
1825
|
-
this.intentsClient = intentsClient ?? new MessagingIntentsClient(jsonMessaging, this.
|
|
1884
|
+
this.channelHandler = channelHandler ?? new MessagingChannelHandler(jsonMessaging, window.composeui.fdc3.config.instanceId);
|
|
1885
|
+
this.intentsClient = intentsClient ?? new MessagingIntentsClient(jsonMessaging, this.channelHandler);
|
|
1826
1886
|
this.metadataClient = metadataClient ?? new MessagingMetadataClient(jsonMessaging, window.composeui.fdc3.config);
|
|
1827
1887
|
this.openClient = openClient ?? new MessagingOpenClient(window.composeui.fdc3.config.instanceId, jsonMessaging, window.composeui.fdc3.openAppIdentifier);
|
|
1828
1888
|
}
|
|
1889
|
+
async [Symbol.asyncDispose]() {
|
|
1890
|
+
console.debug("Disposing ComposeUIDesktopAgent");
|
|
1891
|
+
await this.channelHandler[Symbol.asyncDispose]();
|
|
1892
|
+
for (const listener of this.intentListeners) {
|
|
1893
|
+
await listener.unsubscribe();
|
|
1894
|
+
}
|
|
1895
|
+
this.intentListeners = [];
|
|
1896
|
+
for (const listener of this.topLevelContextListeners) {
|
|
1897
|
+
await listener.unsubscribe();
|
|
1898
|
+
}
|
|
1899
|
+
this.topLevelContextListeners = [];
|
|
1900
|
+
}
|
|
1901
|
+
// This regiters an endpoint to listen when an action was initiated from the UI to select a user channel to join to.
|
|
1902
|
+
async init() {
|
|
1903
|
+
await this.channelHandler.configureChannelSelectorFromUI();
|
|
1904
|
+
}
|
|
1829
1905
|
async open(app, context) {
|
|
1830
1906
|
return await this.openClient.open(app, context);
|
|
1831
1907
|
}
|
|
@@ -1851,7 +1927,7 @@
|
|
|
1851
1927
|
return await this.intentsClient.raiseIntentForContext(context, app);
|
|
1852
1928
|
}
|
|
1853
1929
|
async addIntentListener(intent, handler) {
|
|
1854
|
-
var listener = await this.
|
|
1930
|
+
var listener = await this.channelHandler.getIntentListener(intent, handler);
|
|
1855
1931
|
this.intentListeners.push(listener);
|
|
1856
1932
|
return listener;
|
|
1857
1933
|
}
|
|
@@ -1872,7 +1948,7 @@
|
|
|
1872
1948
|
//There is no context to handle -aka app was not opened via the fdc3.open
|
|
1873
1949
|
this.openedAppContextHandled = true;
|
|
1874
1950
|
}
|
|
1875
|
-
const listener = await this.
|
|
1951
|
+
const listener = await this.channelHandler.getContextListener(this.openedAppContextHandled, this.currentChannel, handler, contextType);
|
|
1876
1952
|
this.topLevelContextListeners.push(listener);
|
|
1877
1953
|
if (!this.currentChannel) {
|
|
1878
1954
|
return listener;
|
|
@@ -1884,20 +1960,18 @@
|
|
|
1884
1960
|
});
|
|
1885
1961
|
}
|
|
1886
1962
|
async getUserChannels() {
|
|
1887
|
-
return await this.
|
|
1963
|
+
return await this.channelHandler.getUserChannels();
|
|
1888
1964
|
}
|
|
1889
1965
|
async joinUserChannel(channelId) {
|
|
1890
1966
|
if (this.currentChannel) {
|
|
1891
1967
|
//DesktopAgnet clients can listen on only one channel
|
|
1968
|
+
console.debug("Leaving current channel: ", this.currentChannel.id);
|
|
1892
1969
|
await this.leaveCurrentChannel();
|
|
1893
1970
|
}
|
|
1894
|
-
let channel = this.
|
|
1971
|
+
let channel = await this.channelHandler.joinUserChannel(channelId);
|
|
1972
|
+
console.debug("Joined to user channel: ", channelId);
|
|
1895
1973
|
if (!channel) {
|
|
1896
|
-
|
|
1897
|
-
if (!channel) {
|
|
1898
|
-
throw new Error(ChannelError.NoChannelFound);
|
|
1899
|
-
}
|
|
1900
|
-
this.addChannel(channel);
|
|
1974
|
+
throw new Error(ChannelError.NoChannelFound);
|
|
1901
1975
|
}
|
|
1902
1976
|
this.currentChannel = channel;
|
|
1903
1977
|
for (const listener of this.topLevelContextListeners) {
|
|
@@ -1908,26 +1982,25 @@
|
|
|
1908
1982
|
}
|
|
1909
1983
|
}
|
|
1910
1984
|
async getOrCreateChannel(channelId) {
|
|
1911
|
-
let appChannel = this.
|
|
1912
|
-
if (appChannel) {
|
|
1913
|
-
return appChannel;
|
|
1914
|
-
}
|
|
1915
|
-
appChannel = await this.channelFactory.createAppChannel(channelId);
|
|
1916
|
-
this.addChannel(appChannel);
|
|
1985
|
+
let appChannel = await this.channelHandler.createAppChannel(channelId);
|
|
1917
1986
|
return appChannel;
|
|
1918
1987
|
}
|
|
1919
1988
|
async createPrivateChannel() {
|
|
1920
|
-
return await this.
|
|
1989
|
+
return await this.channelHandler.createPrivateChannel();
|
|
1921
1990
|
}
|
|
1922
1991
|
async getCurrentChannel() {
|
|
1923
1992
|
return this.currentChannel ?? null;
|
|
1924
1993
|
}
|
|
1925
1994
|
async leaveCurrentChannel() {
|
|
1926
1995
|
//The context listeners, that have been added through the `fdc3.addContextListener()` should unsubscribe
|
|
1996
|
+
console.debug("Unsubscribing top level context listeners: ", this.topLevelContextListeners);
|
|
1927
1997
|
for (const listener of this.topLevelContextListeners) {
|
|
1928
1998
|
await listener.unsubscribe();
|
|
1929
1999
|
}
|
|
1930
|
-
this.currentChannel
|
|
2000
|
+
if (this.currentChannel) {
|
|
2001
|
+
await this.channelHandler.leaveCurrentChannel();
|
|
2002
|
+
this.currentChannel = undefined;
|
|
2003
|
+
}
|
|
1931
2004
|
}
|
|
1932
2005
|
async getInfo() {
|
|
1933
2006
|
return await this.metadataClient.getInfo();
|
|
@@ -1953,21 +2026,6 @@
|
|
|
1953
2026
|
console.error("The opened app via fdc3.open() could not retrieve the context: ", err);
|
|
1954
2027
|
}
|
|
1955
2028
|
}
|
|
1956
|
-
addChannel(channel) {
|
|
1957
|
-
if (channel == null)
|
|
1958
|
-
return;
|
|
1959
|
-
switch (channel.type) {
|
|
1960
|
-
case "app":
|
|
1961
|
-
this.appChannels.push(channel);
|
|
1962
|
-
break;
|
|
1963
|
-
case "user":
|
|
1964
|
-
this.userChannels.push(channel);
|
|
1965
|
-
break;
|
|
1966
|
-
case "private":
|
|
1967
|
-
this.privateChannels.push(channel);
|
|
1968
|
-
break;
|
|
1969
|
-
}
|
|
1970
|
-
}
|
|
1971
2029
|
async callHandlerOnChannelsCurrentContext(listener) {
|
|
1972
2030
|
const lastContext = await this.currentChannel.getCurrentContext(listener.contextType);
|
|
1973
2031
|
if (lastContext) {
|
|
@@ -1994,6 +2052,30 @@
|
|
|
1994
2052
|
const openAppIdentifier = window.composeui.fdc3.openAppIdentifier;
|
|
1995
2053
|
const messaging = window.composeui.messaging.communicator;
|
|
1996
2054
|
const fdc3 = new ComposeUIDesktopAgent(messaging);
|
|
2055
|
+
await fdc3.init();
|
|
2056
|
+
let _disposed = false;
|
|
2057
|
+
const disposeAgent = () => {
|
|
2058
|
+
if (_disposed) {
|
|
2059
|
+
return;
|
|
2060
|
+
}
|
|
2061
|
+
_disposed = true;
|
|
2062
|
+
try {
|
|
2063
|
+
const agent = window.fdc3 || fdc3;
|
|
2064
|
+
if (agent) {
|
|
2065
|
+
agent[Symbol.asyncDispose]();
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
catch (err) {
|
|
2069
|
+
console.warn("Error disposing FDC3 agent", err);
|
|
2070
|
+
}
|
|
2071
|
+
finally {
|
|
2072
|
+
// remove handlers after first run
|
|
2073
|
+
window.removeEventListener("beforeunload", disposeAgent);
|
|
2074
|
+
window.removeEventListener("unload", disposeAgent);
|
|
2075
|
+
}
|
|
2076
|
+
};
|
|
2077
|
+
window.addEventListener("beforeunload", disposeAgent);
|
|
2078
|
+
window.addEventListener("unload", disposeAgent);
|
|
1997
2079
|
if (channelId) {
|
|
1998
2080
|
await fdc3.joinUserChannel(channelId)
|
|
1999
2081
|
.then(async () => {
|
|
@@ -2001,11 +2083,13 @@
|
|
|
2001
2083
|
await fdc3.getOpenedAppContext()
|
|
2002
2084
|
.then(() => {
|
|
2003
2085
|
window.fdc3 = fdc3;
|
|
2086
|
+
console.log("FDC3 initialized, handled initial context which initiates that the app was opened via `fdc3.open` and joined to channel: ", channelId, window.fdc3);
|
|
2004
2087
|
window.dispatchEvent(new Event("fdc3Ready"));
|
|
2005
2088
|
});
|
|
2006
2089
|
}
|
|
2007
2090
|
else {
|
|
2008
2091
|
window.fdc3 = fdc3;
|
|
2092
|
+
console.log("FDC3 initialized and joined to channel: ", channelId, window.fdc3);
|
|
2009
2093
|
window.dispatchEvent(new Event("fdc3Ready"));
|
|
2010
2094
|
}
|
|
2011
2095
|
});
|
|
@@ -2014,11 +2098,13 @@
|
|
|
2014
2098
|
if (openAppIdentifier) {
|
|
2015
2099
|
await fdc3.getOpenedAppContext().then(() => {
|
|
2016
2100
|
window.fdc3 = fdc3;
|
|
2101
|
+
console.log("FDC3 initialized, handled initial context which initiates that the app was opened via `fdc3.open`: ", window.fdc3);
|
|
2017
2102
|
window.dispatchEvent(new Event("fdc3Ready"));
|
|
2018
2103
|
});
|
|
2019
2104
|
}
|
|
2020
2105
|
else {
|
|
2021
2106
|
window.fdc3 = fdc3;
|
|
2107
|
+
console.log("FDC3 initialized: ", window.fdc3);
|
|
2022
2108
|
window.dispatchEvent(new Event("fdc3Ready"));
|
|
2023
2109
|
}
|
|
2024
2110
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morgan-stanley/composeui-fdc3",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "FDC3 DesktopAgent implementation for Compose UI",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@finos/fdc3": "~2.0.3",
|
|
21
21
|
"@morgan-stanley/composeui-messaging-abstractions": "*",
|
|
22
|
-
"rxjs": "
|
|
22
|
+
"rxjs": "7.8.2"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
@@ -30,16 +30,16 @@
|
|
|
30
30
|
"provenance": true
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@rollup/plugin-commonjs": "
|
|
34
|
-
"@rollup/plugin-node-resolve": "16.0.
|
|
33
|
+
"@rollup/plugin-commonjs": "29.0.0",
|
|
34
|
+
"@rollup/plugin-node-resolve": "16.0.3",
|
|
35
35
|
"@types/node": "^24.5.2",
|
|
36
|
-
"jsdom": "^
|
|
37
|
-
"rimraf": "6.
|
|
38
|
-
"rollup": "
|
|
36
|
+
"jsdom": "^28.1.0",
|
|
37
|
+
"rimraf": "6.1.3",
|
|
38
|
+
"rollup": "4.59.0",
|
|
39
39
|
"ts-node": "10.9.2",
|
|
40
|
-
"tslib": "
|
|
41
|
-
"typescript": "
|
|
42
|
-
"vitest": "
|
|
40
|
+
"tslib": "2.8.1",
|
|
41
|
+
"typescript": "5.9.3",
|
|
42
|
+
"vitest": "4.0.18"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "78d8bf3c57db6188e507391de8dfe1720985c315"
|
|
45
45
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import { ContextHandler } from '@finos/fdc3';
|
|
14
15
|
import { ComposeUIContextListener } from './infrastructure/ComposeUIContextListener';
|
|
15
16
|
import { Fdc3AddContextListenerResponse } from './infrastructure/messages/Fdc3AddContextListenerResponse';
|
|
16
17
|
import { IMessaging, JsonMessaging } from '@morgan-stanley/composeui-messaging-abstractions';
|
|
@@ -34,14 +35,20 @@ const wrongContext = {
|
|
|
34
35
|
type: 'dummy'
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
38
|
+
export interface ContextHandlerMock {
|
|
39
|
+
contextHandler: ContextHandler;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let contextMessageHandlerMock : ContextHandlerMock;
|
|
40
43
|
|
|
41
44
|
describe('Tests for ComposeUIContextListener implementation API', () => {
|
|
42
45
|
|
|
43
46
|
beforeEach(async () => {
|
|
44
47
|
|
|
48
|
+
contextMessageHandlerMock = {
|
|
49
|
+
contextHandler: (_: unknown) => {}
|
|
50
|
+
};
|
|
51
|
+
|
|
45
52
|
// @ts-ignore
|
|
46
53
|
window.composeui = {
|
|
47
54
|
fdc3: {
|
|
@@ -18,7 +18,7 @@ import { ComposeUIDesktopAgent } from './ComposeUIDesktopAgent';
|
|
|
18
18
|
import { ComposeUITopic } from './infrastructure/ComposeUITopic';
|
|
19
19
|
import { Channel, ChannelError, ContextHandler } from '@finos/fdc3';
|
|
20
20
|
import { ComposeUIErrors } from './infrastructure/ComposeUIErrors';
|
|
21
|
-
import {
|
|
21
|
+
import { ChannelHandler } from './infrastructure/ChannelHandler';
|
|
22
22
|
import { ComposeUIPrivateChannel } from './infrastructure/ComposeUIPrivateChannel';
|
|
23
23
|
import { ChannelType } from './infrastructure/ChannelType';
|
|
24
24
|
import { Fdc3GetOpenedAppContextResponse } from './infrastructure/messages/Fdc3GetOpenedAppContextResponse';
|
|
@@ -36,7 +36,7 @@ const testInstrument = {
|
|
|
36
36
|
|
|
37
37
|
const contextMessageHandlerMock = vi.fn((_ctx) => 'dummy');
|
|
38
38
|
|
|
39
|
-
const buildChannelFactory = (jm: JsonMessaging):
|
|
39
|
+
const buildChannelFactory = (jm: JsonMessaging): ChannelHandler => ({
|
|
40
40
|
createPrivateChannel: vi.fn(() =>
|
|
41
41
|
Promise.resolve(new ComposeUIPrivateChannel('privateId', 'localInstance', jm, true))
|
|
42
42
|
),
|
|
@@ -51,7 +51,10 @@ const buildChannelFactory = (jm: JsonMessaging): ChannelFactory => ({
|
|
|
51
51
|
getContextListener: vi.fn(
|
|
52
52
|
(_openHandled: boolean, _channel: Channel, handler: ContextHandler, contextType?: string) =>
|
|
53
53
|
Promise.resolve(new ComposeUIContextListener(true, jm, handler, contextType))
|
|
54
|
-
)
|
|
54
|
+
),
|
|
55
|
+
leaveCurrentChannel: vi.fn(() => Promise.resolve()),
|
|
56
|
+
configureChannelSelectorFromUI: vi.fn(() => Promise.resolve()),
|
|
57
|
+
[Symbol.asyncDispose]: vi.fn(() => Promise.resolve())
|
|
55
58
|
});
|
|
56
59
|
|
|
57
60
|
describe('Tests for ComposeUIDesktopAgent implementation API', () => {
|
|
@@ -29,8 +29,8 @@ import {
|
|
|
29
29
|
import { IMessaging, JsonMessaging } from "@morgan-stanley/composeui-messaging-abstractions";
|
|
30
30
|
import { ComposeUIContextListener } from './infrastructure/ComposeUIContextListener';
|
|
31
31
|
import { ComposeUIErrors } from './infrastructure/ComposeUIErrors';
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
32
|
+
import { ChannelHandler } from './infrastructure/ChannelHandler';
|
|
33
|
+
import { MessagingChannelHandler } from './infrastructure/MessagingChannelHandler';
|
|
34
34
|
import { MessagingIntentsClient } from './infrastructure/MessagingIntentsClient';
|
|
35
35
|
import { IntentsClient } from './infrastructure/IntentsClient';
|
|
36
36
|
import { MetadataClient } from './infrastructure/MetadataClient';
|
|
@@ -38,14 +38,11 @@ import { MessagingMetadataClient } from './infrastructure/MessagingMetadataClien
|
|
|
38
38
|
import { OpenClient } from "./infrastructure/OpenClient";
|
|
39
39
|
import { MessagingOpenClient } from "./infrastructure/MessagingOpenClient";
|
|
40
40
|
|
|
41
|
-
export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
42
|
-
private appChannels: Channel[] = [];
|
|
43
|
-
private userChannels: Channel[] = [];
|
|
44
|
-
private privateChannels: Channel[] = [];
|
|
41
|
+
export class ComposeUIDesktopAgent implements DesktopAgent, AsyncDisposable {
|
|
45
42
|
private currentChannel?: Channel;
|
|
46
43
|
private topLevelContextListeners: ComposeUIContextListener[] = [];
|
|
47
44
|
private intentListeners: Listener[] = [];
|
|
48
|
-
private
|
|
45
|
+
private channelHandler: ChannelHandler;
|
|
49
46
|
private intentsClient: IntentsClient;
|
|
50
47
|
private metadataClient: MetadataClient;
|
|
51
48
|
private openClient: OpenClient;
|
|
@@ -55,7 +52,7 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
|
55
52
|
//TODO: we should enable passing multiple channelId to the ctor.
|
|
56
53
|
constructor(
|
|
57
54
|
messaging: IMessaging,
|
|
58
|
-
|
|
55
|
+
channelHandler?: ChannelHandler,
|
|
59
56
|
intentsClient?: IntentsClient,
|
|
60
57
|
metadataClient?: MetadataClient,
|
|
61
58
|
openClient?: OpenClient) {
|
|
@@ -67,12 +64,35 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
|
67
64
|
const jsonMessaging: JsonMessaging = new JsonMessaging(messaging);
|
|
68
65
|
|
|
69
66
|
// TODO: inject this directly instead of the messageRouter
|
|
70
|
-
this.
|
|
71
|
-
this.intentsClient = intentsClient ?? new MessagingIntentsClient(jsonMessaging, this.
|
|
67
|
+
this.channelHandler = channelHandler ?? new MessagingChannelHandler(jsonMessaging, window.composeui.fdc3.config.instanceId);
|
|
68
|
+
this.intentsClient = intentsClient ?? new MessagingIntentsClient(jsonMessaging, this.channelHandler);
|
|
72
69
|
this.metadataClient = metadataClient ?? new MessagingMetadataClient(jsonMessaging, window.composeui.fdc3.config);
|
|
73
70
|
this.openClient = openClient ?? new MessagingOpenClient(window.composeui.fdc3.config.instanceId!, jsonMessaging, window.composeui.fdc3.openAppIdentifier);
|
|
74
71
|
}
|
|
75
72
|
|
|
73
|
+
public async [Symbol.asyncDispose](): Promise<void> {
|
|
74
|
+
console.debug("Disposing ComposeUIDesktopAgent");
|
|
75
|
+
|
|
76
|
+
await this.channelHandler[Symbol.asyncDispose]();
|
|
77
|
+
|
|
78
|
+
for (const listener of this.intentListeners) {
|
|
79
|
+
await listener.unsubscribe();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.intentListeners = [];
|
|
83
|
+
|
|
84
|
+
for (const listener of this.topLevelContextListeners) {
|
|
85
|
+
await listener.unsubscribe();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.topLevelContextListeners = [];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// This regiters an endpoint to listen when an action was initiated from the UI to select a user channel to join to.
|
|
92
|
+
public async init(): Promise<void> {
|
|
93
|
+
await this.channelHandler.configureChannelSelectorFromUI();
|
|
94
|
+
}
|
|
95
|
+
|
|
76
96
|
public async open(app?: string | AppIdentifier, context?: Context): Promise<AppIdentifier> {
|
|
77
97
|
return await this.openClient.open(app, context);
|
|
78
98
|
}
|
|
@@ -106,7 +126,7 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
|
106
126
|
}
|
|
107
127
|
|
|
108
128
|
public async addIntentListener(intent: string, handler: IntentHandler): Promise<Listener> {
|
|
109
|
-
var listener = await this.
|
|
129
|
+
var listener = await this.channelHandler.getIntentListener(intent, handler);
|
|
110
130
|
this.intentListeners.push(listener);
|
|
111
131
|
return listener;
|
|
112
132
|
}
|
|
@@ -132,7 +152,7 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
|
132
152
|
this.openedAppContextHandled = true;
|
|
133
153
|
}
|
|
134
154
|
|
|
135
|
-
const listener = <ComposeUIContextListener>await this.
|
|
155
|
+
const listener = <ComposeUIContextListener>await this.channelHandler.getContextListener(this.openedAppContextHandled, this.currentChannel, handler, contextType);
|
|
136
156
|
this.topLevelContextListeners.push(listener);
|
|
137
157
|
|
|
138
158
|
if (!this.currentChannel) {
|
|
@@ -147,24 +167,22 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
|
147
167
|
}
|
|
148
168
|
|
|
149
169
|
public async getUserChannels(): Promise<Array<Channel>> {
|
|
150
|
-
return await this.
|
|
170
|
+
return await this.channelHandler.getUserChannels();
|
|
151
171
|
}
|
|
152
172
|
|
|
153
173
|
public async joinUserChannel(channelId: string): Promise<void> {
|
|
154
174
|
if (this.currentChannel) {
|
|
155
175
|
//DesktopAgnet clients can listen on only one channel
|
|
176
|
+
console.debug("Leaving current channel: ", this.currentChannel.id);
|
|
156
177
|
await this.leaveCurrentChannel();
|
|
157
178
|
}
|
|
158
179
|
|
|
159
|
-
let channel = this.
|
|
180
|
+
let channel = await this.channelHandler.joinUserChannel(channelId);
|
|
181
|
+
|
|
182
|
+
console.debug("Joined to user channel: ", channelId);
|
|
183
|
+
|
|
160
184
|
if (!channel) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (!channel) {
|
|
164
|
-
throw new Error(ChannelError.NoChannelFound);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
this.addChannel(channel);
|
|
185
|
+
throw new Error(ChannelError.NoChannelFound);
|
|
168
186
|
}
|
|
169
187
|
|
|
170
188
|
this.currentChannel = channel;
|
|
@@ -178,19 +196,12 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
|
178
196
|
}
|
|
179
197
|
|
|
180
198
|
public async getOrCreateChannel(channelId: string): Promise<Channel> {
|
|
181
|
-
let appChannel = this.
|
|
182
|
-
if (appChannel) {
|
|
183
|
-
return appChannel;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
appChannel = await this.channelFactory.createAppChannel(channelId);
|
|
187
|
-
|
|
188
|
-
this.addChannel(appChannel!);
|
|
199
|
+
let appChannel = await this.channelHandler.createAppChannel(channelId);
|
|
189
200
|
return appChannel!;
|
|
190
201
|
}
|
|
191
202
|
|
|
192
203
|
public async createPrivateChannel(): Promise<PrivateChannel> {
|
|
193
|
-
return await this.
|
|
204
|
+
return await this.channelHandler.createPrivateChannel();
|
|
194
205
|
}
|
|
195
206
|
|
|
196
207
|
public async getCurrentChannel(): Promise<Channel | null> {
|
|
@@ -199,11 +210,15 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
|
199
210
|
|
|
200
211
|
public async leaveCurrentChannel(): Promise<void> {
|
|
201
212
|
//The context listeners, that have been added through the `fdc3.addContextListener()` should unsubscribe
|
|
213
|
+
console.debug("Unsubscribing top level context listeners: ", this.topLevelContextListeners);
|
|
202
214
|
for (const listener of this.topLevelContextListeners) {
|
|
203
215
|
await listener.unsubscribe();
|
|
204
216
|
}
|
|
205
217
|
|
|
206
|
-
this.currentChannel
|
|
218
|
+
if (this.currentChannel) {
|
|
219
|
+
await this.channelHandler.leaveCurrentChannel();
|
|
220
|
+
this.currentChannel = undefined;
|
|
221
|
+
}
|
|
207
222
|
}
|
|
208
223
|
|
|
209
224
|
public async getInfo(): Promise<ImplementationMetadata> {
|
|
@@ -234,21 +249,6 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
|
|
|
234
249
|
}
|
|
235
250
|
}
|
|
236
251
|
|
|
237
|
-
private addChannel(channel: Channel): void {
|
|
238
|
-
if (channel == null) return;
|
|
239
|
-
switch (channel.type) {
|
|
240
|
-
case "app":
|
|
241
|
-
this.appChannels.push(channel);
|
|
242
|
-
break;
|
|
243
|
-
case "user":
|
|
244
|
-
this.userChannels.push(channel);
|
|
245
|
-
break;
|
|
246
|
-
case "private":
|
|
247
|
-
this.privateChannels.push(channel);
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
252
|
private async callHandlerOnChannelsCurrentContext(listener: ComposeUIContextListener) : Promise<void> {
|
|
253
253
|
const lastContext = await this.currentChannel!.getCurrentContext(listener.contextType);
|
|
254
254
|
|
package/src/{ComposeUIMessagingChannelFactory.spec.ts → ComposeUIMessagingChannelHandler.spec.ts}
RENAMED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect, vi } from 'vitest';
|
|
14
14
|
import { ChannelError } from '@finos/fdc3';
|
|
15
|
-
import {
|
|
15
|
+
import { MessagingChannelHandler } from './infrastructure/MessagingChannelHandler';
|
|
16
16
|
import { Fdc3JoinUserChannelResponse } from './infrastructure/messages/Fdc3JoinUserChannelResponse';
|
|
17
17
|
import { Fdc3GetUserChannelsResponse } from './infrastructure/messages/Fdc3GetUserChannelsResponse';
|
|
18
18
|
import { ComposeUIChannel } from './infrastructure/ComposeUIChannel';
|
|
@@ -30,11 +30,11 @@ const baseMessagingMock = (): IMessaging => ({
|
|
|
30
30
|
invokeService: vi.fn(() => Promise.resolve(null))
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
describe('
|
|
33
|
+
describe('MessagingChannelHandler tests', () => {
|
|
34
34
|
it('joinUserChannel rejects CreationFailed when no response', async () => {
|
|
35
35
|
const messagingMock = baseMessagingMock();
|
|
36
36
|
const jsonMessaging = new JsonMessaging(messagingMock);
|
|
37
|
-
const factory = new
|
|
37
|
+
const factory = new MessagingChannelHandler(jsonMessaging, 'localInstance');
|
|
38
38
|
await expect(factory.joinUserChannel('dummyId')).rejects.toThrow(ChannelError.CreationFailed);
|
|
39
39
|
expect(messagingMock.invokeService).toHaveBeenCalledTimes(1);
|
|
40
40
|
});
|
|
@@ -44,7 +44,7 @@ describe('MessagingChannelFactory tests', () => {
|
|
|
44
44
|
const messagingMock = baseMessagingMock();
|
|
45
45
|
messagingMock.invokeService = vi.fn(() => Promise.resolve(JSON.stringify(response)));
|
|
46
46
|
const jsonMessaging = new JsonMessaging(messagingMock);
|
|
47
|
-
const factory = new
|
|
47
|
+
const factory = new MessagingChannelHandler(jsonMessaging, 'localInstance');
|
|
48
48
|
await expect(factory.joinUserChannel('dummyId')).rejects.toThrow('testError');
|
|
49
49
|
expect(messagingMock.invokeService).toHaveBeenCalledTimes(1);
|
|
50
50
|
});
|
|
@@ -57,7 +57,7 @@ describe('MessagingChannelFactory tests', () => {
|
|
|
57
57
|
const messagingMock = baseMessagingMock();
|
|
58
58
|
messagingMock.invokeService = vi.fn(() => Promise.resolve(JSON.stringify(response)));
|
|
59
59
|
const jsonMessaging = new JsonMessaging(messagingMock);
|
|
60
|
-
const factory = new
|
|
60
|
+
const factory = new MessagingChannelHandler(jsonMessaging, 'localInstance');
|
|
61
61
|
await expect(factory.joinUserChannel('dummyId')).rejects.toThrow(ChannelError.CreationFailed);
|
|
62
62
|
expect(messagingMock.invokeService).toHaveBeenCalledTimes(1);
|
|
63
63
|
});
|
|
@@ -70,16 +70,16 @@ describe('MessagingChannelFactory tests', () => {
|
|
|
70
70
|
const messagingMock = baseMessagingMock();
|
|
71
71
|
messagingMock.invokeService = vi.fn(() => Promise.resolve(JSON.stringify(response)));
|
|
72
72
|
const jsonMessaging = new JsonMessaging(messagingMock);
|
|
73
|
-
const factory = new
|
|
73
|
+
const factory = new MessagingChannelHandler(jsonMessaging, 'localInstance');
|
|
74
74
|
const result = await factory.joinUserChannel('dummyId');
|
|
75
75
|
expect(result).toBeInstanceOf(ComposeUIChannel);
|
|
76
|
-
expect(messagingMock.invokeService).toHaveBeenCalledTimes(
|
|
76
|
+
expect(messagingMock.invokeService).toHaveBeenCalledTimes(2); //This will trigger the channel selector logic as well.
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
it('getUserChannels rejects NoChannelFound when no response', async () => {
|
|
80
80
|
const messagingMock = baseMessagingMock();
|
|
81
81
|
const jsonMessaging = new JsonMessaging(messagingMock);
|
|
82
|
-
const factory = new
|
|
82
|
+
const factory = new MessagingChannelHandler(jsonMessaging, 'localInstance');
|
|
83
83
|
await expect(factory.getUserChannels()).rejects.toThrow(ChannelError.NoChannelFound);
|
|
84
84
|
expect(messagingMock.invokeService).toHaveBeenCalledTimes(1);
|
|
85
85
|
});
|
|
@@ -89,7 +89,7 @@ describe('MessagingChannelFactory tests', () => {
|
|
|
89
89
|
const messagingMock = baseMessagingMock();
|
|
90
90
|
messagingMock.invokeService = vi.fn(() => Promise.resolve(JSON.stringify(response)));
|
|
91
91
|
const jsonMessaging = new JsonMessaging(messagingMock);
|
|
92
|
-
const factory = new
|
|
92
|
+
const factory = new MessagingChannelHandler(jsonMessaging, 'localInstance');
|
|
93
93
|
await expect(factory.getUserChannels()).rejects.toThrow('testError');
|
|
94
94
|
expect(messagingMock.invokeService).toHaveBeenCalledTimes(1);
|
|
95
95
|
});
|
|
@@ -101,7 +101,7 @@ describe('MessagingChannelFactory tests', () => {
|
|
|
101
101
|
const messagingMock = baseMessagingMock();
|
|
102
102
|
messagingMock.invokeService = vi.fn(() => Promise.resolve(JSON.stringify(response)));
|
|
103
103
|
const jsonMessaging = new JsonMessaging(messagingMock);
|
|
104
|
-
const factory = new
|
|
104
|
+
const factory = new MessagingChannelHandler(jsonMessaging, 'localInstance');
|
|
105
105
|
const result = await factory.getUserChannels();
|
|
106
106
|
expect(result).toBeDefined();
|
|
107
107
|
expect(result.length).toBe(1);
|
package/src/index.ts
CHANGED
|
@@ -39,6 +39,33 @@ async function initialize(): Promise<void> {
|
|
|
39
39
|
const openAppIdentifier: OpenAppIdentifier | undefined = window.composeui.fdc3.openAppIdentifier;
|
|
40
40
|
const messaging = window.composeui.messaging.communicator as IMessaging;
|
|
41
41
|
const fdc3 = new ComposeUIDesktopAgent(messaging);
|
|
42
|
+
await fdc3.init();
|
|
43
|
+
|
|
44
|
+
let _disposed = false;
|
|
45
|
+
|
|
46
|
+
const disposeAgent = () => {
|
|
47
|
+
if (_disposed) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_disposed = true;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const agent: ComposeUIDesktopAgent = (window.fdc3 as ComposeUIDesktopAgent) || fdc3;
|
|
55
|
+
if (agent) {
|
|
56
|
+
agent[Symbol.asyncDispose]()
|
|
57
|
+
}
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.warn("Error disposing FDC3 agent", err);
|
|
60
|
+
} finally {
|
|
61
|
+
// remove handlers after first run
|
|
62
|
+
window.removeEventListener("beforeunload", disposeAgent);
|
|
63
|
+
window.removeEventListener("unload", disposeAgent);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
window.addEventListener("beforeunload", disposeAgent);
|
|
68
|
+
window.addEventListener("unload", disposeAgent);
|
|
42
69
|
|
|
43
70
|
if (channelId) {
|
|
44
71
|
await fdc3.joinUserChannel(channelId)
|
|
@@ -47,10 +74,12 @@ async function initialize(): Promise<void> {
|
|
|
47
74
|
await fdc3.getOpenedAppContext()
|
|
48
75
|
.then(() => {
|
|
49
76
|
window.fdc3 = fdc3;
|
|
77
|
+
console.log("FDC3 initialized, handled initial context which initiates that the app was opened via `fdc3.open` and joined to channel: ", channelId, window.fdc3);
|
|
50
78
|
window.dispatchEvent(new Event("fdc3Ready"));
|
|
51
79
|
})
|
|
52
80
|
} else {
|
|
53
81
|
window.fdc3 = fdc3;
|
|
82
|
+
console.log("FDC3 initialized and joined to channel: ", channelId, window.fdc3);
|
|
54
83
|
window.dispatchEvent(new Event("fdc3Ready"));
|
|
55
84
|
}
|
|
56
85
|
});
|
|
@@ -58,10 +87,12 @@ async function initialize(): Promise<void> {
|
|
|
58
87
|
if (openAppIdentifier) {
|
|
59
88
|
await fdc3.getOpenedAppContext().then(() => {
|
|
60
89
|
window.fdc3 = fdc3;
|
|
90
|
+
console.log("FDC3 initialized, handled initial context which initiates that the app was opened via `fdc3.open`: ", window.fdc3);
|
|
61
91
|
window.dispatchEvent(new Event("fdc3Ready"));
|
|
62
92
|
})
|
|
63
93
|
} else {
|
|
64
94
|
window.fdc3 = fdc3;
|
|
95
|
+
console.log("FDC3 initialized: ", window.fdc3);
|
|
65
96
|
window.dispatchEvent(new Event("fdc3Ready"));
|
|
66
97
|
}
|
|
67
98
|
}
|
|
@@ -14,12 +14,49 @@
|
|
|
14
14
|
import { Channel, ContextHandler, IntentHandler, Listener, PrivateChannel } from "@finos/fdc3";
|
|
15
15
|
import { ChannelType } from "./ChannelType";
|
|
16
16
|
|
|
17
|
-
export interface
|
|
17
|
+
export interface ChannelHandler extends AsyncDisposable {
|
|
18
|
+
/*
|
|
19
|
+
* Gets a channel by sending a request to the backend using its ID and type
|
|
20
|
+
*/
|
|
18
21
|
getChannel(channelId: string, channelType: ChannelType): Promise<Channel>;
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* Creates a private channel by sending a request to the backend
|
|
25
|
+
*/
|
|
19
26
|
createPrivateChannel(): Promise<PrivateChannel>;
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* Creates an app channel by sending a request to the backend using its ID
|
|
30
|
+
*/
|
|
20
31
|
createAppChannel(channelId: string): Promise<Channel>;
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* Joins a user channel by sending a request to the backend using its ID
|
|
35
|
+
*/
|
|
21
36
|
joinUserChannel(channelId: string): Promise<Channel>;
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
* Gets all the user channels by sending a request to the backend
|
|
40
|
+
*/
|
|
22
41
|
getUserChannels(): Promise<Channel[]>;
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* Gets all the app channels by sending a request to the backend
|
|
45
|
+
*/
|
|
23
46
|
getIntentListener(intent: string, handler: IntentHandler): Promise<Listener>;
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* Gets a context listener by sending a request to the backend. This should reflect if the initial context sent by the fdc3.open call was handled or not.
|
|
50
|
+
*/
|
|
24
51
|
getContextListener(openHandled: boolean, channel?: Channel, handler?: ContextHandler, contextType?: string | null): Promise<Listener>;
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* Configures the channel selector to allow the user to select a channel from the UI, by registering an endpoint to listen to UI initiated actions.
|
|
55
|
+
*/
|
|
56
|
+
configureChannelSelectorFromUI(): Promise<void>;
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* Leaves the current channel by sending a request to the backend using its ID
|
|
60
|
+
*/
|
|
61
|
+
leaveCurrentChannel(): Promise<void>;
|
|
25
62
|
}
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
import { DisplayMetadata } from "@finos/fdc3";
|
|
14
14
|
import { ChannelType } from "./ChannelType";
|
|
15
15
|
|
|
16
|
+
/*
|
|
17
|
+
* Represents a channel item containing its id, type and optional display metadata
|
|
18
|
+
*/
|
|
16
19
|
export interface ChannelItem {
|
|
17
20
|
id: string;
|
|
18
21
|
type: ChannelType;
|
|
@@ -35,7 +35,7 @@ export class ComposeUIChannel implements Channel {
|
|
|
35
35
|
this.displayMetadata = displayMetadata;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
//Broadcasting on the composeui/fdc3/v2.0
|
|
38
|
+
//Broadcasting on the composeui/fdc3/v2.0/<channel>/broadcast topic
|
|
39
39
|
public async broadcast(context: Context): Promise<void> {
|
|
40
40
|
//Setting the last published context message.
|
|
41
41
|
this.lastContexts.set(context.type, context);
|
|
@@ -42,6 +42,9 @@ export class ComposeUIContextListener implements Listener {
|
|
|
42
42
|
|
|
43
43
|
public async subscribe(channelId: string, channelType: ChannelType): Promise<void> {
|
|
44
44
|
await this.registerContextListener(channelId, channelType);
|
|
45
|
+
|
|
46
|
+
console.debug("Subscribed context listener with id: ", this.id, ", to channel: ", channelId, ", of type: ", channelType, ", for context type: ", this.contextType);
|
|
47
|
+
|
|
45
48
|
const subscribeTopic = ComposeUITopic.broadcast(channelId, channelType);
|
|
46
49
|
|
|
47
50
|
this.unsubscribable = await this.jsonMessaging.subscribeJson<Context>(subscribeTopic, async (context: Context) => {
|
|
@@ -54,6 +57,7 @@ export class ComposeUIContextListener implements Listener {
|
|
|
54
57
|
}
|
|
55
58
|
});
|
|
56
59
|
|
|
60
|
+
console.log("Registered context listener with id: ", this.id, ", to topic: ", subscribeTopic);
|
|
57
61
|
this.isSubscribed = true;
|
|
58
62
|
}
|
|
59
63
|
|
|
@@ -94,16 +98,18 @@ export class ComposeUIContextListener implements Listener {
|
|
|
94
98
|
|
|
95
99
|
public async unsubscribe(): Promise<void> {
|
|
96
100
|
if (!this.unsubscribable || !this.isSubscribed) {
|
|
101
|
+
console.debug("The current listener is not subscribed.");
|
|
97
102
|
return;
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
try {
|
|
101
106
|
await this.leaveChannel();
|
|
107
|
+
console.debug("Unsubscribed context listener with id: ", this.id);
|
|
102
108
|
} catch(err) {
|
|
103
109
|
console.log(err);
|
|
104
110
|
}
|
|
105
111
|
|
|
106
|
-
this.unsubscribable.unsubscribe();
|
|
112
|
+
await this.unsubscribable.unsubscribe();
|
|
107
113
|
this.isSubscribed = false;
|
|
108
114
|
|
|
109
115
|
if (this.unsubscribeCallback) {
|
|
@@ -129,6 +135,7 @@ export class ComposeUIContextListener implements Listener {
|
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
private async leaveChannel() : Promise<void> {
|
|
138
|
+
console.debug("Removing context listener with id: ", this.id);
|
|
132
139
|
const request = new Fdc3RemoveContextListenerRequest(window.composeui.fdc3.config?.instanceId!, this.id!, this.contextType);
|
|
133
140
|
const response = await this.jsonMessaging.invokeJsonService<Fdc3RemoveContextListenerRequest, Fdc3RemoveContextListenerResponse>(ComposeUITopic.removeContextListener(), request);
|
|
134
141
|
if (!response) {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { AppMetadata, IntentResolution, IntentResult } from "@finos/fdc3";
|
|
14
14
|
import { JsonMessaging } from "@morgan-stanley/composeui-messaging-abstractions";
|
|
15
|
-
import {
|
|
15
|
+
import { ChannelHandler } from "./ChannelHandler";
|
|
16
16
|
import { ComposeUIErrors } from "./ComposeUIErrors";
|
|
17
17
|
import { ComposeUITopic } from "./ComposeUITopic";
|
|
18
18
|
import { Fdc3GetIntentResultRequest } from "./messages/Fdc3GetIntentResultRequest";
|
|
@@ -20,18 +20,18 @@ import { Fdc3GetIntentResultResponse } from "./messages/Fdc3GetIntentResultRespo
|
|
|
20
20
|
|
|
21
21
|
export class ComposeUIIntentResolution implements IntentResolution {
|
|
22
22
|
private jsonMessaging: JsonMessaging;
|
|
23
|
-
private
|
|
23
|
+
private channelHandler: ChannelHandler;
|
|
24
24
|
public source: AppMetadata;
|
|
25
25
|
public intent: string
|
|
26
26
|
public messageId: string;
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
constructor(messageId: string, jsonMessaging: JsonMessaging,
|
|
29
|
+
constructor(messageId: string, jsonMessaging: JsonMessaging, channelHandler: ChannelHandler, intent: string, source: AppMetadata) {
|
|
30
30
|
this.messageId = messageId;
|
|
31
31
|
this.intent = intent;
|
|
32
32
|
this.source = source;
|
|
33
33
|
this.jsonMessaging = jsonMessaging;
|
|
34
|
-
this.
|
|
34
|
+
this.channelHandler = channelHandler;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async getResult(): Promise<IntentResult> {
|
|
@@ -47,7 +47,7 @@ export class ComposeUIIntentResolution implements IntentResolution {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (result.channelId && result.channelType) {
|
|
50
|
-
const channel = this.
|
|
50
|
+
const channel = this.channelHandler.getChannel(result.channelId, result.channelType)
|
|
51
51
|
return channel;
|
|
52
52
|
} else if (result.context) {
|
|
53
53
|
return result.context;
|
|
@@ -107,6 +107,14 @@ export class ComposeUITopic {
|
|
|
107
107
|
return `${this.topicRoot}/${this.joinUserChannelSuffix}`;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
public static channelSelectorFromUI(instanceId: string): string {
|
|
111
|
+
return `${this.topicRoot}/channelSelector/UI/${instanceId}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public static channelSelectorFromAPI(instanceId: string): string {
|
|
115
|
+
return `${this.topicRoot}/channelSelector/API/${instanceId}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
110
118
|
public static getInfo(): string {
|
|
111
119
|
return `${this.topicRoot}/${this.getInfoSuffix}`;
|
|
112
120
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { ChannelError, ContextHandler, IntentHandler, Listener, PrivateChannel } from "@finos/fdc3";
|
|
15
15
|
import { JsonMessaging } from "@morgan-stanley/composeui-messaging-abstractions";
|
|
16
16
|
import { Channel } from "@finos/fdc3";
|
|
17
|
-
import {
|
|
17
|
+
import { ChannelHandler } from "./ChannelHandler";
|
|
18
18
|
import { ComposeUIPrivateChannel } from "./ComposeUIPrivateChannel";
|
|
19
19
|
import { Fdc3CreatePrivateChannelRequest } from "./messages/Fdc3CreatePrivateChannelRequest";
|
|
20
20
|
import { Fdc3CreatePrivateChannelResponse } from "./messages/Fdc3CreatePrivateChannelResponse";
|
|
@@ -38,14 +38,26 @@ import { Fdc3JoinUserChannelResponse } from "./messages/Fdc3JoinUserChannelRespo
|
|
|
38
38
|
import { ChannelItem } from "./ChannelItem";
|
|
39
39
|
import { ComposeUIContextListener } from "./ComposeUIContextListener";
|
|
40
40
|
|
|
41
|
-
export class
|
|
41
|
+
export class MessagingChannelHandler implements ChannelHandler {
|
|
42
42
|
private jsonMessaging: JsonMessaging;
|
|
43
43
|
private fdc3instanceId: string;
|
|
44
|
+
private channelSelector: AsyncDisposable | undefined = undefined;
|
|
44
45
|
|
|
45
46
|
constructor(jsonMessaging: JsonMessaging,fdc3instanceId: string) {
|
|
46
47
|
this.jsonMessaging = jsonMessaging;
|
|
47
48
|
this.fdc3instanceId = fdc3instanceId;
|
|
48
49
|
}
|
|
50
|
+
|
|
51
|
+
[Symbol.asyncDispose](): PromiseLike<void> {
|
|
52
|
+
return this.channelSelector
|
|
53
|
+
? this.channelSelector[Symbol.asyncDispose]()
|
|
54
|
+
: Promise.resolve();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public async configureChannelSelectorFromUI(): Promise<void> {
|
|
58
|
+
this.channelSelector = await this.jsonMessaging.registerService(ComposeUITopic.channelSelectorFromUI(this.fdc3instanceId), this.selectUserChannelFromUIHandler);
|
|
59
|
+
console.debug("Configured channel selector for module: ", this.fdc3instanceId);
|
|
60
|
+
}
|
|
49
61
|
|
|
50
62
|
public async getChannel(channelId: string, channelType: ChannelType): Promise<Channel> {
|
|
51
63
|
const topic = ComposeUITopic.findChannel();
|
|
@@ -117,24 +129,43 @@ export class MessagingChannelFactory implements ChannelFactory {
|
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
public async joinUserChannel(channelId: string): Promise<Channel> {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
132
|
+
try {
|
|
133
|
+
const topic: string = ComposeUITopic.joinUserChannel();
|
|
134
|
+
const request: Fdc3JoinUserChannelRequest = new Fdc3JoinUserChannelRequest(channelId, this.fdc3instanceId);
|
|
135
|
+
const response = await this.jsonMessaging.invokeJsonService<Fdc3JoinUserChannelRequest, Fdc3JoinUserChannelResponse>(topic, request);
|
|
123
136
|
|
|
124
|
-
|
|
125
|
-
throw new Error(ChannelError.CreationFailed);
|
|
126
|
-
}
|
|
137
|
+
console.debug("Received joinUserChannel response: ", response);
|
|
127
138
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
if (!response) {
|
|
140
|
+
throw new Error(ChannelError.CreationFailed);
|
|
141
|
+
}
|
|
131
142
|
|
|
132
|
-
|
|
133
|
-
|
|
143
|
+
if (response.error) {
|
|
144
|
+
throw new Error(response.error);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!response.success) {
|
|
148
|
+
throw new Error(ChannelError.CreationFailed);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
var channel = new ComposeUIChannel(channelId, "user", this.jsonMessaging, response.displayMetadata);
|
|
152
|
+
|
|
153
|
+
this.triggerChannelJoinedEvent(channel.id);
|
|
154
|
+
|
|
155
|
+
return channel;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error("Error joining user channel: ", error);
|
|
158
|
+
throw error;
|
|
134
159
|
}
|
|
160
|
+
}
|
|
135
161
|
|
|
136
|
-
|
|
137
|
-
|
|
162
|
+
private async triggerChannelJoinedEvent(id: string | undefined) : Promise<void> {
|
|
163
|
+
try {
|
|
164
|
+
var result = await this.jsonMessaging.invokeService(ComposeUITopic.channelSelectorFromAPI(this.fdc3instanceId), id);
|
|
165
|
+
console.debug("Triggered channel selector of container: ", this.fdc3instanceId, ", with: ", id, ", and got result:", result);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error("Error triggering channel joined event for module: ", this.fdc3instanceId, ", with channel id: ", id, ", error: ", error);
|
|
168
|
+
}
|
|
138
169
|
}
|
|
139
170
|
|
|
140
171
|
public async getUserChannels(): Promise<Channel[]> {
|
|
@@ -193,4 +224,36 @@ export class MessagingChannelFactory implements ChannelFactory {
|
|
|
193
224
|
const listener = new ComposeUIContextListener(openHandled, this.jsonMessaging, handler!, contextType ?? undefined);
|
|
194
225
|
return listener;
|
|
195
226
|
}
|
|
227
|
+
|
|
228
|
+
public async leaveCurrentChannel(): Promise<void> {
|
|
229
|
+
await this.triggerChannelJoinedEvent(undefined);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private async selectUserChannelFromUIHandler(request?: string | null | undefined): Promise<string | null> {
|
|
233
|
+
try {
|
|
234
|
+
if (!request) {
|
|
235
|
+
console.debug("Empty request received when the user channel selection was requested from UI.");
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
var objectRequest = JSON.parse(request);
|
|
240
|
+
var joinUserChannelRequest = objectRequest as Fdc3JoinUserChannelRequest;
|
|
241
|
+
console.debug("Parsed the request from the UI when user selected a user channel to join: ", joinUserChannelRequest);
|
|
242
|
+
|
|
243
|
+
if (!joinUserChannelRequest || !joinUserChannelRequest.channelId) {
|
|
244
|
+
console.debug("Invalid request received when user selected a user channel to join to from the UI: ", request);
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
//We should join the channel requested by the user from the UI. -> this will trigger the handler of the module/container to show which channel the app is joined to.
|
|
249
|
+
await window.fdc3.joinUserChannel(joinUserChannelRequest.channelId);
|
|
250
|
+
|
|
251
|
+
return joinUserChannelRequest.channelId;
|
|
252
|
+
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.error("Error processing request when channel selector was invoked: ", request, ", error: ", error);
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
196
258
|
}
|
|
259
|
+
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { AppIdentifier, AppIntent, AppMetadata, Context, IntentResolution } from "@finos/fdc3";
|
|
15
15
|
import { JsonMessaging } from "@morgan-stanley/composeui-messaging-abstractions";
|
|
16
|
-
import {
|
|
16
|
+
import { ChannelHandler } from "./ChannelHandler";
|
|
17
17
|
import { ComposeUIErrors } from "./ComposeUIErrors";
|
|
18
18
|
import { ComposeUIIntentResolution } from "./ComposeUIIntentResolution";
|
|
19
19
|
import { ComposeUITopic } from "./ComposeUITopic";
|
|
@@ -27,15 +27,15 @@ import { Fdc3RaiseIntentResponse } from "./messages/Fdc3RaiseIntentResponse";
|
|
|
27
27
|
import { Fdc3RaiseIntentForContextRequest } from "./messages/Fdc3RaiseIntentForContextRequest";
|
|
28
28
|
|
|
29
29
|
export class MessagingIntentsClient implements IntentsClient {
|
|
30
|
-
private
|
|
30
|
+
private channelHandler: ChannelHandler;
|
|
31
31
|
private jsonMessaging: JsonMessaging;
|
|
32
32
|
|
|
33
|
-
constructor( jsonMessaging: JsonMessaging, channelFactory:
|
|
33
|
+
constructor( jsonMessaging: JsonMessaging, channelFactory: ChannelHandler, ) {
|
|
34
34
|
if (!window.composeui.fdc3.config || !window.composeui.fdc3.config.instanceId) {
|
|
35
35
|
throw new Error(ComposeUIErrors.InstanceIdNotFound);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
this.
|
|
38
|
+
this.channelHandler = channelFactory;
|
|
39
39
|
this.jsonMessaging = jsonMessaging;
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -69,7 +69,7 @@ export class MessagingIntentsClient implements IntentsClient {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
public async getIntentResolution(messageId: string, intent: string, source: AppMetadata): Promise<IntentResolution> {
|
|
72
|
-
return new ComposeUIIntentResolution(messageId, this.jsonMessaging, this.
|
|
72
|
+
return new ComposeUIIntentResolution(messageId, this.jsonMessaging, this.channelHandler, intent, source);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
public async raiseIntent(intent: string, context: Context, app?: string | AppIdentifier): Promise<IntentResolution> {
|
|
@@ -88,7 +88,7 @@ export class MessagingIntentsClient implements IntentsClient {
|
|
|
88
88
|
throw new Error(response.error);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const intentResolution = new ComposeUIIntentResolution(response.messageId, this.jsonMessaging, this.
|
|
91
|
+
const intentResolution = new ComposeUIIntentResolution(response.messageId, this.jsonMessaging, this.channelHandler, response.intent!, response.appMetadata!);
|
|
92
92
|
return intentResolution;
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -113,7 +113,7 @@ export class MessagingIntentsClient implements IntentsClient {
|
|
|
113
113
|
throw new Error(response.error);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
const intentResolution = new ComposeUIIntentResolution(response.messageId!, this.jsonMessaging, this.
|
|
116
|
+
const intentResolution = new ComposeUIIntentResolution(response.messageId!, this.jsonMessaging, this.channelHandler, response.intent!, response.appMetadata!);
|
|
117
117
|
return intentResolution;
|
|
118
118
|
}
|
|
119
119
|
}
|