goblin-desktop 2.0.21 → 2.0.24

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.
Files changed (143) hide show
  1. package/.editorconfig +9 -9
  2. package/.eslintrc.js +28 -28
  3. package/.zou-flow +3 -3
  4. package/README.md +108 -108
  5. package/builders/builders.js +3 -3
  6. package/builders/wizard.js +457 -457
  7. package/contexts.js +13 -13
  8. package/desktop-manager.js +10 -10
  9. package/desktop-window.js +13 -13
  10. package/desktop.js +13 -13
  11. package/lib/service.js +137 -137
  12. package/package.json +36 -36
  13. package/password-wizard.js +13 -13
  14. package/quest-run-wizard.js +13 -13
  15. package/taskbar.js +13 -13
  16. package/widgets/audio/sfx.js +177 -177
  17. package/widgets/board/view.js +37 -37
  18. package/widgets/board/widget.js +65 -65
  19. package/widgets/contexts/logic-handlers.js +36 -36
  20. package/widgets/contexts/service.js +40 -40
  21. package/widgets/contexts/view.js +22 -22
  22. package/widgets/contexts/widget.js +147 -147
  23. package/widgets/datagrid/datagrid-entity.js +82 -82
  24. package/widgets/datagrid/datagrid-headers.js +272 -272
  25. package/widgets/datagrid/styles.js +13 -13
  26. package/widgets/datagrid/widget.js +192 -192
  27. package/widgets/datagrid-cell/styles.js +52 -52
  28. package/widgets/datagrid-cell/widget.js +41 -41
  29. package/widgets/datagrid-item/styles.js +15 -15
  30. package/widgets/datagrid-item/widget.js +74 -74
  31. package/widgets/default/view.js +95 -91
  32. package/widgets/desktop/compensator.js +9 -9
  33. package/widgets/desktop/logic-handlers.js +237 -237
  34. package/widgets/desktop/reducer.js +35 -35
  35. package/widgets/desktop/service.js +828 -828
  36. package/widgets/desktop/styles.js +28 -28
  37. package/widgets/desktop/widget.js +175 -175
  38. package/widgets/desktop-clock/styles.js +69 -69
  39. package/widgets/desktop-clock/widget.js +387 -387
  40. package/widgets/desktop-clock-clock/styles.js +56 -56
  41. package/widgets/desktop-clock-clock/widget.js +96 -96
  42. package/widgets/desktop-clock-menu/styles.js +129 -129
  43. package/widgets/desktop-clock-menu/widget.js +63 -63
  44. package/widgets/desktop-connection-status/reducer.js +15 -15
  45. package/widgets/desktop-connection-status/styles.js +44 -44
  46. package/widgets/desktop-connection-status/widget.js +129 -129
  47. package/widgets/desktop-content/widget.js +68 -68
  48. package/widgets/desktop-footer/reducer.js +31 -31
  49. package/widgets/desktop-footer/styles.js +36 -36
  50. package/widgets/desktop-footer/widget.js +52 -52
  51. package/widgets/desktop-monitors/styles.js +155 -155
  52. package/widgets/desktop-monitors/widget.js +272 -272
  53. package/widgets/desktop-notebook/styles.js +155 -155
  54. package/widgets/desktop-notebook/widget.js +252 -252
  55. package/widgets/desktop-notifications/styles.js +147 -147
  56. package/widgets/desktop-notifications/widget.js +231 -231
  57. package/widgets/desktop-scale/reducer.js +15 -15
  58. package/widgets/desktop-scale/styles.js +48 -48
  59. package/widgets/desktop-scale/widget.js +172 -172
  60. package/widgets/desktop-state-monitor/styles.js +72 -72
  61. package/widgets/desktop-state-monitor/widget.js +123 -123
  62. package/widgets/desktop-taskbar/widget.js +57 -57
  63. package/widgets/desktop-themes-menu/widget.js +121 -121
  64. package/widgets/desktop-topbar/widget.js +201 -201
  65. package/widgets/desktop-window/service.js +56 -56
  66. package/widgets/desktop-window/styles.js +22 -22
  67. package/widgets/desktop-window/widget.js +70 -70
  68. package/widgets/detail/compensator.js +17 -17
  69. package/widgets/detail/view.js +40 -40
  70. package/widgets/detail/widget.js +125 -125
  71. package/widgets/editor/widget.js +84 -80
  72. package/widgets/entity-alerts/styles.js +77 -77
  73. package/widgets/entity-alerts/widget.js +328 -328
  74. package/widgets/entity-list/styles.js +66 -66
  75. package/widgets/entity-list/view.js +36 -36
  76. package/widgets/entity-list/widget.js +209 -209
  77. package/widgets/entity-list-item/widget.js +68 -68
  78. package/widgets/entity-row/styles.js +105 -105
  79. package/widgets/entity-row/widget.js +524 -524
  80. package/widgets/entity-row-button/styles.js +46 -46
  81. package/widgets/entity-row-button/widget.js +57 -57
  82. package/widgets/entity-view/reducer.js +20 -20
  83. package/widgets/entity-view/styles.js +90 -90
  84. package/widgets/entity-view/widget.js +516 -516
  85. package/widgets/facet-checkbox/styles.js +17 -17
  86. package/widgets/facet-checkbox/widget.js +43 -43
  87. package/widgets/facet-filter/widget.js +94 -94
  88. package/widgets/facet-filter-add/styles.js +30 -30
  89. package/widgets/facet-filter-add/widget.js +105 -105
  90. package/widgets/facet-filter-button/styles.js +74 -74
  91. package/widgets/facet-filter-button/widget.js +214 -214
  92. package/widgets/facet-filter-list-dialog/styles.js +59 -59
  93. package/widgets/facet-filter-list-dialog/widget.js +253 -253
  94. package/widgets/facet-filter-list-dialog-footer/styles.js +22 -22
  95. package/widgets/facet-filter-list-dialog-footer/widget.js +105 -105
  96. package/widgets/facet-filter-range-dialog/styles.js +82 -82
  97. package/widgets/facet-filter-range-dialog/widget.js +399 -399
  98. package/widgets/facet-filter-range-dialog-footer/styles.js +22 -22
  99. package/widgets/facet-filter-range-dialog-footer/widget.js +182 -182
  100. package/widgets/gamepad/widget.js +75 -75
  101. package/widgets/helpers/facet-helpers.js +105 -105
  102. package/widgets/hinter/reducer.js +35 -35
  103. package/widgets/hinter/styles.js +79 -79
  104. package/widgets/hinter/view.js +31 -31
  105. package/widgets/hinter/widget.js +291 -291
  106. package/widgets/junction/styles.js +22 -22
  107. package/widgets/junction/widget.js +50 -50
  108. package/widgets/main-tab-menu/styles.js +17 -17
  109. package/widgets/main-tab-menu/widget.js +136 -136
  110. package/widgets/map/view.js +49 -49
  111. package/widgets/map/widget.js +65 -65
  112. package/widgets/monitor/reducer.js +15 -15
  113. package/widgets/monitor/widget.js +66 -66
  114. package/widgets/navigating-layer/widget.js +25 -25
  115. package/widgets/notifications-button/widget.js +44 -44
  116. package/widgets/password-wizard/service.js +53 -53
  117. package/widgets/password-wizard/ui.js +66 -66
  118. package/widgets/plugin/reducer.js +19 -19
  119. package/widgets/plugin/styles.js +294 -294
  120. package/widgets/plugin/widget.js +637 -636
  121. package/widgets/quest-run-wizard/service.js +49 -49
  122. package/widgets/quest-run-wizard/ui.js +25 -25
  123. package/widgets/search/styles.js +80 -80
  124. package/widgets/search/widget.js +285 -285
  125. package/widgets/simple/view.js +29 -29
  126. package/widgets/status-filters/widget.js +121 -121
  127. package/widgets/tab/styles.js +16 -16
  128. package/widgets/tab/widget.js +89 -89
  129. package/widgets/tab-content/widget.js +35 -35
  130. package/widgets/tabs/widget.js +48 -48
  131. package/widgets/taskbar/service.js +99 -99
  132. package/widgets/taskbar/view.js +24 -24
  133. package/widgets/taskbar/widget.js +167 -167
  134. package/widgets/widget-doc-caller/reducer.js +15 -15
  135. package/widgets/widget-doc-caller/styles.js +20 -20
  136. package/widgets/widget-doc-caller/widget.js +55 -55
  137. package/widgets/wizard/widget.js +299 -299
  138. package/widgets/wizard-buttons/widget.js +111 -107
  139. package/widgets/workitem/styles.js +281 -281
  140. package/widgets/workitem/view.js +62 -62
  141. package/widgets/workitem/widget.js +971 -971
  142. package/widgets/workitem-dialog/widget.js +86 -86
  143. package/widgets/workitem-fields/widget.js +63 -63
@@ -1,828 +1,828 @@
1
- 'use strict';
2
-
3
- const path = require('path');
4
- const Goblin = require('xcraft-core-goblin');
5
- const watt = require('gigawatts');
6
- const goblinName = path.basename(module.parent.filename, '.js');
7
- const StringBuilder = require('goblin-nabu/lib/string-builder.js');
8
- const xUtils = require('xcraft-core-utils');
9
- const {getFileFilter} = xUtils.files;
10
- const {locks} = require('xcraft-core-utils');
11
- const desktopLock = locks.getMutex;
12
- // Define initial logic values
13
- const logicState = {};
14
-
15
- // Define logic handlers according rc.json
16
- const logicHandlers = require('./logic-handlers.js');
17
- /******************************************************************************/
18
-
19
- // Register quest's according rc.json
20
- Goblin.registerQuest(goblinName, 'create', function* (
21
- quest,
22
- clientSessionId,
23
- labId,
24
- username,
25
- session,
26
- configuration,
27
- routes,
28
- mainGoblin
29
- ) {
30
- if (clientSessionId) {
31
- quest.goblin.setX('clientSessionId', clientSessionId);
32
- } else {
33
- quest.log.warn('no clientSessionId provided to the new desktop');
34
- }
35
- quest.goblin.setX('labId', labId);
36
- quest.goblin.setX('configuration', configuration);
37
- // CREATE DEFAULT CONTEXT MANAGER
38
- yield quest.create('contexts', {
39
- id: `contexts@${quest.goblin.id}`,
40
- desktopId: quest.goblin.id,
41
- });
42
-
43
- //CREATE TASKBAR (TASK LAUNCHER)
44
- quest.create('taskbar', {
45
- id: `taskbar@${quest.goblin.id}`,
46
- desktopId: quest.goblin.id,
47
- });
48
-
49
- if (!mainGoblin && configuration) {
50
- mainGoblin = configuration.mainGoblin;
51
- }
52
-
53
- if (mainGoblin) {
54
- let useNabu = mainGoblin === 'nabu';
55
-
56
- if (!useNabu) {
57
- const mainConfig = require('xcraft-core-etc')().load(
58
- `goblin-${mainGoblin}`
59
- );
60
- useNabu = mainConfig.profile && mainConfig.profile.useNabu;
61
- }
62
-
63
- // CREATE NABU TOOLBAR IF NEEDED
64
- if (useNabu) {
65
- const toolbarId = `nabu-toolbar@${quest.goblin.id}`;
66
- yield quest.create('nabu-toolbar', {
67
- id: toolbarId,
68
- desktopId: quest.goblin.id,
69
- enabled: false,
70
- show: true,
71
- });
72
- }
73
- }
74
-
75
- quest.do({
76
- id: quest.goblin.id,
77
- username,
78
- session,
79
- profileKey: configuration && configuration.id,
80
- });
81
-
82
- quest.log.info(`Desktop ${quest.goblin.id} created!`);
83
- const id = quest.goblin.id;
84
-
85
- quest.goblin.defer(
86
- quest.sub(
87
- `*::*.${quest.goblin.id.split('@')[1]}.desktop-notification-broadcasted`,
88
- function* (err, {msg, resp}) {
89
- yield resp.cmd(`${goblinName}.add-notification`, {id, ...msg.data});
90
- }
91
- )
92
- );
93
-
94
- quest.goblin.defer(
95
- quest.sub(`*::*.${quest.goblin.id}.<add-workitem-requested>`, function* (
96
- err,
97
- {msg, resp}
98
- ) {
99
- yield resp.cmd(`${goblinName}.add-workitem`, {id, ...msg.data});
100
- })
101
- );
102
-
103
- quest.goblin.defer(
104
- quest.sub(`*::*.${quest.goblin.id}.<remove-workitem-requested>`, function* (
105
- err,
106
- {msg, resp}
107
- ) {
108
- yield resp.cmd(`${goblinName}.removeWorkitem`, {id, ...msg.data});
109
- })
110
- );
111
-
112
- return quest.goblin.id;
113
- });
114
-
115
- /******************************************************************************/
116
-
117
- Goblin.registerQuest(goblinName, 'change-locale', function (quest, locale) {
118
- const labId = quest.goblin.getX('labId');
119
- quest.evt(`<${labId}>.user-locale-changed`, {locale});
120
- });
121
-
122
- Goblin.registerQuest(goblinName, 'setDefaultNewWorkitem', function (
123
- quest,
124
- workitem
125
- ) {
126
- quest.goblin.setX('newWorkitemDef', workitem);
127
- });
128
-
129
- Goblin.registerQuest(goblinName, 'openNewWorkitem', function* (
130
- quest,
131
- clientSessionId
132
- ) {
133
- const workitem = quest.goblin.getX('newWorkitemDef');
134
- if (!workitem) {
135
- return;
136
- }
137
- yield quest.me.addWorkitem({
138
- clientSessionId,
139
- workitem: {...workitem}, //!newref
140
- navigate: true,
141
- });
142
- });
143
- /******************************************************************************/
144
-
145
- Goblin.registerQuest(goblinName, 'removeWorkitem', function* (
146
- quest,
147
- workitemId,
148
- close,
149
- navToLastWorkitem
150
- ) {
151
- const state = quest.goblin.getState();
152
- const workitem = state.get(`workitems.${workitemId}`);
153
- if (!workitem) {
154
- quest.log.dbg(`Skipping ${workitemId} remove...`);
155
- return;
156
- }
157
-
158
- yield desktopLock.lock(workitemId);
159
- quest.defer(() => desktopLock.unlock(workitemId));
160
-
161
- yield quest.doSync({workitemId});
162
-
163
- const api = quest.getAPI(workitemId);
164
- if (api && close) {
165
- if (api.close) {
166
- yield api.close({kind: 'kill'});
167
- }
168
- }
169
-
170
- yield quest.kill([workitemId]);
171
-
172
- const kind = workitem.get('kind');
173
- if (navToLastWorkitem && kind !== 'dialog') {
174
- yield quest.me.navToLastWorkitem();
175
- }
176
-
177
- if (kind === 'dialog') {
178
- const contextId = workitem.get('context');
179
- quest.dispatch('setCurrentDialogByContext', {
180
- contextId,
181
- workitemId: null,
182
- });
183
- }
184
- quest.log.dbg(`Removing ${workitemId}...[DONE]`);
185
- });
186
-
187
- /******************************************************************************/
188
- const doAdd = watt(function* (
189
- quest,
190
- widgetId,
191
- clientSessionId,
192
- workitem,
193
- navigate
194
- ) {
195
- const desk = quest.me;
196
- const desktopId = desk.id;
197
-
198
- /* Manage `maxInstances` property which is useful to limit the quantity
199
- * of instances. If the `navigate` property is passed to true, then
200
- * a navigate is performed with the first entry.
201
- */
202
- if (Number.isInteger(workitem.maxInstances)) {
203
- const workitems = quest.goblin.getState().get('workitems');
204
- if (workitems) {
205
- const items = workitems.filter((v, k) =>
206
- k.startsWith(`${workitem.name}@`)
207
- );
208
-
209
- if (items.count() >= workitem.maxInstances) {
210
- const workitemId = items.keySeq().first();
211
- const workitemKind = workitems.get(workitemId).get('kind');
212
- //navigate to existing tab when possible
213
- if (navigate && workitemKind !== 'dialog') {
214
- yield desk.navToWorkitem({
215
- workitemId,
216
- });
217
- }
218
-
219
- quest.log.dbg(`Skipping ${widgetId} add`);
220
- return {
221
- desktopId,
222
- workitemId: widgetId,
223
- skipped: true,
224
- };
225
- }
226
- }
227
- }
228
-
229
- quest.dispatch('set-workitem', {
230
- id: widgetId,
231
- kind: workitem.kind,
232
- entityId: workitem.payload.entityId,
233
- context: workitem.contextId,
234
- view: workitem.view,
235
- name: workitem.name,
236
- description: workitem.description,
237
- glyph: workitem.icon,
238
- closable: true,
239
- });
240
-
241
- if (workitem.kind === 'dialog') {
242
- quest.dispatch('setCurrentDialogByContext', {
243
- contextId: workitem.contextId,
244
- workitemId: widgetId,
245
- });
246
- }
247
-
248
- if (navigate && workitem.kind !== 'dialog') {
249
- yield desk.navToWorkitem({
250
- workitemId: widgetId,
251
- });
252
- }
253
-
254
- return {
255
- desktopId,
256
- workitemId: widgetId,
257
- skipped: false,
258
- };
259
- });
260
-
261
- Goblin.registerQuest(goblinName, 'add-workitem', function* (
262
- quest,
263
- workitem,
264
- clientSessionId,
265
- navigate
266
- ) {
267
- if (!workitem.name) {
268
- throw new Error(
269
- `Cannot add workitem without a name: ${JSON.stringify(workitem)}`
270
- );
271
- }
272
-
273
- if (!workitem.payload) {
274
- workitem.payload = {};
275
- }
276
-
277
- if (workitem.newEntityType) {
278
- workitem.payload.entityId = `${workitem.newEntityType}@${quest.uuidV4()}`;
279
- }
280
-
281
- if (!workitem.id) {
282
- workitem.id = quest.uuidV4();
283
- }
284
-
285
- if (!workitem.view) {
286
- workitem.view = 'default';
287
- }
288
-
289
- if (!workitem.kind) {
290
- workitem.kind = 'tab';
291
- }
292
-
293
- if (workitem.kind === 'dialog') {
294
- workitem.maxInstances = 1;
295
- }
296
-
297
- if (!workitem.contextId) {
298
- const state = quest.goblin.getState();
299
- workitem.contextId = state.get(`current.workcontext`, null);
300
- }
301
-
302
- //Manage collision with desktopId
303
- if (workitem.payload) {
304
- if (workitem.payload.desktopId) {
305
- workitem.payload.deskId = workitem.payload.desktopId;
306
- delete workitem.payload.desktopId;
307
- }
308
- }
309
-
310
- if (!quest.user.canDo(`${workitem.name}.create`)) {
311
- return;
312
- }
313
-
314
- const desktopId = quest.goblin.id;
315
- const widgetId = `${workitem.name}${
316
- workitem.mode ? `@${workitem.mode}` : ''
317
- }@${desktopId}@${workitem.id}`;
318
-
319
- quest.log.dbg(`Adding ${widgetId}...`);
320
-
321
- yield desktopLock.lock(widgetId);
322
- quest.defer(() => desktopLock.unlock(widgetId));
323
-
324
- yield desktopLock.lock(desktopId);
325
- const res = yield doAdd(quest, widgetId, clientSessionId, workitem, navigate);
326
- desktopLock.unlock(desktopId);
327
-
328
- if (res.skipped) {
329
- quest.log.dbg(`Adding ${widgetId}...[FAILED]`);
330
- return null;
331
- } else {
332
- const workitemAPI = yield quest.create(
333
- widgetId,
334
- Object.assign(
335
- {
336
- id: widgetId,
337
- desktopId,
338
- clientSessionId,
339
- contextId: workitem.contextId,
340
- workflowId: workitem.workflowId,
341
- isDialog: workitem.kind === 'dialog',
342
- mode: workitem.mode ? workitem.mode : false,
343
- level: 1,
344
- },
345
- workitem.payload,
346
- {payload: workitem.payload}
347
- )
348
- );
349
-
350
- if (workitemAPI.waitLoaded) {
351
- yield workitemAPI.waitLoaded();
352
- }
353
- quest.log.dbg(`Adding ${widgetId}...[DONE]`);
354
- return widgetId;
355
- }
356
- });
357
-
358
- /******************************************************************************/
359
-
360
- Goblin.registerQuest(goblinName, 'add-context', function* (
361
- quest,
362
- contextId,
363
- name,
364
- scope
365
- ) {
366
- const contexts = quest.getAPI(`contexts@${quest.goblin.id}`);
367
- yield contexts.add({
368
- contextId,
369
- name,
370
- scope,
371
- });
372
- });
373
-
374
- /******************************************************************************/
375
-
376
- Goblin.registerQuest(goblinName, 'setHinter', function (quest, hinterId) {
377
- quest.do({hinterId});
378
- });
379
-
380
- Goblin.registerQuest(goblinName, 'setDetail', function (quest, hinterId) {
381
- if (!hinterId) {
382
- quest.do({detailId: null});
383
- return;
384
- }
385
- const detailId = `${hinterId.replace(`hinter`, `detail`)}`;
386
- quest.do({detailId});
387
- });
388
-
389
- /******************************************************************************/
390
-
391
- Goblin.registerQuest(goblinName, 'change-theme', function (quest, name) {
392
- quest.evt.full(`<${quest.goblin.id}>.change-theme.requested`, {
393
- name,
394
- });
395
- });
396
-
397
- /******************************************************************************/
398
-
399
- Goblin.registerQuest(goblinName, 'change-team', function (quest, teamId) {
400
- quest.do();
401
- });
402
-
403
- /******************************************************************************/
404
-
405
- Goblin.registerQuest(goblinName, 'get-current-context', function (quest) {
406
- return quest.goblin.getState().get('current.workcontext');
407
- });
408
-
409
- /******************************************************************************/
410
-
411
- Goblin.registerQuest(goblinName, 'set-nav-to-default', function* (
412
- quest,
413
- defaultContextId
414
- ) {
415
- const state = quest.goblin.getState();
416
- const currentWK = state.get('current.workcontext');
417
- if (!currentWK) {
418
- yield quest.me.navToContext({contextId: defaultContextId});
419
- }
420
- });
421
-
422
- Goblin.registerQuest(goblinName, 'navToContext', function (quest, contextId) {
423
- quest.do({contextId});
424
- });
425
-
426
- /******************************************************************************/
427
-
428
- Goblin.registerQuest(goblinName, 'navToWorkitem', function (quest, workitemId) {
429
- const state = quest.goblin.getState();
430
-
431
- const workitem = state.get(`workitems.${workitemId}`);
432
- if (!workitem) {
433
- quest.log.warn(
434
- `cancel navigate to an undefined workitem, ${workitemId} for desktop ${quest.goblin.id}`
435
- );
436
- return;
437
- }
438
-
439
- const contextId = workitem.get('context');
440
- const view = workitem.get('view');
441
-
442
- //set new current workitem
443
- quest.dispatch('setCurrentWorkitemByContext', {contextId, view, workitemId});
444
- });
445
-
446
- /******************************************************************************/
447
-
448
- Goblin.registerQuest(goblinName, 'navToLastWorkitem', function (quest) {
449
- const state = quest.goblin.getState();
450
- const currentWorkcontext = state.get('current.workcontext');
451
- const last = state.get(`last.${currentWorkcontext}`);
452
- if (!last) {
453
- return;
454
- }
455
-
456
- const workitemId = last.get('workitem');
457
-
458
- quest.dispatch('setCurrentWorkitemByContext', {
459
- contextId: currentWorkcontext,
460
- workitemId,
461
- });
462
- });
463
-
464
- /******************************************************************************/
465
-
466
- Goblin.registerQuest(goblinName, 'run-client-quest', function (
467
- quest,
468
- labId,
469
- goblinName,
470
- goblinId,
471
- questName,
472
- questArgs
473
- ) {
474
- quest.evt(`<${labId}>.run-client-quest-requested`, {
475
- desktopId: quest.goblin.id,
476
- goblinName,
477
- goblinId,
478
- questName,
479
- questArgs,
480
- });
481
- });
482
-
483
- /******************************************************************************/
484
-
485
- Goblin.registerQuest(goblinName, 'dispatch', function (quest, action) {
486
- quest.evt.full(`<${quest.goblin.id}>.dispatch.requested`, {
487
- action,
488
- });
489
- });
490
-
491
- Goblin.registerQuest(goblinName, 'start-nav', function* (quest) {
492
- const navigating = quest.goblin.getState().get('navigating');
493
- if (navigating) {
494
- return false;
495
- }
496
- yield quest.doSync();
497
- return true;
498
- });
499
-
500
- Goblin.registerQuest(goblinName, 'end-nav', function* (
501
- quest,
502
- navRequestId,
503
- route,
504
- skip
505
- ) {
506
- if (!skip) {
507
- yield quest.doSync();
508
- }
509
- if (navRequestId) {
510
- quest.evt(`${navRequestId}.done`);
511
- }
512
- });
513
-
514
- /******************************************************************************/
515
-
516
- Goblin.registerQuest(goblinName, 'gamepad-changed', function (
517
- quest,
518
- gamepad
519
- ) {});
520
-
521
- /******************************************************************************/
522
-
523
- //---------------//
524
- // Notifications //
525
- //---------------//
526
-
527
- Goblin.registerQuest(goblinName, 'add-notification', function (
528
- quest,
529
- notificationId,
530
- glyph,
531
- color,
532
- message,
533
- command,
534
- externalUrl,
535
- isDownload,
536
- broadcast
537
- ) {
538
- if (!notificationId) {
539
- notificationId = quest.uuidV4();
540
- }
541
-
542
- message = StringBuilder.combine(message);
543
-
544
- if (broadcast) {
545
- quest.evt(
546
- `${quest.goblin.id.split('@')[1]}.desktop-notification-broadcasted`,
547
- {
548
- notificationId,
549
- glyph,
550
- color,
551
- message,
552
- command,
553
- externalUrl,
554
- isDownload,
555
- }
556
- );
557
- return;
558
- }
559
-
560
- quest.do({
561
- notificationId,
562
- glyph,
563
- color,
564
- message,
565
- command,
566
- externalUrl,
567
- isDownload,
568
- });
569
- const dnd = quest.goblin.getState().get('dnd');
570
- if (!dnd) {
571
- quest.dispatch('set-notifications', {show: true});
572
- }
573
- quest.dispatch('update-not-read-count');
574
-
575
- return quest.goblin
576
- .getState()
577
- .get(`notifications.${notificationId}`, null)
578
- .toJS();
579
- });
580
-
581
- Goblin.registerQuest(goblinName, 'remove-notification', function (
582
- quest,
583
- notification
584
- ) {
585
- quest.do({notification});
586
- quest.dispatch('update-not-read-count');
587
- });
588
-
589
- Goblin.registerQuest(goblinName, 'remove-notifications', function (quest) {
590
- quest.do();
591
- quest.dispatch('update-not-read-count');
592
- });
593
-
594
- Goblin.registerQuest(goblinName, 'click-notification', function* (
595
- quest,
596
- notification
597
- ) {
598
- if (notification.command) {
599
- yield quest.cmd(notification.command, {notification});
600
- }
601
- });
602
-
603
- Goblin.registerQuest(goblinName, 'set-dnd', function (quest, show) {
604
- quest.do();
605
- });
606
-
607
- Goblin.registerQuest(goblinName, 'set-only-news', function (quest, show) {
608
- quest.do();
609
- });
610
-
611
- Goblin.registerQuest(goblinName, 'set-notifications', function (quest, show) {
612
- quest.do();
613
- if (!show) {
614
- quest.dispatch('read-all');
615
- }
616
- quest.dispatch('update-not-read-count');
617
- });
618
-
619
- /******************************************************************************/
620
-
621
- //--------------//
622
- // StateMonitor //
623
- //--------------//
624
-
625
- Goblin.registerQuest(goblinName, 'show-state-monitor', function (quest) {
626
- quest.do();
627
- });
628
-
629
- Goblin.registerQuest(goblinName, 'add-state-monitor', function (quest) {
630
- quest.do();
631
- });
632
-
633
- Goblin.registerQuest(goblinName, 'back-state-monitor', function (quest) {
634
- quest.do();
635
- });
636
-
637
- Goblin.registerQuest(goblinName, 'forward-state-monitor', function (quest) {
638
- quest.do();
639
- });
640
-
641
- /******************************************************************************/
642
-
643
- Goblin.registerQuest(goblinName, 'download-file', function (
644
- quest,
645
- filePath,
646
- openFile
647
- ) {
648
- if (quest.user) {
649
- const {sessionType, sessionId, windowId} = quest.user.getContext();
650
- const clientSessionId = `${sessionType}@${sessionId}`;
651
- const clientWindowId = windowId;
652
- const fs = require('fs');
653
- const stream = fs.createReadStream;
654
- const routingKey = require('xcraft-core-host').getRoutingKey();
655
- if (fs.existsSync(filePath)) {
656
- let file = stream(filePath);
657
- quest.evt(
658
- `<${clientSessionId}-${clientWindowId}-download-file-requested>`,
659
- {
660
- xcraftStream: file,
661
- routingKey,
662
- fileFilter: getFileFilter(filePath),
663
- defaultPath: path.basename(filePath),
664
- openFile,
665
- }
666
- );
667
- }
668
- } else {
669
- throw new Error('Cannot identifie user requesting download');
670
- }
671
- });
672
-
673
- /******************************************************************************/
674
-
675
- Goblin.registerQuest(goblinName, 'change-mandate', function (quest) {
676
- quest.evt(`mandate.changed`);
677
- });
678
-
679
- /******************************************************************************/
680
-
681
- Goblin.registerQuest(goblinName, 'change-screen', function (quest) {
682
- quest.evt(`screen.changed`);
683
- });
684
-
685
- /******************************************************************************/
686
-
687
- Goblin.registerQuest(goblinName, 'get-configuration', function (quest) {
688
- const conf = quest.goblin.getX('configuration');
689
- return conf;
690
- });
691
-
692
- /******************************************************************************/
693
-
694
- Goblin.registerQuest(goblinName, 'get-user-info', function (quest) {
695
- return quest.goblin.getState().get('username');
696
- });
697
-
698
- /******************************************************************************/
699
-
700
- Goblin.registerQuest(goblinName, 'get-lab-id', function (quest) {
701
- return quest.goblin.getX('labId');
702
- });
703
-
704
- /******************************************************************************/
705
-
706
- Goblin.registerQuest(goblinName, 'set-lab-id', function (quest, labId) {
707
- return quest.goblin.setX('labId', labId);
708
- });
709
-
710
- /******************************************************************************/
711
-
712
- Goblin.registerQuest(goblinName, 'get-client-session-id', function (quest) {
713
- return quest.goblin.getX('clientSessionId');
714
- });
715
-
716
- /******************************************************************************/
717
-
718
- Goblin.registerQuest(goblinName, 'get-workitems', function (quest) {
719
- const state = quest.goblin.getState();
720
- const wks = state.get('workitems');
721
- return wks ? wks.toJS() : {};
722
- });
723
-
724
- /******************************************************************************/
725
-
726
- Goblin.registerQuest(goblinName, 'close', function* (quest) {
727
- const deskManager = quest.getAPI('desktop-manager');
728
- yield deskManager.close({sessionDesktopId: quest.goblin.id});
729
- });
730
-
731
- Goblin.registerQuest(goblinName, 'closeCurrentTab', function* (quest) {
732
- const state = quest.goblin.getState();
733
- const context = state.get('current.workcontext');
734
- const currentWorkitem = state.get(`current.workitems.${context}`);
735
- const workitem = state.get(`workitems.${currentWorkitem}`);
736
- if (!workitem || workitem.get('kind') !== 'tab') {
737
- return;
738
- }
739
-
740
- yield quest.me.removeWorkitem({workitemId: currentWorkitem});
741
- });
742
-
743
- Goblin.registerQuest(goblinName, 'closeAllCurrentTabs', function* (quest) {
744
- const state = quest.goblin.getState();
745
- const context = state.get('current.workcontext');
746
-
747
- const toClose = [];
748
- for (const workitem of state.get(`workitems`).values()) {
749
- if (workitem.get('kind') === 'tab' && workitem.get('context') === context) {
750
- toClose.push(workitem.get('id'));
751
- }
752
- }
753
-
754
- for (const workitemId of toClose) {
755
- yield quest.me.removeWorkitem({workitemId});
756
- }
757
- });
758
-
759
- Goblin.registerQuest(goblinName, 'on-close-window', function (
760
- quest,
761
- currentUrl
762
- ) {
763
- quest.log.dbg(`${quest.goblin.id} window closing...`);
764
- });
765
-
766
- /******************************************************************************/
767
-
768
- Goblin.registerQuest(goblinName, 'open-entity-wizard', function* (quest) {
769
- yield quest.me.addWorkitem({
770
- workitem: {name: 'open-entity-wizard', kind: 'dialog'},
771
- });
772
- });
773
-
774
- /******************************************************************************/
775
-
776
- /******************************************************************************/
777
-
778
- Goblin.registerQuest(goblinName, 'save-note', function (quest, content) {
779
- quest.dispatch('set-note', {content});
780
- });
781
-
782
- /******************************************************************************/
783
-
784
- Goblin.registerQuest(goblinName, 'delete', function (quest) {
785
- quest.log.info('Deleting desktop...');
786
- });
787
-
788
- /******************************************************************************/
789
-
790
- Goblin.registerQuest(goblinName, 'toggle-monitor-feed', function* (
791
- quest,
792
- isOn
793
- ) {
794
- if (!isOn) {
795
- yield quest.warehouse.feedSubscriptionAdd({
796
- feed: quest.goblin.id,
797
- branch: 'activity-monitor',
798
- });
799
- } else {
800
- yield quest.warehouse.feedSubscriptionDel({
801
- feed: quest.goblin.id,
802
- branch: 'activity-monitor',
803
- });
804
- }
805
- });
806
-
807
- const getMetrics = function (goblin) {
808
- const metrics = {};
809
- const state = goblin.getState();
810
- const clientSession = goblin.getX('clientSessionId');
811
- const username = goblin.getState().get('username');
812
- const labels = {
813
- clientSession,
814
- username,
815
- };
816
- metrics['workitems'] = {labels, total: state.get('workitems').size};
817
- metrics['notifications'] = {labels, total: state.get('notifications').size};
818
- metrics['stateMonitorHistoryStack'] = {
819
- labels,
820
- total: state.get('stateMonitorHistory.stack').size,
821
- };
822
- return metrics;
823
- };
824
-
825
- // Create a Goblin with initial state and handlers
826
- module.exports = Goblin.configure(goblinName, logicState, logicHandlers, {
827
- getMetrics,
828
- });
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const Goblin = require('xcraft-core-goblin');
5
+ const watt = require('gigawatts');
6
+ const goblinName = path.basename(module.parent.filename, '.js');
7
+ const StringBuilder = require('goblin-nabu/lib/string-builder.js');
8
+ const xUtils = require('xcraft-core-utils');
9
+ const {getFileFilter} = xUtils.files;
10
+ const {locks} = require('xcraft-core-utils');
11
+ const desktopLock = locks.getMutex;
12
+ // Define initial logic values
13
+ const logicState = {};
14
+
15
+ // Define logic handlers according rc.json
16
+ const logicHandlers = require('./logic-handlers.js');
17
+ /******************************************************************************/
18
+
19
+ // Register quest's according rc.json
20
+ Goblin.registerQuest(goblinName, 'create', function* (
21
+ quest,
22
+ clientSessionId,
23
+ labId,
24
+ username,
25
+ session,
26
+ configuration,
27
+ routes,
28
+ mainGoblin
29
+ ) {
30
+ if (clientSessionId) {
31
+ quest.goblin.setX('clientSessionId', clientSessionId);
32
+ } else {
33
+ quest.log.warn('no clientSessionId provided to the new desktop');
34
+ }
35
+ quest.goblin.setX('labId', labId);
36
+ quest.goblin.setX('configuration', configuration);
37
+ // CREATE DEFAULT CONTEXT MANAGER
38
+ yield quest.create('contexts', {
39
+ id: `contexts@${quest.goblin.id}`,
40
+ desktopId: quest.goblin.id,
41
+ });
42
+
43
+ //CREATE TASKBAR (TASK LAUNCHER)
44
+ quest.create('taskbar', {
45
+ id: `taskbar@${quest.goblin.id}`,
46
+ desktopId: quest.goblin.id,
47
+ });
48
+
49
+ if (!mainGoblin && configuration) {
50
+ mainGoblin = configuration.mainGoblin;
51
+ }
52
+
53
+ if (mainGoblin) {
54
+ let useNabu = mainGoblin === 'nabu';
55
+
56
+ if (!useNabu) {
57
+ const mainConfig = require('xcraft-core-etc')().load(
58
+ `goblin-${mainGoblin}`
59
+ );
60
+ useNabu = mainConfig.profile && mainConfig.profile.useNabu;
61
+ }
62
+
63
+ // CREATE NABU TOOLBAR IF NEEDED
64
+ if (useNabu) {
65
+ const toolbarId = `nabu-toolbar@${quest.goblin.id}`;
66
+ yield quest.create('nabu-toolbar', {
67
+ id: toolbarId,
68
+ desktopId: quest.goblin.id,
69
+ enabled: false,
70
+ show: true,
71
+ });
72
+ }
73
+ }
74
+
75
+ quest.do({
76
+ id: quest.goblin.id,
77
+ username,
78
+ session,
79
+ profileKey: configuration && configuration.id,
80
+ });
81
+
82
+ quest.log.info(`Desktop ${quest.goblin.id} created!`);
83
+ const id = quest.goblin.id;
84
+
85
+ quest.goblin.defer(
86
+ quest.sub(
87
+ `*::*.${quest.goblin.id.split('@')[1]}.desktop-notification-broadcasted`,
88
+ function* (err, {msg, resp}) {
89
+ yield resp.cmd(`${goblinName}.add-notification`, {id, ...msg.data});
90
+ }
91
+ )
92
+ );
93
+
94
+ quest.goblin.defer(
95
+ quest.sub(`*::*.${quest.goblin.id}.<add-workitem-requested>`, function* (
96
+ err,
97
+ {msg, resp}
98
+ ) {
99
+ yield resp.cmd(`${goblinName}.add-workitem`, {id, ...msg.data});
100
+ })
101
+ );
102
+
103
+ quest.goblin.defer(
104
+ quest.sub(`*::*.${quest.goblin.id}.<remove-workitem-requested>`, function* (
105
+ err,
106
+ {msg, resp}
107
+ ) {
108
+ yield resp.cmd(`${goblinName}.removeWorkitem`, {id, ...msg.data});
109
+ })
110
+ );
111
+
112
+ return quest.goblin.id;
113
+ });
114
+
115
+ /******************************************************************************/
116
+
117
+ Goblin.registerQuest(goblinName, 'change-locale', function (quest, locale) {
118
+ const labId = quest.goblin.getX('labId');
119
+ quest.evt(`<${labId}>.user-locale-changed`, {locale});
120
+ });
121
+
122
+ Goblin.registerQuest(goblinName, 'setDefaultNewWorkitem', function (
123
+ quest,
124
+ workitem
125
+ ) {
126
+ quest.goblin.setX('newWorkitemDef', workitem);
127
+ });
128
+
129
+ Goblin.registerQuest(goblinName, 'openNewWorkitem', function* (
130
+ quest,
131
+ clientSessionId
132
+ ) {
133
+ const workitem = quest.goblin.getX('newWorkitemDef');
134
+ if (!workitem) {
135
+ return;
136
+ }
137
+ yield quest.me.addWorkitem({
138
+ clientSessionId,
139
+ workitem: {...workitem}, //!newref
140
+ navigate: true,
141
+ });
142
+ });
143
+ /******************************************************************************/
144
+
145
+ Goblin.registerQuest(goblinName, 'removeWorkitem', function* (
146
+ quest,
147
+ workitemId,
148
+ close,
149
+ navToLastWorkitem
150
+ ) {
151
+ const state = quest.goblin.getState();
152
+ const workitem = state.get(`workitems.${workitemId}`);
153
+ if (!workitem) {
154
+ quest.log.dbg(`Skipping ${workitemId} remove...`);
155
+ return;
156
+ }
157
+
158
+ yield desktopLock.lock(workitemId);
159
+ quest.defer(() => desktopLock.unlock(workitemId));
160
+
161
+ yield quest.doSync({workitemId});
162
+
163
+ const api = quest.getAPI(workitemId);
164
+ if (api && close) {
165
+ if (api.close) {
166
+ yield api.close({kind: 'kill'});
167
+ }
168
+ }
169
+
170
+ yield quest.kill([workitemId]);
171
+
172
+ const kind = workitem.get('kind');
173
+ if (navToLastWorkitem && kind !== 'dialog') {
174
+ yield quest.me.navToLastWorkitem();
175
+ }
176
+
177
+ if (kind === 'dialog') {
178
+ const contextId = workitem.get('context');
179
+ quest.dispatch('setCurrentDialogByContext', {
180
+ contextId,
181
+ workitemId: null,
182
+ });
183
+ }
184
+ quest.log.dbg(`Removing ${workitemId}...[DONE]`);
185
+ });
186
+
187
+ /******************************************************************************/
188
+ const doAdd = watt(function* (
189
+ quest,
190
+ widgetId,
191
+ clientSessionId,
192
+ workitem,
193
+ navigate
194
+ ) {
195
+ const desk = quest.me;
196
+ const desktopId = desk.id;
197
+
198
+ /* Manage `maxInstances` property which is useful to limit the quantity
199
+ * of instances. If the `navigate` property is passed to true, then
200
+ * a navigate is performed with the first entry.
201
+ */
202
+ if (Number.isInteger(workitem.maxInstances)) {
203
+ const workitems = quest.goblin.getState().get('workitems');
204
+ if (workitems) {
205
+ const items = workitems.filter((v, k) =>
206
+ k.startsWith(`${workitem.name}@`)
207
+ );
208
+
209
+ if (items.count() >= workitem.maxInstances) {
210
+ const workitemId = items.keySeq().first();
211
+ const workitemKind = workitems.get(workitemId).get('kind');
212
+ //navigate to existing tab when possible
213
+ if (navigate && workitemKind !== 'dialog') {
214
+ yield desk.navToWorkitem({
215
+ workitemId,
216
+ });
217
+ }
218
+
219
+ quest.log.dbg(`Skipping ${widgetId} add`);
220
+ return {
221
+ desktopId,
222
+ workitemId: widgetId,
223
+ skipped: true,
224
+ };
225
+ }
226
+ }
227
+ }
228
+
229
+ quest.dispatch('set-workitem', {
230
+ id: widgetId,
231
+ kind: workitem.kind,
232
+ entityId: workitem.payload.entityId,
233
+ context: workitem.contextId,
234
+ view: workitem.view,
235
+ name: workitem.name,
236
+ description: workitem.description,
237
+ glyph: workitem.icon,
238
+ closable: true,
239
+ });
240
+
241
+ if (workitem.kind === 'dialog') {
242
+ quest.dispatch('setCurrentDialogByContext', {
243
+ contextId: workitem.contextId,
244
+ workitemId: widgetId,
245
+ });
246
+ }
247
+
248
+ if (navigate && workitem.kind !== 'dialog') {
249
+ yield desk.navToWorkitem({
250
+ workitemId: widgetId,
251
+ });
252
+ }
253
+
254
+ return {
255
+ desktopId,
256
+ workitemId: widgetId,
257
+ skipped: false,
258
+ };
259
+ });
260
+
261
+ Goblin.registerQuest(goblinName, 'add-workitem', function* (
262
+ quest,
263
+ workitem,
264
+ clientSessionId,
265
+ navigate
266
+ ) {
267
+ if (!workitem.name) {
268
+ throw new Error(
269
+ `Cannot add workitem without a name: ${JSON.stringify(workitem)}`
270
+ );
271
+ }
272
+
273
+ if (!workitem.payload) {
274
+ workitem.payload = {};
275
+ }
276
+
277
+ if (workitem.newEntityType) {
278
+ workitem.payload.entityId = `${workitem.newEntityType}@${quest.uuidV4()}`;
279
+ }
280
+
281
+ if (!workitem.id) {
282
+ workitem.id = quest.uuidV4();
283
+ }
284
+
285
+ if (!workitem.view) {
286
+ workitem.view = 'default';
287
+ }
288
+
289
+ if (!workitem.kind) {
290
+ workitem.kind = 'tab';
291
+ }
292
+
293
+ if (workitem.kind === 'dialog') {
294
+ workitem.maxInstances = 1;
295
+ }
296
+
297
+ if (!workitem.contextId) {
298
+ const state = quest.goblin.getState();
299
+ workitem.contextId = state.get(`current.workcontext`, null);
300
+ }
301
+
302
+ //Manage collision with desktopId
303
+ if (workitem.payload) {
304
+ if (workitem.payload.desktopId) {
305
+ workitem.payload.deskId = workitem.payload.desktopId;
306
+ delete workitem.payload.desktopId;
307
+ }
308
+ }
309
+
310
+ if (!quest.user.canDo(`${workitem.name}.create`)) {
311
+ return;
312
+ }
313
+
314
+ const desktopId = quest.goblin.id;
315
+ const widgetId = `${workitem.name}${
316
+ workitem.mode ? `@${workitem.mode}` : ''
317
+ }@${desktopId}@${workitem.id}`;
318
+
319
+ quest.log.dbg(`Adding ${widgetId}...`);
320
+
321
+ yield desktopLock.lock(widgetId);
322
+ quest.defer(() => desktopLock.unlock(widgetId));
323
+
324
+ yield desktopLock.lock(desktopId);
325
+ const res = yield doAdd(quest, widgetId, clientSessionId, workitem, navigate);
326
+ desktopLock.unlock(desktopId);
327
+
328
+ if (res.skipped) {
329
+ quest.log.dbg(`Adding ${widgetId}...[FAILED]`);
330
+ return null;
331
+ } else {
332
+ const workitemAPI = yield quest.create(
333
+ widgetId,
334
+ Object.assign(
335
+ {
336
+ id: widgetId,
337
+ desktopId,
338
+ clientSessionId,
339
+ contextId: workitem.contextId,
340
+ workflowId: workitem.workflowId,
341
+ isDialog: workitem.kind === 'dialog',
342
+ mode: workitem.mode ? workitem.mode : false,
343
+ level: 1,
344
+ },
345
+ workitem.payload,
346
+ {payload: workitem.payload}
347
+ )
348
+ );
349
+
350
+ if (workitemAPI.waitLoaded) {
351
+ yield workitemAPI.waitLoaded();
352
+ }
353
+ quest.log.dbg(`Adding ${widgetId}...[DONE]`);
354
+ return widgetId;
355
+ }
356
+ });
357
+
358
+ /******************************************************************************/
359
+
360
+ Goblin.registerQuest(goblinName, 'add-context', function* (
361
+ quest,
362
+ contextId,
363
+ name,
364
+ scope
365
+ ) {
366
+ const contexts = quest.getAPI(`contexts@${quest.goblin.id}`);
367
+ yield contexts.add({
368
+ contextId,
369
+ name,
370
+ scope,
371
+ });
372
+ });
373
+
374
+ /******************************************************************************/
375
+
376
+ Goblin.registerQuest(goblinName, 'setHinter', function (quest, hinterId) {
377
+ quest.do({hinterId});
378
+ });
379
+
380
+ Goblin.registerQuest(goblinName, 'setDetail', function (quest, hinterId) {
381
+ if (!hinterId) {
382
+ quest.do({detailId: null});
383
+ return;
384
+ }
385
+ const detailId = `${hinterId.replace(`hinter`, `detail`)}`;
386
+ quest.do({detailId});
387
+ });
388
+
389
+ /******************************************************************************/
390
+
391
+ Goblin.registerQuest(goblinName, 'change-theme', function (quest, name) {
392
+ quest.evt.full(`<${quest.goblin.id}>.change-theme.requested`, {
393
+ name,
394
+ });
395
+ });
396
+
397
+ /******************************************************************************/
398
+
399
+ Goblin.registerQuest(goblinName, 'change-team', function (quest, teamId) {
400
+ quest.do();
401
+ });
402
+
403
+ /******************************************************************************/
404
+
405
+ Goblin.registerQuest(goblinName, 'get-current-context', function (quest) {
406
+ return quest.goblin.getState().get('current.workcontext');
407
+ });
408
+
409
+ /******************************************************************************/
410
+
411
+ Goblin.registerQuest(goblinName, 'set-nav-to-default', function* (
412
+ quest,
413
+ defaultContextId
414
+ ) {
415
+ const state = quest.goblin.getState();
416
+ const currentWK = state.get('current.workcontext');
417
+ if (!currentWK) {
418
+ yield quest.me.navToContext({contextId: defaultContextId});
419
+ }
420
+ });
421
+
422
+ Goblin.registerQuest(goblinName, 'navToContext', function (quest, contextId) {
423
+ quest.do({contextId});
424
+ });
425
+
426
+ /******************************************************************************/
427
+
428
+ Goblin.registerQuest(goblinName, 'navToWorkitem', function (quest, workitemId) {
429
+ const state = quest.goblin.getState();
430
+
431
+ const workitem = state.get(`workitems.${workitemId}`);
432
+ if (!workitem) {
433
+ quest.log.warn(
434
+ `cancel navigate to an undefined workitem, ${workitemId} for desktop ${quest.goblin.id}`
435
+ );
436
+ return;
437
+ }
438
+
439
+ const contextId = workitem.get('context');
440
+ const view = workitem.get('view');
441
+
442
+ //set new current workitem
443
+ quest.dispatch('setCurrentWorkitemByContext', {contextId, view, workitemId});
444
+ });
445
+
446
+ /******************************************************************************/
447
+
448
+ Goblin.registerQuest(goblinName, 'navToLastWorkitem', function (quest) {
449
+ const state = quest.goblin.getState();
450
+ const currentWorkcontext = state.get('current.workcontext');
451
+ const last = state.get(`last.${currentWorkcontext}`);
452
+ if (!last) {
453
+ return;
454
+ }
455
+
456
+ const workitemId = last.get('workitem');
457
+
458
+ quest.dispatch('setCurrentWorkitemByContext', {
459
+ contextId: currentWorkcontext,
460
+ workitemId,
461
+ });
462
+ });
463
+
464
+ /******************************************************************************/
465
+
466
+ Goblin.registerQuest(goblinName, 'run-client-quest', function (
467
+ quest,
468
+ labId,
469
+ goblinName,
470
+ goblinId,
471
+ questName,
472
+ questArgs
473
+ ) {
474
+ quest.evt(`<${labId}>.run-client-quest-requested`, {
475
+ desktopId: quest.goblin.id,
476
+ goblinName,
477
+ goblinId,
478
+ questName,
479
+ questArgs,
480
+ });
481
+ });
482
+
483
+ /******************************************************************************/
484
+
485
+ Goblin.registerQuest(goblinName, 'dispatch', function (quest, action) {
486
+ quest.evt.full(`<${quest.goblin.id}>.dispatch.requested`, {
487
+ action,
488
+ });
489
+ });
490
+
491
+ Goblin.registerQuest(goblinName, 'start-nav', function* (quest) {
492
+ const navigating = quest.goblin.getState().get('navigating');
493
+ if (navigating) {
494
+ return false;
495
+ }
496
+ yield quest.doSync();
497
+ return true;
498
+ });
499
+
500
+ Goblin.registerQuest(goblinName, 'end-nav', function* (
501
+ quest,
502
+ navRequestId,
503
+ route,
504
+ skip
505
+ ) {
506
+ if (!skip) {
507
+ yield quest.doSync();
508
+ }
509
+ if (navRequestId) {
510
+ quest.evt(`${navRequestId}.done`);
511
+ }
512
+ });
513
+
514
+ /******************************************************************************/
515
+
516
+ Goblin.registerQuest(goblinName, 'gamepad-changed', function (
517
+ quest,
518
+ gamepad
519
+ ) {});
520
+
521
+ /******************************************************************************/
522
+
523
+ //---------------//
524
+ // Notifications //
525
+ //---------------//
526
+
527
+ Goblin.registerQuest(goblinName, 'add-notification', function (
528
+ quest,
529
+ notificationId,
530
+ glyph,
531
+ color,
532
+ message,
533
+ command,
534
+ externalUrl,
535
+ isDownload,
536
+ broadcast
537
+ ) {
538
+ if (!notificationId) {
539
+ notificationId = quest.uuidV4();
540
+ }
541
+
542
+ message = StringBuilder.combine(message);
543
+
544
+ if (broadcast) {
545
+ quest.evt(
546
+ `${quest.goblin.id.split('@')[1]}.desktop-notification-broadcasted`,
547
+ {
548
+ notificationId,
549
+ glyph,
550
+ color,
551
+ message,
552
+ command,
553
+ externalUrl,
554
+ isDownload,
555
+ }
556
+ );
557
+ return;
558
+ }
559
+
560
+ quest.do({
561
+ notificationId,
562
+ glyph,
563
+ color,
564
+ message,
565
+ command,
566
+ externalUrl,
567
+ isDownload,
568
+ });
569
+ const dnd = quest.goblin.getState().get('dnd');
570
+ if (!dnd) {
571
+ quest.dispatch('set-notifications', {show: true});
572
+ }
573
+ quest.dispatch('update-not-read-count');
574
+
575
+ return quest.goblin
576
+ .getState()
577
+ .get(`notifications.${notificationId}`, null)
578
+ .toJS();
579
+ });
580
+
581
+ Goblin.registerQuest(goblinName, 'remove-notification', function (
582
+ quest,
583
+ notification
584
+ ) {
585
+ quest.do({notification});
586
+ quest.dispatch('update-not-read-count');
587
+ });
588
+
589
+ Goblin.registerQuest(goblinName, 'remove-notifications', function (quest) {
590
+ quest.do();
591
+ quest.dispatch('update-not-read-count');
592
+ });
593
+
594
+ Goblin.registerQuest(goblinName, 'click-notification', function* (
595
+ quest,
596
+ notification
597
+ ) {
598
+ if (notification.command) {
599
+ yield quest.cmd(notification.command, {notification});
600
+ }
601
+ });
602
+
603
+ Goblin.registerQuest(goblinName, 'set-dnd', function (quest, show) {
604
+ quest.do();
605
+ });
606
+
607
+ Goblin.registerQuest(goblinName, 'set-only-news', function (quest, show) {
608
+ quest.do();
609
+ });
610
+
611
+ Goblin.registerQuest(goblinName, 'set-notifications', function (quest, show) {
612
+ quest.do();
613
+ if (!show) {
614
+ quest.dispatch('read-all');
615
+ }
616
+ quest.dispatch('update-not-read-count');
617
+ });
618
+
619
+ /******************************************************************************/
620
+
621
+ //--------------//
622
+ // StateMonitor //
623
+ //--------------//
624
+
625
+ Goblin.registerQuest(goblinName, 'show-state-monitor', function (quest) {
626
+ quest.do();
627
+ });
628
+
629
+ Goblin.registerQuest(goblinName, 'add-state-monitor', function (quest) {
630
+ quest.do();
631
+ });
632
+
633
+ Goblin.registerQuest(goblinName, 'back-state-monitor', function (quest) {
634
+ quest.do();
635
+ });
636
+
637
+ Goblin.registerQuest(goblinName, 'forward-state-monitor', function (quest) {
638
+ quest.do();
639
+ });
640
+
641
+ /******************************************************************************/
642
+
643
+ Goblin.registerQuest(goblinName, 'download-file', function (
644
+ quest,
645
+ filePath,
646
+ openFile
647
+ ) {
648
+ if (quest.user) {
649
+ const {sessionType, sessionId, windowId} = quest.user.getContext();
650
+ const clientSessionId = `${sessionType}@${sessionId}`;
651
+ const clientWindowId = windowId;
652
+ const fs = require('fs');
653
+ const stream = fs.createReadStream;
654
+ const routingKey = require('xcraft-core-host').getRoutingKey();
655
+ if (fs.existsSync(filePath)) {
656
+ let file = stream(filePath);
657
+ quest.evt(
658
+ `<${clientSessionId}-${clientWindowId}-download-file-requested>`,
659
+ {
660
+ xcraftStream: file,
661
+ routingKey,
662
+ fileFilter: getFileFilter(filePath),
663
+ defaultPath: path.basename(filePath),
664
+ openFile,
665
+ }
666
+ );
667
+ }
668
+ } else {
669
+ throw new Error('Cannot identifie user requesting download');
670
+ }
671
+ });
672
+
673
+ /******************************************************************************/
674
+
675
+ Goblin.registerQuest(goblinName, 'change-mandate', function (quest) {
676
+ quest.evt(`mandate.changed`);
677
+ });
678
+
679
+ /******************************************************************************/
680
+
681
+ Goblin.registerQuest(goblinName, 'change-screen', function (quest) {
682
+ quest.evt(`screen.changed`);
683
+ });
684
+
685
+ /******************************************************************************/
686
+
687
+ Goblin.registerQuest(goblinName, 'get-configuration', function (quest) {
688
+ const conf = quest.goblin.getX('configuration');
689
+ return conf;
690
+ });
691
+
692
+ /******************************************************************************/
693
+
694
+ Goblin.registerQuest(goblinName, 'get-user-info', function (quest) {
695
+ return quest.goblin.getState().get('username');
696
+ });
697
+
698
+ /******************************************************************************/
699
+
700
+ Goblin.registerQuest(goblinName, 'get-lab-id', function (quest) {
701
+ return quest.goblin.getX('labId');
702
+ });
703
+
704
+ /******************************************************************************/
705
+
706
+ Goblin.registerQuest(goblinName, 'set-lab-id', function (quest, labId) {
707
+ return quest.goblin.setX('labId', labId);
708
+ });
709
+
710
+ /******************************************************************************/
711
+
712
+ Goblin.registerQuest(goblinName, 'get-client-session-id', function (quest) {
713
+ return quest.goblin.getX('clientSessionId');
714
+ });
715
+
716
+ /******************************************************************************/
717
+
718
+ Goblin.registerQuest(goblinName, 'get-workitems', function (quest) {
719
+ const state = quest.goblin.getState();
720
+ const wks = state.get('workitems');
721
+ return wks ? wks.toJS() : {};
722
+ });
723
+
724
+ /******************************************************************************/
725
+
726
+ Goblin.registerQuest(goblinName, 'close', function* (quest) {
727
+ const deskManager = quest.getAPI('desktop-manager');
728
+ yield deskManager.close({sessionDesktopId: quest.goblin.id});
729
+ });
730
+
731
+ Goblin.registerQuest(goblinName, 'closeCurrentTab', function* (quest) {
732
+ const state = quest.goblin.getState();
733
+ const context = state.get('current.workcontext');
734
+ const currentWorkitem = state.get(`current.workitems.${context}`);
735
+ const workitem = state.get(`workitems.${currentWorkitem}`);
736
+ if (!workitem || workitem.get('kind') !== 'tab') {
737
+ return;
738
+ }
739
+
740
+ yield quest.me.removeWorkitem({workitemId: currentWorkitem});
741
+ });
742
+
743
+ Goblin.registerQuest(goblinName, 'closeAllCurrentTabs', function* (quest) {
744
+ const state = quest.goblin.getState();
745
+ const context = state.get('current.workcontext');
746
+
747
+ const toClose = [];
748
+ for (const workitem of state.get(`workitems`).values()) {
749
+ if (workitem.get('kind') === 'tab' && workitem.get('context') === context) {
750
+ toClose.push(workitem.get('id'));
751
+ }
752
+ }
753
+
754
+ for (const workitemId of toClose) {
755
+ yield quest.me.removeWorkitem({workitemId});
756
+ }
757
+ });
758
+
759
+ Goblin.registerQuest(goblinName, 'on-close-window', function (
760
+ quest,
761
+ currentUrl
762
+ ) {
763
+ quest.log.dbg(`${quest.goblin.id} window closing...`);
764
+ });
765
+
766
+ /******************************************************************************/
767
+
768
+ Goblin.registerQuest(goblinName, 'open-entity-wizard', function* (quest) {
769
+ yield quest.me.addWorkitem({
770
+ workitem: {name: 'open-entity-wizard', kind: 'dialog'},
771
+ });
772
+ });
773
+
774
+ /******************************************************************************/
775
+
776
+ /******************************************************************************/
777
+
778
+ Goblin.registerQuest(goblinName, 'save-note', function (quest, content) {
779
+ quest.dispatch('set-note', {content});
780
+ });
781
+
782
+ /******************************************************************************/
783
+
784
+ Goblin.registerQuest(goblinName, 'delete', function (quest) {
785
+ quest.log.info('Deleting desktop...');
786
+ });
787
+
788
+ /******************************************************************************/
789
+
790
+ Goblin.registerQuest(goblinName, 'toggle-monitor-feed', function* (
791
+ quest,
792
+ isOn
793
+ ) {
794
+ if (!isOn) {
795
+ yield quest.warehouse.feedSubscriptionAdd({
796
+ feed: quest.goblin.id,
797
+ branch: 'activity-monitor',
798
+ });
799
+ } else {
800
+ yield quest.warehouse.feedSubscriptionDel({
801
+ feed: quest.goblin.id,
802
+ branch: 'activity-monitor',
803
+ });
804
+ }
805
+ });
806
+
807
+ const getMetrics = function (goblin) {
808
+ const metrics = {};
809
+ const state = goblin.getState();
810
+ const clientSession = goblin.getX('clientSessionId');
811
+ const username = goblin.getState().get('username');
812
+ const labels = {
813
+ clientSession,
814
+ username,
815
+ };
816
+ metrics['workitems'] = {labels, total: state.get('workitems').size};
817
+ metrics['notifications'] = {labels, total: state.get('notifications').size};
818
+ metrics['stateMonitorHistoryStack'] = {
819
+ labels,
820
+ total: state.get('stateMonitorHistory.stack').size,
821
+ };
822
+ return metrics;
823
+ };
824
+
825
+ // Create a Goblin with initial state and handlers
826
+ module.exports = Goblin.configure(goblinName, logicState, logicHandlers, {
827
+ getMetrics,
828
+ });