@hpcc-js/marshaller 2.28.7 → 2.28.9

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 (55) hide show
  1. package/LICENSE +43 -43
  2. package/dist/index.es6.js +25 -13
  3. package/dist/index.es6.js.map +1 -1
  4. package/dist/index.js +25 -13
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.min.js +2 -2
  7. package/dist/index.min.js.map +1 -1
  8. package/package.json +14 -14
  9. package/src/__package__.ts +3 -3
  10. package/src/dashy.css +239 -239
  11. package/src/dashy.ts +521 -521
  12. package/src/ddl1/DDLApi.ts +229 -229
  13. package/src/ddl1/FlyoutButton.ts +120 -120
  14. package/src/ddl1/Graph.ts +93 -93
  15. package/src/ddl1/HTML.ts +77 -77
  16. package/src/ddl1/HipieDDL.ts +2437 -2437
  17. package/src/ddl1/HipieDDLMixin.ts +380 -380
  18. package/src/ddl1/Tabbed.ts +91 -91
  19. package/src/ddl1/TargetMarshaller.ts +57 -57
  20. package/src/ddl2/PopupManager.ts +89 -89
  21. package/src/ddl2/activities/activity.ts +431 -431
  22. package/src/ddl2/activities/databomb.ts +237 -237
  23. package/src/ddl2/activities/datasource.ts +52 -52
  24. package/src/ddl2/activities/dspicker.ts +106 -106
  25. package/src/ddl2/activities/filter.ts +542 -542
  26. package/src/ddl2/activities/form.ts +153 -153
  27. package/src/ddl2/activities/groupby.ts +439 -439
  28. package/src/ddl2/activities/hipiepipeline.ts +114 -114
  29. package/src/ddl2/activities/limit.ts +49 -49
  30. package/src/ddl2/activities/logicalfile.ts +62 -62
  31. package/src/ddl2/activities/nullview.ts +12 -12
  32. package/src/ddl2/activities/project.ts +764 -764
  33. package/src/ddl2/activities/rest.ts +568 -568
  34. package/src/ddl2/activities/roxie.ts +490 -490
  35. package/src/ddl2/activities/sampledata.json +16264 -16264
  36. package/src/ddl2/activities/sort.ts +176 -176
  37. package/src/ddl2/activities/wuresult.ts +395 -395
  38. package/src/ddl2/dashboard.css +13 -13
  39. package/src/ddl2/dashboard.ts +330 -330
  40. package/src/ddl2/dashboardDockPanel.ts +123 -123
  41. package/src/ddl2/dashboardGrid.ts +202 -202
  42. package/src/ddl2/ddl.ts +410 -410
  43. package/src/ddl2/ddleditor.ts +60 -60
  44. package/src/ddl2/dsTable.ts +238 -238
  45. package/src/ddl2/dvTable.ts +31 -31
  46. package/src/ddl2/graphadapter.ts +297 -297
  47. package/src/ddl2/javascriptadapter.ts +354 -354
  48. package/src/ddl2/model/element.ts +398 -398
  49. package/src/ddl2/model/visualization.ts +351 -351
  50. package/src/ddl2/model/vizChartPanel.ts +149 -149
  51. package/src/ddl2/pipelinePanel.css +4 -4
  52. package/src/ddl2/pipelinePanel.ts +465 -465
  53. package/src/index.ts +26 -26
  54. package/types/__package__.d.ts +2 -2
  55. package/types-3.4/__package__.d.ts +2 -2
@@ -1,2437 +1,2437 @@
1
- import { Class, Database, Utility, Widget } from "@hpcc-js/common";
2
- import { MultiChart } from "@hpcc-js/composite";
3
- import { DDL1 } from "@hpcc-js/ddl-shim";
4
- import { Comms, Table } from "@hpcc-js/other";
5
- import { map as d3Map } from "d3-collection";
6
-
7
- declare const require: any;
8
-
9
- const LOADING = "...loading...";
10
- const _CHANGED = "_changed";
11
-
12
- function faCharFix(faChar) {
13
- if (faChar) {
14
- return String.fromCharCode(parseInt(faChar));
15
- }
16
- return faChar;
17
- }
18
-
19
- function hipieType2DBType(hipieType) {
20
- switch (hipieType) {
21
- case "bool":
22
- case "boolean":
23
- return "boolean";
24
- case "integer":
25
- case "float":
26
- case "double":
27
- return "number";
28
- case "date":
29
- case "time":
30
- return "time";
31
- case "geohash":
32
- return "geohash";
33
- case "dataset":
34
- return "dataset";
35
- case "visualization":
36
- return "widget";
37
- default:
38
- if (hipieType) {
39
- if (hipieType.indexOf("unsigned") === 0) {
40
- return "number";
41
- } else if (hipieType.indexOf("integer") === 0) {
42
- return "number";
43
- } else if (hipieType.indexOf("real") === 0) {
44
- return "number";
45
- } else if (hipieType.indexOf("string") === 0) {
46
- return "string";
47
- }
48
- }
49
- }
50
- if ((window as any).__hpcc_debug) {
51
- console.warn("unknown hipieType: " + hipieType);
52
- }
53
- return "string";
54
- }
55
-
56
- // Mappings ---
57
- function SourceMappings(this: any, visualization, mappings) {
58
- this.visualization = visualization;
59
- const newMappings = {};
60
- for (const key in mappings) {
61
- if (mappings[key] instanceof Array) {
62
- mappings[key].forEach(function (mapingItem, idx) {
63
- newMappings[idx === 0 ? key : key + "_" + idx] = mapingItem;
64
- });
65
- } else {
66
- newMappings[key] = mappings[key];
67
- }
68
- }
69
- this.mappings = newMappings;
70
- this.hasMappings = false;
71
- this.reverseMappings = {};
72
- this.columns = [];
73
- this.columnsIdx = {};
74
- this.columnsRHS = [];
75
- this.columnsRHSIdx = {};
76
- }
77
-
78
- SourceMappings.prototype.init = function () {
79
- for (const key in this.mappings) {
80
- this.reverseMappings[this.mappings[key]] = key;
81
- if (this.columnsIdx[key] === undefined) {
82
- this.columns.push(key);
83
- this.columnsIdx[key] = this.columns.length - 1;
84
- }
85
- this.columnsRHS[this.columnsIdx[key]] = this.mappings[key];
86
- this.columnsRHSIdx[this.mappings[key]] = this.columnsIdx[key];
87
- this.hasMappings = true;
88
- }
89
- };
90
-
91
- SourceMappings.prototype.init = function () {
92
- for (const key in this.mappings) {
93
- this.reverseMappings[this.mappings[key]] = key;
94
- if (this.columnsIdx[key] === undefined) {
95
- this.columns.push(key);
96
- this.columnsIdx[key] = this.columns.length - 1;
97
- }
98
- this.columnsRHS[this.columnsIdx[key]] = this.mappings[key];
99
- this.columnsRHSIdx[this.mappings[key]] = this.columnsIdx[key];
100
- this.hasMappings = true;
101
- }
102
- };
103
-
104
- SourceMappings.prototype.getFields = function () {
105
- if (this.visualization.fields()) {
106
- return Object.keys(this.mappings).map(key => {
107
- const field = this.visualization.field(key);
108
- if (!field) {
109
- console.warn("Unknown mapping field: " + key);
110
- }
111
- return new Database.Field(field.id())
112
- .type(field.jsType())
113
- .label(this.reverseMappings[field.id()])
114
- ;
115
- });
116
- }
117
- return null;
118
- };
119
-
120
- SourceMappings.prototype.contains = function (key) {
121
- return this.mappings[key] !== undefined;
122
- };
123
-
124
- SourceMappings.prototype.doMap = function (item) {
125
- const retVal = [];
126
- for (const key in this.mappings) {
127
- const rhsKey = this.mappings[key];
128
- try {
129
- let val = item[rhsKey];
130
- if (val === undefined) {
131
- val = item[rhsKey.toLowerCase()];
132
- }
133
- retVal[this.columnsIdx[key]] = val;
134
- } catch (e) {
135
- console.warn("Invalid Mapping: " + this.visualization.id + " [" + rhsKey + "->" + item + "]");
136
- }
137
- }
138
- return retVal;
139
- };
140
-
141
- SourceMappings.prototype.doReverseMap = function (item) {
142
- const retVal = {};
143
- for (const key in this.mappings) {
144
- const rhsKey = this.mappings[key];
145
- try {
146
- let val = item[key];
147
- if (val === undefined) {
148
- val = item[key.toLowerCase()];
149
- }
150
- retVal[rhsKey] = val;
151
- } catch (e) {
152
- console.warn("Invalid Mapping: " + this.visualization.id + " [" + key + "->" + item + "]");
153
- }
154
- }
155
- return retVal;
156
- };
157
-
158
- SourceMappings.prototype.doMapAll = function (data) {
159
- return data.hipieMappings(this.columnsRHS.map(col => {
160
- return this.visualization.field(col);
161
- }), this.visualization.dashboard.marshaller.missingDataString());
162
- };
163
-
164
- SourceMappings.prototype.getMap = function (key) {
165
- return this.mappings[key];
166
- };
167
-
168
- SourceMappings.prototype.getReverseMap = function (key) {
169
- return this.reverseMappings[key];
170
- };
171
-
172
- SourceMappings.prototype.hipieMapSortArray = function (sort) {
173
- return sort.map(sortField => {
174
- let reverse = false;
175
- if (sortField.indexOf("-") === 0) {
176
- sortField = sortField.substring(1);
177
- reverse = true;
178
- }
179
- const fieldIdx = this.columnsRHS.indexOf(sortField);
180
- if (fieldIdx < 0) {
181
- console.warn("SourceMappings.prototype.hipieMapSortArray: Invalid sort array - " + sortField);
182
- }
183
- return {
184
- idx: fieldIdx,
185
- reverse
186
- };
187
- }).filter(function (d) { return d.idx >= 0; });
188
- };
189
-
190
- function ChartMappings(this: any, visualization, mappings) {
191
- SourceMappings.call(this, visualization, mappings);
192
- this.columns = ["label", "weight"];
193
- this.columnsIdx = { label: 0, weight: 1 };
194
- this.init();
195
- }
196
- ChartMappings.prototype = Object.create(SourceMappings.prototype);
197
-
198
- function ChoroMappings(this: any, visualization, mappings) {
199
- SourceMappings.call(this, visualization, mappings);
200
- if (mappings.state) {
201
- this.columns = ["state", "weight"];
202
- this.columnsIdx = { state: 0, weight: 1 };
203
- } else if (mappings.county) {
204
- this.columns = ["county", "weight"];
205
- this.columnsIdx = { county: 0, weight: 1 };
206
- } else if (mappings.geohash) {
207
- this.columns = ["geohash", "weight"];
208
- this.columnsIdx = { geohash: 0, weight: 1 };
209
- }
210
- this.init();
211
- }
212
- ChoroMappings.prototype = Object.create(SourceMappings.prototype);
213
-
214
- function ChoroMappings2(this: any, visualization, mappings) {
215
- SourceMappings.call(this, visualization, mappings);
216
- if (mappings.state) {
217
- this.columns = ["state"];
218
- this.columnsIdx = { state: 0 };
219
- } else if (mappings.county) {
220
- this.columns = ["county"];
221
- this.columnsIdx = { county: 0 };
222
- } else if (mappings.geohash) {
223
- this.columns = ["geohash", "label"];
224
- this.columnsIdx = { geohash: 0, label: 1 };
225
- }
226
- const weightOffset = this.columns.length;
227
- if (mappings.weight instanceof Array) {
228
- mappings.weight.forEach((w, i) => {
229
- this.columns.push(w);
230
- this.columnsIdx[i === 0 ? "weight" : "weight_" + i] = i + weightOffset;
231
- });
232
- }
233
- this.init();
234
- }
235
- ChoroMappings2.prototype = Object.create(SourceMappings.prototype);
236
-
237
- function HeatMapMappings(this: any, visualization, mappings) {
238
- SourceMappings.call(this, visualization, mappings);
239
- this.columns = ["x", "y", "weight"];
240
- this.columnsIdx = { x: 0, y: 1, weight: 2 };
241
- this.init();
242
- }
243
- HeatMapMappings.prototype = Object.create(SourceMappings.prototype);
244
-
245
- function LineMappings(this: any, visualization, mappings) {
246
- const newMappings = {
247
- label: mappings.x[0]
248
- };
249
- mappings.y.forEach(function (item, idx) {
250
- newMappings[item] = item;
251
- });
252
- SourceMappings.call(this, visualization, newMappings);
253
- this.init();
254
- }
255
- LineMappings.prototype = Object.create(SourceMappings.prototype);
256
-
257
- function TableMappings(this: any, visualization, mappings) {
258
- const newMappings = {};
259
- for (const key in mappings) {
260
- mappings[key].forEach(function (mapingItem, idx) {
261
- newMappings[visualization.label[idx]] = mapingItem;
262
- });
263
- }
264
- SourceMappings.call(this, visualization, newMappings);
265
- this.init();
266
- }
267
- TableMappings.prototype = Object.create(SourceMappings.prototype);
268
-
269
- TableMappings.prototype.init = function () {
270
- this.visualization.label.forEach((label, idx) => {
271
- this.reverseMappings[this.mappings[label]] = label;
272
- this.columns.push(label);
273
- this.columnsIdx[label] = idx;
274
- this.columnsRHS[idx] = this.mappings[label];
275
- this.columnsRHSIdx[this.mappings[label]] = idx;
276
- this.hasMappings = true;
277
- });
278
- };
279
-
280
- TableMappings.prototype.doMapAll = function (data) {
281
- let retVal = SourceMappings.prototype.doMapAll.apply(this, arguments);
282
- if (retVal instanceof Array) {
283
- const columnsRHSIdx = this.visualization.source.getColumnsRHSIdx();
284
- this.visualization.fields().forEach(field => {
285
- const fieldType = field.jsType();
286
- const colIdx = columnsRHSIdx[field.id()];
287
- if (colIdx === undefined) {
288
- console.warn("Invalid Mapping: " + field.id());
289
- } else {
290
- retVal = retVal.map((row) => {
291
- let cell = row[colIdx];
292
- if (cell && cell.Row) {
293
- cell = cell.Row;
294
- }
295
- if (cell instanceof Array) {
296
- switch (fieldType) {
297
- case "dataset":
298
- const columns = [];
299
- const columnsIdx = {};
300
- const data2 = cell.map(function (row2, idx) {
301
- const retVal2 = [];
302
- retVal2.length = columns.length;
303
- for (const key in row2) {
304
- if (idx === 0) {
305
- columnsIdx[key] = columns.length;
306
- columns.push(key);
307
- }
308
- retVal2[columnsIdx[key]] = row2[key];
309
- }
310
- return retVal2;
311
- });
312
- const table = new Table()
313
- .columns(columns)
314
- .data(data2)
315
- ;
316
- row[colIdx] = table;
317
- break;
318
- case "widget":
319
- const viz = this.visualization.vizDeclarations[field.localVisualizationID()];
320
- const output = viz.source.getOutput();
321
- const db = output.db;
322
- output.setData(cell, []);
323
- const widget = viz.widget;
324
- const newWidget = new widget.constructor()
325
- .showToolbar(false)
326
- .chartType(widget.chartType())
327
- .chartTypeDefaults(widget.chartTypeDefaults())
328
- .columns(viz.source.getColumns())
329
- .data(viz.source.getData())
330
- ;
331
- output.db = db;
332
- row[colIdx] = newWidget;
333
- break;
334
- }
335
- }
336
- return row;
337
- });
338
- }
339
- });
340
- }
341
- return retVal;
342
- };
343
-
344
- function GraphMappings(this: any, visualization, mappings, link) {
345
- SourceMappings.call(this, visualization, mappings);
346
- this.icon = visualization.icon || {};
347
- this.fields = visualization.fields();
348
- this.columns = ["uid", "label", "weight", "flags"];
349
- this.columnsIdx = { uid: 0, label: 1, weight: 2, flags: 3 };
350
- this.init();
351
- this.link = link;
352
- this.linkMappings = new SourceMappings(visualization, this.link.mappings);
353
- this.linkMappings.columns = ["uid"];
354
- this.linkMappings.columnsIdx = { uid: 0, label: 1 };
355
- this.visualization = visualization;
356
- }
357
- GraphMappings.prototype = Object.create(SourceMappings.prototype);
358
-
359
- GraphMappings.prototype.calcIconInfo = function (flag, origItem, forAnnotation) {
360
- const retVal = {};
361
- function mapStruct(struct, retVal2) {
362
- if (struct) {
363
- for (const key in struct) {
364
- switch (key) {
365
- case "faChar":
366
- retVal2.faChar = faCharFix(struct.faChar);
367
- break;
368
- default:
369
- if (forAnnotation && key.indexOf("icon_") === 0) { // Backward compatability
370
- console.warn("Deprecated flag property: " + key);
371
- retVal2[key.split("icon_")[1]] = struct[key];
372
- } else {
373
- retVal2[key] = struct[key];
374
- }
375
- }
376
- }
377
- }
378
- }
379
- if (origItem && origItem[flag.fieldid] && flag.valuemappings) {
380
- const annotationInfo = flag.valuemappings[origItem[flag.fieldid]];
381
- mapStruct(annotationInfo, retVal);
382
- }
383
-
384
- for (const _key in retVal) { // jshint ignore:line
385
- return retVal;
386
- }
387
- return null;
388
- };
389
-
390
- GraphMappings.prototype.doMapAll = function (db) {
391
- const data = db.jsonObj();
392
- const context = this;
393
- const vertexMap = {};
394
- const vertices = [];
395
- const megaChart = this.visualization.widget;
396
- const graph = megaChart.chart();
397
- function getVertex(item, origItem?) {
398
- const id = "uid_" + item[0];
399
- let retVal = vertexMap[id];
400
- if (!retVal && origItem) {
401
- retVal = new graph.Vertex()
402
- .faChar((context.icon && context.icon.faChar ? faCharFix(context.icon.faChar) : "\uf128"))
403
- .text(item[1] ? item[1] : "")
404
- .data(item)
405
- ;
406
- retVal.__hpcc_uid = item[0];
407
- vertexMap[id] = retVal;
408
- vertices.push(retVal);
409
-
410
- // Icon ---
411
- const iconInfo = context.calcIconInfo(context.visualization.icon, origItem, false);
412
- if (iconInfo) {
413
- for (const key in iconInfo) {
414
- if (retVal[key]) {
415
- retVal[key](iconInfo[key]);
416
- }
417
- }
418
- }
419
-
420
- // Annotations ---
421
- const annotations = [];
422
- context.visualization.flags.forEach(function (flag) {
423
- const iconInfo2 = context.calcIconInfo(flag, origItem, true);
424
- if (iconInfo2) {
425
- annotations.push(iconInfo2);
426
- }
427
- });
428
- retVal.annotationIcons(annotations);
429
- }
430
- return retVal;
431
- }
432
- const edges = [];
433
- data.forEach(function (item) {
434
- const mappedItem = context.doMap(item);
435
- getVertex(mappedItem, item);
436
- });
437
- data.forEach(function (item) {
438
- const mappedItem = context.doMap(item);
439
- const vertex = getVertex(mappedItem, item);
440
- if (item[context.link.childfile] && item[context.link.childfile] instanceof Array) {
441
- const childItems = item[context.link.childfile];
442
- childItems.forEach(function (childItem, i) {
443
- const childMappedItem = context.linkMappings.doMap(childItem);
444
- const childVertex = getVertex(childMappedItem);
445
- if (childVertex && vertex.id() !== childVertex.id()) {
446
- const edge = new graph.Edge()
447
- .sourceVertex(vertex)
448
- .targetVertex(childVertex)
449
- .sourceMarker("circle")
450
- .targetMarker("arrow")
451
- .text(childMappedItem[1] ? childMappedItem[1] : "")
452
- .data(childMappedItem)
453
- ;
454
- const linkcolor = graph.linkcolor_default();
455
- if (linkcolor && linkcolor.fieldid) {
456
- edge.strokeColor(childItem[linkcolor.fieldid]);
457
- }
458
- const linktooltip = graph.linkcolor_default();
459
- if (linktooltip && linktooltip.fieldid) {
460
- edge.tooltip(childItem[linktooltip.fieldid]);
461
- }
462
- edges.push(edge);
463
- }
464
- });
465
- }
466
- });
467
- return { vertices, edges, merge: false };
468
- };
469
-
470
- // Viz Source ---
471
- function Source(this: any, visualization, source) {
472
- this.visualization = visualization;
473
- if (source) {
474
- this._id = source.id;
475
- this._output = source.output;
476
- this.mappings = null;
477
- if (!source.mappings) {
478
- console.warn("no mappings for:" + visualization.id + "->" + source.id);
479
- }
480
- switch (this.visualization.type) {
481
- case "LINE":
482
- this.mappings = new LineMappings(this.visualization, source.mappings);
483
- break;
484
- case "TABLE":
485
- this.mappings = new TableMappings(this.visualization, source.mappings);
486
- break;
487
- case "GRAPH":
488
- this.mappings = new GraphMappings(this.visualization, source.mappings, source.link);
489
- break;
490
- case "CHORO":
491
- if (source.mappings.weight instanceof Array && source.mappings.weight.length) {
492
- this.mappings = new ChoroMappings2(this.visualization, source.mappings);
493
- if (source.mappings.weight.length > 1) {
494
- this.visualization.type = "LINE";
495
- }
496
- } else {
497
- this.mappings = new ChoroMappings(this.visualization, source.mappings);
498
- }
499
- break;
500
- case "HEAT_MAP":
501
- this.mappings = new HeatMapMappings(this.visualization, source.mappings);
502
- break;
503
- default:
504
- this.mappings = new ChartMappings(this.visualization, source.mappings);
505
- break;
506
- }
507
- this.first = source.first;
508
- this.reverse = source.reverse;
509
- this.sort = source.sort;
510
- this.properties = source.properties;
511
- }
512
- }
513
-
514
- Source.prototype.getQualifiedID = function () {
515
- return this.visualization.getQualifiedID() + "." + this._id;
516
- };
517
-
518
- Source.prototype.exists = function () {
519
- return this._id;
520
- };
521
-
522
- Source.prototype.getDatasource = function () {
523
- return this.visualization.dashboard.getDatasource(this._id);
524
- };
525
-
526
- Source.prototype.getOutput = function () {
527
- const datasource = this.getDatasource();
528
- if (datasource && datasource._outputs) {
529
- return datasource._outputs[this._output];
530
- }
531
- return null;
532
- };
533
-
534
- Source.prototype.hasData = function () {
535
- return this.getOutput().db ? true : false;
536
- };
537
-
538
- Source.prototype.getFields = function () {
539
- return this.mappings.getFields();
540
- };
541
-
542
- Source.prototype.getColumnsRHS = function () {
543
- return this.mappings.columnsRHS;
544
- };
545
-
546
- Source.prototype.getColumnsRHSIdx = function () {
547
- return this.mappings.columnsRHSIdx;
548
- };
549
-
550
- Source.prototype.getColumns = function () {
551
- return this.mappings && this.mappings.columns ? this.mappings.columns : [];
552
- };
553
-
554
- Source.prototype.getData = function () {
555
- const db = this.getOutput().db;
556
- const retVal = this.mappings.doMapAll(db);
557
- if (retVal.length && this.sort) {
558
- Utility.multiSort(retVal, this.mappings.hipieMapSortArray(this.sort));
559
- }
560
- if (this.reverse) {
561
- retVal.reverse();
562
- }
563
- if (this.first && retVal.length > this.first) {
564
- retVal.length = this.first;
565
- }
566
- return retVal;
567
- };
568
-
569
- Source.prototype.getXTitle = function () {
570
- return this.mappings.columns[0];
571
- };
572
-
573
- Source.prototype.getYTitle = function () {
574
- return this.mappings.columns.filter(function (d, i) { return i > 0; }).join(" / ");
575
- };
576
-
577
- Source.prototype.getMap = function (col) {
578
- return (this.mappings && this.mappings.hasMappings) ? this.mappings.getMap(col) : col;
579
- };
580
-
581
- Source.prototype.getReverseMap = function (col) {
582
- return (this.mappings && this.mappings.hasMappings) ? this.mappings.getReverseMap(col) : col;
583
- };
584
-
585
- // Viz Events ---
586
- function EventUpdate(this: any, event, update, defMappings) {
587
- this.event = event;
588
- this.dashboard = event.visualization.dashboard;
589
- this._col = update.col;
590
- this._visualization = update.visualization;
591
- this._instance = update.instance;
592
- this._datasource = update.datasource;
593
- this._merge = update.merge;
594
- this._mappings = update.mappings || defMappings;
595
- }
596
-
597
- EventUpdate.prototype.getDatasource = function () {
598
- return this.dashboard.getDatasource(this._datasource);
599
- };
600
-
601
- EventUpdate.prototype.getVisualization = function () {
602
- return this.dashboard.getVisualization(this._visualization);
603
- };
604
-
605
- EventUpdate.prototype.mapData = function (row) {
606
- const retVal = {};
607
- if (row) {
608
- for (const key in this._mappings) {
609
- const origKey = this.getReverseMap(key);
610
- retVal[this._mappings[key]] = row[origKey];
611
- }
612
- }
613
- return retVal;
614
- };
615
-
616
- EventUpdate.prototype.getMap = function (col) {
617
- return this.event.visualization.source.getMap(col);
618
- };
619
-
620
- EventUpdate.prototype.getReverseMap = function (col) {
621
- return this.event.visualization.source.getReverseMap(col);
622
- };
623
-
624
- EventUpdate.prototype.selectedRow = function () {
625
- if (this.event.visualization.hasSelection()) {
626
- return this.event.visualization._widgetState.row;
627
- }
628
- return {};
629
- };
630
-
631
- EventUpdate.prototype.mapSelected = function () {
632
- return this.mapData(this.selectedRow());
633
- };
634
-
635
- EventUpdate.prototype.calcRequestFor = function (visualization) {
636
- const retVal = {};
637
- const updateVisualization = this.getVisualization();
638
- updateVisualization.getInputVisualizations().forEach(function (inViz, idx) {
639
- // Calc request for each visualization to be updated ---
640
- const changed = inViz === visualization;
641
- inViz.getUpdatesForVisualization(updateVisualization).forEach(function (inVizUpdateObj) {
642
- // Gather all contributing "input visualization events" for the visualization that is to be updated ---
643
- const inVizRequest = inVizUpdateObj.mapSelected();
644
- for (const key in inVizRequest) {
645
- if (retVal[key] && retVal[key] !== inVizRequest[key]) {
646
- console.warn("Duplicate Filter with mismatched value (defaulting to 'first' or 'first changed' instance): " + key);
647
- if (changed) {
648
- retVal[key] = inVizRequest[key];
649
- retVal[key + _CHANGED] = changed;
650
- }
651
- } else {
652
- retVal[key] = inVizRequest[key];
653
- retVal[key + _CHANGED] = changed;
654
- }
655
- }
656
- });
657
- });
658
- return retVal;
659
- };
660
-
661
- function Event(this: any, visualization, eventID, event) {
662
- this.visualization = visualization;
663
- this.eventID = eventID;
664
- this._updates = [];
665
- this._mappings = event.mappings;
666
- if (event) {
667
- this._updates = event.updates.map(updateInfo => {
668
- return new EventUpdate(this, updateInfo, event.mappings);
669
- });
670
- }
671
- }
672
-
673
- Event.prototype.exists = function () {
674
- return this._updates.length;
675
- };
676
-
677
- Event.prototype.getUpdates = function () {
678
- return this._updates.filter(updateInfo => {
679
- if (!updateInfo._col) return true;
680
- return updateInfo._col === updateInfo.getMap(this.visualization._widgetState.col);
681
- });
682
- };
683
-
684
- Event.prototype.getUpdatesDatasources = function () {
685
- const dedup = {};
686
- const retVal = [];
687
- this.getUpdatesVisualizations().forEach(function (item, idx) {
688
- const datasource = item.source.getDatasource();
689
- if (datasource && !dedup[datasource.id]) {
690
- dedup[datasource.id] = true;
691
- retVal.push(datasource);
692
- }
693
- }, this);
694
- return retVal;
695
- };
696
-
697
- Event.prototype.getUpdatesVisualizations = function () {
698
- const dedup = {};
699
- const retVal = [];
700
- this._updates.forEach(function (updateObj, idx) {
701
- const visualization = updateObj.getVisualization();
702
- if (!dedup[visualization.id]) {
703
- dedup[visualization.id] = true;
704
- retVal.push(visualization);
705
- }
706
- }, this);
707
- return retVal;
708
- };
709
-
710
- Event.prototype.fetchData = function () {
711
- const fetchDataOptimizer = new VisualizationRequestOptimizer();
712
- this.getUpdates().forEach(updateObj => {
713
- fetchDataOptimizer.appendRequest(updateObj.getDatasource(), updateObj.calcRequestFor(this.visualization), updateObj.getVisualization());
714
- });
715
- return fetchDataOptimizer.fetchData();
716
- };
717
-
718
- function Events(this: any, visualization, events) {
719
- this.visualization = visualization;
720
- this.events = {};
721
- for (const key in events) {
722
- this.events[key] = new Event(visualization, key, events[key]);
723
- }
724
- }
725
-
726
- Events.prototype.setWidget = function (widget) {
727
- const context = this;
728
- for (const key in this.events) {
729
- if (widget["vertex_" + key]) {
730
- widget["vertex_" + key] = function (row, col, selected) {
731
- context.visualization.processEvent(key, context.events[key], row, col, selected);
732
- };
733
- }
734
- if (widget[key]) {
735
- widget[key] = function (row, col, selected) {
736
- context.visualization.processEvent(key, context.events[key], row, col, selected);
737
- };
738
- }
739
- }
740
- };
741
-
742
- Events.prototype.exists = function () {
743
- return this._updates !== undefined;
744
- };
745
-
746
- Events.prototype.getUpdates = function () {
747
- let retVal = [];
748
- for (const key in this.events) {
749
- retVal = retVal.concat(this.events[key].getUpdates());
750
- }
751
- return retVal;
752
- };
753
-
754
- Events.prototype.getUpdatesDatasources = function () {
755
- let retVal = [];
756
- for (const key in this.events) {
757
- retVal = retVal.concat(this.events[key].getUpdatesDatasources());
758
- }
759
- return retVal;
760
- };
761
-
762
- Events.prototype.getUpdatesVisualizations = function () {
763
- let retVal = [];
764
- for (const key in this.events) {
765
- retVal = retVal.concat(this.events[key].getUpdatesVisualizations());
766
- }
767
- return retVal;
768
- };
769
-
770
- // Visualization Field---
771
- function Field(this: any, ddlField) {
772
- this._id = ddlField.id;
773
- this._label = ddlField.label;
774
- this._properties = ddlField.properties || {};
775
- }
776
- Field.prototype = Object.create(Class.prototype);
777
- Field.prototype.constructor = Field;
778
-
779
- Field.prototype.id = function () {
780
- return this._id;
781
- };
782
-
783
- Field.prototype.label = function () {
784
- return this._properties.label || this._label;
785
- };
786
-
787
- Field.prototype.type = function () {
788
- return this._properties.type || "";
789
- };
790
-
791
- Field.prototype.jsType = function () {
792
- return hipieType2DBType(this.type());
793
- };
794
-
795
- Field.prototype.charttype = function (_) {
796
- if (!arguments.length) return this._properties.charttype || "";
797
- this._properties.charttype = _;
798
- return this;
799
- };
800
-
801
- Field.prototype.localVisualizationID = function () {
802
- return this._properties.localVisualizationID || "";
803
- };
804
-
805
- Field.prototype.enumvals = function () {
806
- return this._properties.enumvals; // Return undefined if non existent
807
- };
808
-
809
- Field.prototype.hasDefault = function () {
810
- return this.default() !== undefined;
811
- };
812
-
813
- Field.prototype.default = function () {
814
- if (this.type() === "range") {
815
- return this._properties.default || ["", ""];
816
- }
817
- if (this._properties.default instanceof Array && this._properties.default.length) {
818
- return this._properties.default[0];
819
- }
820
- return this._properties.default || "";
821
- };
822
-
823
- Field.prototype.hasFunction = function () {
824
- return this.function() !== undefined;
825
- };
826
-
827
- Field.prototype.function = function () {
828
- return this._properties.function;
829
- };
830
-
831
- Field.prototype.params = function () {
832
- const retVal = [];
833
- const params = this._properties.params || {};
834
- for (const key in params) {
835
- retVal.push(params[key]);
836
- }
837
- return retVal;
838
- };
839
-
840
- Field.prototype.properties = function () {
841
- return this._properties;
842
- };
843
-
844
- // Visualization ---
845
- function requirePromise(this: any, packageID) {
846
- return new Promise((resolve, reject) => {
847
- if (require) {
848
- require([packageID], Package => {
849
- resolve.call(this, Package);
850
- });
851
- } else {
852
- reject("No require.");
853
- }
854
- });
855
- }
856
-
857
- function legacyRequire(this: any, packageArr, callback) {
858
- const promises = packageArr.map(function (packageID) {
859
- if (packageID.indexOf("../") === 0) {
860
- const parts = packageID.split("/");
861
- return requirePromise("@hpcc-js/" + parts[1]).then(function (Package) {
862
- return Package[parts[2]];
863
- });
864
- }
865
- return requirePromise(packageID);
866
- });
867
- Promise.all(promises).then(packages => {
868
- callback.apply(this, packages);
869
- });
870
- }
871
-
872
- export class Visualization extends Class {
873
- protected dashboard;
874
- parentVisualization;
875
- protected type;
876
- protected id;
877
- protected label;
878
- protected icon;
879
- protected flags;
880
- protected title;
881
- protected _fields;
882
- protected _fieldsMap;
883
- properties;
884
- protected source;
885
- protected events;
886
- protected layers;
887
- protected hasVizDeclarations;
888
- protected vizDeclarations;
889
- widget;
890
- protected _widgetState;
891
-
892
- constructor(dashboard, visualization, parentVisualization) {
893
- super();
894
-
895
- this.dashboard = dashboard;
896
- this.parentVisualization = parentVisualization;
897
- this.type = visualization.type;
898
- this.id = visualization.id;
899
-
900
- switch (this.type) {
901
- case "TABLE":
902
- this.label = (visualization).label;
903
- break;
904
- case "GRAPH":
905
- this.label = (visualization).label;
906
- this.icon = (visualization).icon || { faChar: "\uf128" };
907
- this.flags = (visualization).flag || [];
908
- break;
909
- }
910
- this.title = visualization.title || visualization.id;
911
- this._fields = (visualization.fields || []).map(function (field) {
912
- return new Field(field);
913
- });
914
- this._fieldsMap = {};
915
- this._fields.forEach(field => {
916
- this._fieldsMap[field.id()] = field;
917
- });
918
-
919
- this.properties = visualization.properties || (visualization.source ? visualization.source.properties : null) || {};
920
- this.source = new Source(this, visualization.source);
921
- this.events = new Events(this, visualization.events);
922
- this.layers = [];
923
- this.hasVizDeclarations = false;
924
- this.vizDeclarations = {};
925
- if (this.type === "CHORO") {
926
- this.layers = (visualization.visualizations || []).map(innerViz => {
927
- return dashboard.createVisualization(innerViz, this);
928
- });
929
- } else {
930
- (visualization.visualizations || []).forEach(innerViz => {
931
- this.vizDeclarations[innerViz.id] = dashboard.createVisualization(innerViz, this);
932
- this.hasVizDeclarations = true;
933
- });
934
- }
935
- const context = this;
936
- switch (this.type) {
937
- case "CHORO":
938
- let chartType = visualization.properties && visualization.properties.charttype ? visualization.properties.charttype : "";
939
- if (parentVisualization) {
940
- switch (chartType) {
941
- case "MAP_PINS":
942
- this.loadWidget("../map/Pins", function (widget) {
943
- try {
944
- widget
945
- .id(visualization.id)
946
- .columns(context.source.getColumns())
947
- .geohashColumn("geohash")
948
- .tooltipColumn("label")
949
- .fillColor(visualization.color ? visualization.color : null)
950
- .projection("albersUsaPr")
951
- ;
952
- } catch (e) {
953
- console.warn("Unexpected widget type: " + widget.classID());
954
- }
955
- });
956
- break;
957
- }
958
- } else {
959
- chartType = chartType || "CHORO";
960
- if (chartType === "CHORO") {
961
- if (this.source.mappings.contains("state")) {
962
- chartType = "CHORO_USSTATES";
963
- } else if (this.source.mappings.contains("county")) {
964
- chartType = "CHORO_USCOUNTIES";
965
- } else if (this.source.mappings.contains("country")) {
966
- chartType = "CHORO_COUNTRIES";
967
- }
968
- }
969
- Promise.all(context.layers.map(function (layer) { return layer.loadedPromise(); })).then(function () {
970
- context.loadWidget("../composite/MegaChart", function (widget) {
971
- const layers = context.layers.map(function (layer) { return layer.widget; });
972
- try {
973
- switch (widget.classID()) {
974
- case "composite_MegaChart":
975
- widget
976
- .id(visualization.id)
977
- .showChartSelect_default(false)
978
- .chartType_default(chartType)
979
- .chartTypeDefaults({
980
- autoScaleMode: layers.length ? "data" : "mesh"
981
- })
982
- .chartTypeProperties({
983
- layers
984
- })
985
- ;
986
- break;
987
- default:
988
- widget
989
- .id(visualization.id)
990
- .autoScaleMode(layers.length ? "data" : "mesh")
991
- .layers(layers)
992
- ;
993
- break;
994
- }
995
- } catch (e) {
996
- console.warn("Unexpected widget type: " + widget.classID());
997
- }
998
- });
999
- });
1000
- }
1001
- break;
1002
- case "2DCHART":
1003
- case "PIE":
1004
- case "BUBBLE":
1005
- case "BAR":
1006
- case "WORD_CLOUD":
1007
- this.loadWidget("../composite/MegaChart", function (widget) {
1008
- try {
1009
- widget
1010
- .id(visualization.id)
1011
- .chartType_default(context.properties.chartType || context.properties.charttype || context.type)
1012
- ;
1013
- } catch (e) {
1014
- console.warn("Unexpected widget type: " + widget.classID());
1015
- }
1016
- });
1017
- break;
1018
- case "LINE":
1019
- this.loadWidget("../composite/MegaChart", function (widget) {
1020
- try {
1021
- widget
1022
- .id(visualization.id)
1023
- .chartType_default(context.properties.chartType || context.properties.charttype || context.type)
1024
- ;
1025
- } catch (e) {
1026
- console.warn("Unexpected widget type: " + widget.classID());
1027
- }
1028
- });
1029
- break;
1030
- case "TABLE":
1031
- this.loadWidget("../composite/MegaChart", function (widget) {
1032
- try {
1033
- widget
1034
- .id(visualization.id)
1035
- .showChartSelect_default(false)
1036
- .chartType_default("TABLE")
1037
- ;
1038
- } catch (e) {
1039
- console.warn("Unexpected widget type: " + widget.classID());
1040
- }
1041
- });
1042
- break;
1043
- case "SLIDER":
1044
- this.loadWidget("../form/Slider", function (widget) {
1045
- try {
1046
- widget
1047
- .id(visualization.id)
1048
- ;
1049
- if (visualization.range) {
1050
- let selectionLabel = "";
1051
- if (Utility.exists("events.click.updates", visualization) && visualization.events.click.updates.length) {
1052
- for (const key in visualization.events.click.updates[0].mappings) {
1053
- selectionLabel = key;
1054
- break;
1055
- }
1056
- }
1057
- widget
1058
- .low_default(+visualization.range[0])
1059
- .high_default(+visualization.range[1])
1060
- .step_default(+visualization.range[2])
1061
- .selectionLabel_default(selectionLabel)
1062
- .selectionLabel(selectionLabel)
1063
- ;
1064
- }
1065
- } catch (e) {
1066
- console.warn("Unexpected widget type: " + widget.classID());
1067
- }
1068
- });
1069
- break;
1070
- case "GRAPH":
1071
- this.loadWidget("../composite/MegaChart", function (widget) {
1072
- try {
1073
- widget
1074
- .id(visualization.id)
1075
- .showChartSelect_default(false)
1076
- .chartType_default("GRAPH")
1077
- .chartTypeDefaults({
1078
- layout: "ForceDirected2",
1079
- applyScaleOnLayout: true
1080
- })
1081
- ;
1082
- } catch (e) {
1083
- console.warn("Unexpected widget type: " + widget.classID());
1084
- }
1085
- });
1086
- break;
1087
- case "FORM":
1088
- this.loadWidgets(["../form/Form", "../form/Input", "../form/Button", "../form/CheckBox", "../form/ColorInput", "../form/Radio", "../form/Range", "../form/Select", "../form/Slider", "../form/TextArea", "../form/InputRange"], function (widget, widgetClasses) {
1089
- const Input = widgetClasses[1];
1090
- const CheckBox = widgetClasses[3];
1091
- const Radio = widgetClasses[5];
1092
- const Select = widgetClasses[7];
1093
- const TextArea = widgetClasses[9];
1094
- const InputRange = widgetClasses[10];
1095
-
1096
- try {
1097
- widget
1098
- .id(visualization.id)
1099
- .inputs(context.fields().map(function (field) {
1100
-
1101
- const selectOptions = [];
1102
- let options = [];
1103
- let inp;
1104
- if (!field.charttype() && field.type() === "range") {
1105
- // TODO - Verify with @DL
1106
- field.charttype("RANGE");
1107
- }
1108
- switch (field.charttype()) {
1109
- case "TEXT":
1110
- inp = new Input()
1111
- .type_default("text")
1112
- ;
1113
- break;
1114
- case "TEXTAREA":
1115
- inp = new TextArea();
1116
- break;
1117
- case "CHECKBOX":
1118
- inp = new CheckBox();
1119
- break;
1120
- case "RADIO":
1121
- inp = new Radio();
1122
- break;
1123
- case "HIDDEN":
1124
- inp = new Input()
1125
- .type_default("hidden")
1126
- ;
1127
- break;
1128
- case "RANGE":
1129
- inp = new InputRange();
1130
- break;
1131
- default:
1132
- if (field.enumvals()) {
1133
- inp = new Select();
1134
- options = field.enumvals();
1135
- for (const val in options) {
1136
- selectOptions.push([val, options[val]]);
1137
- }
1138
- } else {
1139
- inp = new Input()
1140
- .type_default("text")
1141
- ;
1142
- }
1143
- break;
1144
- }
1145
-
1146
- inp
1147
- .name_default(field.id())
1148
- .label_default(field.label())
1149
- .value_default(field.default()) // TODO Hippie support for multiple default values (checkbox only)
1150
- ;
1151
-
1152
- if (inp instanceof CheckBox || inp instanceof Radio) { // change this to instanceof?
1153
- const vals = Object.keys(field.enumvals());
1154
- inp.selectOptions_default(vals);
1155
- } else if (selectOptions.length) {
1156
- inp.selectOptions_default(selectOptions);
1157
- }
1158
-
1159
- return inp;
1160
- }))
1161
- ;
1162
- } catch (e) {
1163
- console.warn("Unexpected widget type: " + widget.classID());
1164
- }
1165
- });
1166
- break;
1167
- case "HEAT_MAP":
1168
- this.loadWidgets(["../other/HeatMap"], function (widget) {
1169
- try {
1170
- widget
1171
- .id(visualization.id)
1172
- .image_default(context.properties.imageUrl)
1173
- ;
1174
- } catch (e) {
1175
- console.warn("Unexpected widget type: " + widget.classID());
1176
- }
1177
- });
1178
- break;
1179
- default:
1180
- this.loadWidget("../common/TextBox", function (widget) {
1181
- try {
1182
- widget
1183
- .id(visualization.id)
1184
- .text_default(context.id + "\n" + "TODO: " + context.type)
1185
- ;
1186
- } catch (e) {
1187
- console.warn("Unexpected widget type: " + widget.classID());
1188
- }
1189
- });
1190
- break;
1191
- }
1192
- }
1193
-
1194
- getQualifiedID() {
1195
- return this.id;
1196
- }
1197
-
1198
- fields() {
1199
- return this._fields;
1200
- }
1201
-
1202
- hasField(id) {
1203
- return this.field[id] !== undefined;
1204
- }
1205
-
1206
- field(id) {
1207
- return this._fieldsMap[id];
1208
- }
1209
-
1210
- loadedPromise() {
1211
- const context = this;
1212
- return new Promise<void>(function (resolve, reject) {
1213
- const intervalHandle = setInterval(function () {
1214
- if (context.isLoaded()) {
1215
- clearInterval(intervalHandle);
1216
- resolve();
1217
- }
1218
- }, 100);
1219
- });
1220
- }
1221
-
1222
- isLoading() {
1223
- return this.widget === null;
1224
- }
1225
-
1226
- isLoaded() {
1227
- return this.widget instanceof Widget;
1228
- }
1229
-
1230
- loadMegaChartWidget(widgetPath, callback) {
1231
- this.loadWidgets(["../composite/MegaChart", widgetPath], function (megaChart, widgets) {
1232
- const chart = new widgets[1]();
1233
- megaChart
1234
- .chartType_default(MultiChart.prototype._allChartTypesByClass[chart.classID()].id)
1235
- .chart(chart)
1236
- ;
1237
- if (callback) {
1238
- callback(megaChart, chart, widgets);
1239
- }
1240
- });
1241
- }
1242
-
1243
- loadWidget(widgetPath, callback) {
1244
- this.loadWidgets([widgetPath], callback);
1245
- }
1246
-
1247
- loadWidgets(widgetPaths, callback) {
1248
- this.widget = null;
1249
-
1250
- const context = this;
1251
- legacyRequire(widgetPaths, function (WidgetClass) {
1252
- const existingWidget = context.dashboard.marshaller.getWidget(context.id);
1253
- if (existingWidget) {
1254
- if (WidgetClass.prototype._class !== existingWidget.classID()) {
1255
- console.warn("Unexpected persisted widget type (old persist string?)");
1256
- }
1257
- context.setWidget(existingWidget);
1258
- } else {
1259
- context.setWidget(new WidgetClass());
1260
- }
1261
- if (callback) {
1262
- callback(context.widget, arguments);
1263
- }
1264
- });
1265
- }
1266
-
1267
- setWidget(widget) {
1268
- this.widget = widget;
1269
- this.events.setWidget(widget);
1270
- if (this.widget.columns) {
1271
- const columns = this.source.getColumns();
1272
- this.widget.columns(columns, true);
1273
- }
1274
- for (const key in this.properties) {
1275
- switch (widget.classID()) {
1276
- case "chart_MultiChart":
1277
- case "composite_MegaChart":
1278
- if (widget[key + "_default"]) {
1279
- widget[key + "_default"](this.properties[key]);
1280
- }
1281
- widget.chartTypeDefaults()[key] = this.properties[key];
1282
- break;
1283
- default:
1284
- if (this.widget[key + "_default"]) {
1285
- try {
1286
- this.widget[key + "_default"](this.properties[key]);
1287
- } catch (e) {
1288
- console.warn("Invalid Property:" + this.id + ".properties." + key);
1289
- }
1290
- }
1291
- }
1292
- }
1293
- return this.widget;
1294
- }
1295
-
1296
- accept(visitor) {
1297
- visitor.visit(this);
1298
- }
1299
-
1300
- getUpdates() {
1301
- return this.events.getUpdates();
1302
- }
1303
-
1304
- getUpdatesForDatasource(otherDatasource) {
1305
- return this.events.getUpdates().filter(function (updateObj) {
1306
- return updateObj.getDatasource() === otherDatasource;
1307
- });
1308
- }
1309
-
1310
- getUpdatesForVisualization(otherViz) {
1311
- return this.events.getUpdates().filter(function (updateObj) {
1312
- return updateObj.getVisualization() === otherViz;
1313
- });
1314
- }
1315
-
1316
- getInputFields(mapped?): any {
1317
- const retVal = {};
1318
- const updatedBy = this.getInputVisualizations();
1319
- updatedBy.forEach(viz => {
1320
- if (viz.hasSelection()) {
1321
- viz.getUpdatesForVisualization(this).forEach(function (updateObj) {
1322
- const sel = mapped ? updateObj.mapSelected() : updateObj.selectedRow();
1323
- for (const key in sel) {
1324
- retVal[key] = sel[key];
1325
- }
1326
- });
1327
- }
1328
- });
1329
- return retVal;
1330
- }
1331
-
1332
- update(params?) {
1333
- let titleWidget = null;
1334
- if (!this.parentVisualization) {
1335
- titleWidget = this.widget;
1336
- while (titleWidget && !titleWidget.title) {
1337
- titleWidget = titleWidget.locateParentWidget();
1338
- }
1339
- }
1340
-
1341
- if (!params) {
1342
- params = "";
1343
- let titleFormatStr = "";
1344
- if (titleWidget && titleWidget.ddlParamsFormat) {
1345
- titleFormatStr = titleWidget.ddlParamsFormat();
1346
- }
1347
-
1348
- const dedupParams = {};
1349
- if (titleFormatStr) {
1350
- params = Utility.template(titleFormatStr, this.getInputFields());
1351
- } else {
1352
- const paramsArr = [];
1353
- const mappedData = this.getInputFields(true);
1354
- for (const key in mappedData) {
1355
- if (mappedData[key]) {
1356
- if (!dedupParams[key]) {
1357
- dedupParams[key] = true;
1358
- paramsArr.push(mappedData[key]);
1359
- }
1360
- }
1361
- }
1362
- params = paramsArr.join(", ");
1363
- }
1364
- }
1365
-
1366
- const context = this;
1367
- return new Promise<void>(function (resolve, reject) {
1368
- if (titleWidget) {
1369
- const title = titleWidget.title();
1370
- const titleParts = title.split(" (");
1371
- titleWidget
1372
- .title(titleParts[0] + (params.trim() ? " (" + params + ")" : ""))
1373
- .render(function () {
1374
- resolve();
1375
- })
1376
- ;
1377
- } else {
1378
- let ddlViz = context;
1379
- while (ddlViz.parentVisualization) {
1380
- ddlViz = ddlViz.parentVisualization;
1381
- }
1382
- ddlViz.widget.render(function () {
1383
- resolve();
1384
- });
1385
- }
1386
- if (context.dashboard.marshaller.propogateClear()) {
1387
- context.events.getUpdatesVisualizations().forEach(function (updatedViz) {
1388
- updatedViz.update();
1389
- });
1390
- }
1391
- });
1392
- }
1393
-
1394
- notify() {
1395
- if (this.widget) {
1396
- const data = this.source.hasData() ? this.source.getData() : [];
1397
- this.widget.data(data);
1398
- if (this.type === "GRAPH" && data.vertices) {
1399
- const ipFields = this.getInputFields(true);
1400
- data.vertices.filter(function (v) {
1401
- return v.__hpcc_uid === ipFields.treeuid;
1402
- }).forEach(function (v) {
1403
- v.centroid(true);
1404
- });
1405
- }
1406
- return this.update();
1407
- }
1408
- return Promise.resolve();
1409
- }
1410
-
1411
- clear() {
1412
- this._widgetState = {
1413
- row: {},
1414
- selected: false
1415
- };
1416
- this.fields().forEach(field => {
1417
- if (field.hasDefault()) {
1418
- this._widgetState.row[field.id()] = field.default();
1419
- this._widgetState.selected = true;
1420
- }
1421
- });
1422
- if (this.widget && this.dashboard.marshaller.clearDataOnUpdate()) {
1423
- this.widget.data([]);
1424
- }
1425
- if (this.dashboard.marshaller.propogateClear()) {
1426
- this.events.getUpdatesVisualizations().forEach(function (updatedViz) {
1427
- updatedViz.clear();
1428
- });
1429
- }
1430
- }
1431
-
1432
- on(eventID, func) {
1433
- const context = this;
1434
- this.overrideMethod(eventID, function (origFunc, args) {
1435
- origFunc.apply(context, args);
1436
- setTimeout(function () {
1437
- func.apply(context, args);
1438
- }, 0);
1439
- });
1440
- return this;
1441
- }
1442
-
1443
- calcRequestFor(visualization) {
1444
- let retVal = {};
1445
- this.getUpdatesForVisualization(visualization).forEach(function (updatesObj) {
1446
- // TODO: When we support more than "click" this will need enhancment...
1447
- retVal = updatesObj.calcRequestFor(visualization);
1448
- });
1449
- return retVal;
1450
- }
1451
-
1452
- processEvent(eventID, event, row, col, selected) {
1453
- this._widgetState = {
1454
- row,
1455
- col,
1456
- selected: selected === undefined ? true : selected
1457
- };
1458
- const context = this;
1459
- setTimeout(function () {
1460
- event.fetchData().then(function (promises) {
1461
- context.dashboard.marshaller.vizEvent(context.widget, "post_" + eventID, row, col, selected);
1462
- });
1463
- }, 0);
1464
- }
1465
-
1466
- hasSelection() {
1467
- return this._widgetState && this._widgetState.selected;
1468
- }
1469
-
1470
- selection() {
1471
- if (this.hasSelection()) {
1472
- return this._widgetState.row;
1473
- }
1474
- return null;
1475
- }
1476
-
1477
- reverseMappedSelection() {
1478
- if (this.hasSelection()) {
1479
- return this.source.mappings ? this.source.mappings.doReverseMap(this._widgetState.row) : this._widgetState.row;
1480
- }
1481
- return null;
1482
- }
1483
-
1484
- getInputVisualizations() {
1485
- return this.dashboard.marshaller.getVisualizationArray().filter(viz => {
1486
- const updates = viz.events.getUpdatesVisualizations();
1487
- if (updates.indexOf(this) >= 0) {
1488
- return true;
1489
- }
1490
- return false;
1491
- });
1492
- }
1493
-
1494
- serializeState() {
1495
- const state: any = {
1496
- widgetState: this._widgetState
1497
- };
1498
- if (this.widget) {
1499
- if (this.widget.serializeState) {
1500
- state.widget = this.widget.serializeState();
1501
- } else if (this.widget.data) {
1502
- state.widget = {
1503
- data: this.widget.data()
1504
- };
1505
- }
1506
- }
1507
- return state;
1508
- }
1509
-
1510
- deserializeState(state) {
1511
- if (state) {
1512
- this._widgetState = state.widgetState;
1513
- if (this.widget && state.widget) {
1514
- if (this.widget.deserializeState) {
1515
- this.widget.deserializeState(state.widget);
1516
- } else if (this.widget.data && state.widget.data) {
1517
- this.widget.data(state.widget.data);
1518
- }
1519
- }
1520
- }
1521
- return this;
1522
- }
1523
- }
1524
-
1525
- // Output ---
1526
- function Filter(this: any, datasource, ddlFilter: string | DDL1.IFilter) {
1527
- this.datasource = datasource;
1528
- if (typeof ddlFilter === "string") {
1529
- ddlFilter = {
1530
- fieldid: ddlFilter,
1531
- nullable: true,
1532
- rule: "=="
1533
- };
1534
- }
1535
- this.fieldid = ddlFilter.fieldid;
1536
- this.nullable = ddlFilter.nullable;
1537
- this.rule = ddlFilter.rule || "==";
1538
- this.minid = ddlFilter.minid;
1539
- this.maxid = ddlFilter.maxid;
1540
- this.calcRequestFieldID();
1541
- }
1542
-
1543
- Filter.prototype.calcRequestFieldID = function () {
1544
- this._requestFieldID = this.fieldid;
1545
- this._requestMinID = this.minid;
1546
- this._requestMaxID = this.maxid;
1547
- switch (this.rule) {
1548
- case "<":
1549
- case "<=":
1550
- if (Utility.endsWith(this.fieldid, "-max")) {
1551
- this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_max" : "");
1552
- }
1553
- break;
1554
- case ">":
1555
- case ">=":
1556
- if (Utility.endsWith(this.fieldid, "-min")) {
1557
- this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_min" : "");
1558
- }
1559
- break;
1560
- case "set":
1561
- if (Utility.endsWith(this.fieldid, "-set")) {
1562
- this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_set" : "");
1563
- }
1564
- break;
1565
- case "range":
1566
- if (Utility.endsWith(this.minid, "-min")) {
1567
- this._requestMinID = this.minid.substring(0, this.minid.length - 4) + (this.datasource.isRoxie() ? "_min" : "");
1568
- }
1569
- if (Utility.endsWith(this.maxid, "-max")) {
1570
- this._requestMaxID = this.maxid.substring(0, this.maxid.length - 4) + (this.datasource.isRoxie() ? "_max" : "");
1571
- }
1572
- break;
1573
- }
1574
- };
1575
-
1576
- Filter.prototype.isRange = function () {
1577
- return this.rule === "range";
1578
- };
1579
-
1580
- Filter.prototype.isSet = function () {
1581
- return this.rule === "set";
1582
- };
1583
-
1584
- Filter.prototype._calcRequest = function (filteredRequest, request, fieldid, requestFieldID, value) {
1585
- if (!this.datasource.isRoxie()) {
1586
- // Ignore requestFieldID, until filtering WU results
1587
- // Otherwise there are many fieldID collisions
1588
- requestFieldID = fieldid;
1589
- }
1590
- filteredRequest[requestFieldID + _CHANGED] = request[fieldid + _CHANGED] || false;
1591
- if (filteredRequest[requestFieldID] !== value) {
1592
- filteredRequest[requestFieldID] = value;
1593
- }
1594
- };
1595
-
1596
- Filter.prototype.calcRequest = function (filteredRequest, request, fillInMissing) {
1597
- if (!fillInMissing && request[this.fieldid] === undefined) {
1598
- return;
1599
- }
1600
- const value = request[this.fieldid] === undefined ? null : request[this.fieldid];
1601
- if (this.isRange()) {
1602
- if (value instanceof Array && value.length === 2) {
1603
- this._calcRequest(filteredRequest, request, this.minid, this._requestMinID, value[0]);
1604
- this._calcRequest(filteredRequest, request, this.maxid, this._requestMaxID, value[1]);
1605
- }
1606
- } else {
1607
- this._calcRequest(filteredRequest, request, this.fieldid, this._requestFieldID, value);
1608
- if (this.isSet() && this.datasource.isRoxie()) {
1609
- // TODO in the future the value should be an array ---
1610
- filteredRequest[this._requestFieldID + ".Item$"] = filteredRequest[this._requestFieldID];
1611
- delete filteredRequest[this._requestFieldID];
1612
- }
1613
- }
1614
- };
1615
-
1616
- Filter.prototype.matches = function (row, value): boolean {
1617
- if (value === undefined || value === null || value === "") {
1618
- return this.nullable;
1619
- }
1620
- let rowValue = row[this._requestFieldID];
1621
- if (rowValue === undefined) {
1622
- rowValue = row[this._requestFieldID.toLowerCase()];
1623
- }
1624
- if (rowValue === undefined) {
1625
- console.warn("Empty cell value: '" + this._requestFieldID + "'");
1626
- return false;
1627
- }
1628
- switch (this.rule) {
1629
- case "<":
1630
- if (rowValue.localeCompare) {
1631
- return rowValue.localeCompare(value) < 0;
1632
- }
1633
- return rowValue < value;
1634
- case ">":
1635
- if (rowValue.localeCompare) {
1636
- return rowValue.localeCompare(value) > 0;
1637
- }
1638
- return rowValue > value;
1639
- case "<=":
1640
- if (rowValue.localeCompare) {
1641
- return rowValue.localeCompare(value) <= 0;
1642
- }
1643
- return rowValue <= value;
1644
- case ">=":
1645
- if (rowValue.localeCompare) {
1646
- return rowValue.localeCompare(value) >= 0;
1647
- }
1648
- return rowValue >= value;
1649
- case "!=":
1650
- case "notequals":
1651
- return rowValue != value; // jshint ignore:line
1652
- case "set":
1653
- if (value instanceof Array) {
1654
- return value.indexOf(rowValue) >= 0;
1655
- }
1656
- return value == rowValue; // jshint ignore:line
1657
- case "==":
1658
- return value == rowValue; // jshint ignore:line
1659
- default:
1660
- console.warn("Unknown filter rule: '" + this.rule + "'");
1661
- return value == rowValue; // jshint ignore:line
1662
- }
1663
- };
1664
-
1665
- export class Output {
1666
-
1667
- datasource;
1668
- id;
1669
- from;
1670
- protected notify;
1671
- filters;
1672
- protected db;
1673
-
1674
- constructor(datasource, output) {
1675
- this.datasource = datasource;
1676
- this.id = output.id;
1677
- this.from = output.from;
1678
- this.notify = output.notify || [];
1679
- this.filters = (output.filter || []).map(filter => {
1680
- return new Filter(this.datasource, filter);
1681
- });
1682
- }
1683
-
1684
- getQualifiedID() {
1685
- return this.datasource.getQualifiedID() + "." + this.id;
1686
- }
1687
-
1688
- getUpdatesVisualizations() {
1689
- const retVal = [];
1690
- this.notify.forEach(item => {
1691
- retVal.push(this.datasource.marshaller.getVisualization(item));
1692
- });
1693
- return retVal;
1694
- }
1695
-
1696
- accept(visitor) {
1697
- visitor.visit(this);
1698
- }
1699
-
1700
- vizNotify(updates) {
1701
- const promises = [];
1702
- this.notify.filter(function (item) {
1703
- return !updates || updates.indexOf(item) >= 0;
1704
- }).forEach(item => {
1705
- const viz = this.datasource.marshaller.getVisualization(item);
1706
- promises.push(viz.notify());
1707
- });
1708
- return Promise.all(promises);
1709
- }
1710
-
1711
- setData(data, updates) {
1712
- this.db = new Database.Grid().jsonObj(data);
1713
- return this.vizNotify(updates);
1714
- }
1715
- }
1716
-
1717
- // FetchData Optimizers ---
1718
- function DatasourceRequestOptimizer(this: any) {
1719
- this.datasourceRequests = {
1720
- };
1721
- }
1722
-
1723
- DatasourceRequestOptimizer.prototype.appendRequest = function (updateDatasource, request, updateVisualization) {
1724
- const datasourceRequestID = updateDatasource.id + "(" + JSON.stringify(request) + ")";
1725
- if (!this.datasourceRequests[datasourceRequestID]) {
1726
- this.datasourceRequests[datasourceRequestID] = {
1727
- updateDatasource,
1728
- request,
1729
- updates: []
1730
- };
1731
- } else if ((window as any).__hpcc_debug) {
1732
- console.warn("Optimized duplicate fetch: " + datasourceRequestID);
1733
- }
1734
- const datasourceOptimizedItem = this.datasourceRequests[datasourceRequestID];
1735
- if (datasourceOptimizedItem.updates.indexOf(updateVisualization.id) < 0) {
1736
- datasourceOptimizedItem.updates.push(updateVisualization.id);
1737
- }
1738
- };
1739
-
1740
- DatasourceRequestOptimizer.prototype.fetchData = function () {
1741
- const promises = [];
1742
- for (const key in this.datasourceRequests) {
1743
- const item = this.datasourceRequests[key];
1744
- promises.push(item.updateDatasource.fetchData(item.request, item.updates));
1745
- }
1746
- return Promise.all(promises);
1747
- };
1748
-
1749
- function VisualizationRequestOptimizer(this: any, skipClear?) {
1750
- this.skipClear = skipClear;
1751
- this.visualizationRequests = {
1752
- };
1753
- }
1754
-
1755
- VisualizationRequestOptimizer.prototype.appendRequest = function (updateDatasource, request, updateVisualization) {
1756
- if (updateDatasource && updateVisualization) {
1757
- const visualizationRequestID = updateVisualization.id + "(" + updateDatasource.id + ")";
1758
- if (!this.visualizationRequests[visualizationRequestID]) {
1759
- this.visualizationRequests[visualizationRequestID] = {
1760
- updateVisualization,
1761
- updateDatasource,
1762
- request: {}
1763
- };
1764
- } else if ((window as any).__hpcc_debug) {
1765
- console.warn("Optimized duplicate fetch: " + visualizationRequestID);
1766
- }
1767
- const visualizationOptimizedItem = this.visualizationRequests[visualizationRequestID];
1768
- Utility.mixin(visualizationOptimizedItem.request, request);
1769
- }
1770
- };
1771
-
1772
- VisualizationRequestOptimizer.prototype.fetchData = function () {
1773
- const datasourceRequestOptimizer = new DatasourceRequestOptimizer();
1774
- for (const key in this.visualizationRequests) {
1775
- const item = this.visualizationRequests[key];
1776
- if (!this.skipClear && item.updateVisualization.type !== "GRAPH") {
1777
- item.updateVisualization.clear();
1778
- }
1779
- item.updateVisualization.update(LOADING);
1780
- datasourceRequestOptimizer.appendRequest(item.updateDatasource, item.request, item.updateVisualization);
1781
- }
1782
- return datasourceRequestOptimizer.fetchData();
1783
- };
1784
-
1785
- // Datasource ---
1786
- let transactionID = 0;
1787
- const transactionQueue = [];
1788
- export class Datasource {
1789
-
1790
- protected marshaller;
1791
- id;
1792
- protected WUID;
1793
- protected URL;
1794
- databomb;
1795
- protected filters;
1796
- protected _loadedCount;
1797
- protected _outputs;
1798
- protected _outputArray;
1799
- comms;
1800
- protected _loadedCount2;
1801
- protected _loadedCount3;
1802
- protected _loadedCount4;
1803
-
1804
- constructor(marshaller, datasource: DDL1.IAnyDatasource, proxyMappings, timeout) {
1805
- this.marshaller = marshaller;
1806
- this.id = datasource.id;
1807
- if (DDL1.isWorkunitDatasource(datasource)) {
1808
- this.WUID = datasource.WUID;
1809
- } else if (DDL1.isHipieDatasource(datasource)) {
1810
- this.URL = (marshaller.espUrl && marshaller.espUrl.url()) ? marshaller.espUrl.url() : datasource.URL;
1811
- } else if (DDL1.isDatabombDatasource(datasource)) {
1812
- this.databomb = datasource.databomb;
1813
- }
1814
- this.filters = (datasource.filter || []).map(filter => {
1815
- return new Filter(this, filter);
1816
- });
1817
- this._loadedCount = 0;
1818
-
1819
- const context = this;
1820
- this._outputs = {};
1821
- this._outputArray = [];
1822
- const hipieResults = [];
1823
- datasource.outputs.forEach(item => {
1824
- const output = new Output(context, item);
1825
- context._outputs[item.id] = output;
1826
- context._outputArray.push(output);
1827
- hipieResults.push({
1828
- id: item.id,
1829
- from: item.from,
1830
- filters: output.filters || this.filters
1831
- });
1832
- });
1833
-
1834
- if (this.WUID) {
1835
- this.comms = new Comms.HIPIEWorkunit()
1836
- .url(this.URL)
1837
- .proxyMappings(proxyMappings)
1838
- .timeout(timeout)
1839
- .hipieResults(hipieResults)
1840
- ;
1841
- } else if (this.databomb) {
1842
- this.comms = new Comms.HIPIEDatabomb()
1843
- .hipieResults(hipieResults)
1844
- ;
1845
- } else if (DDL1.isHipieDatasource(datasource)) {
1846
- this.comms = new Comms.HIPIERoxie()
1847
- .url(datasource.URL)
1848
- .proxyMappings(proxyMappings)
1849
- .timeout(timeout)
1850
- .hipieResults(hipieResults)
1851
- ;
1852
- }
1853
- }
1854
-
1855
- isRoxie() {
1856
- return !this.WUID && !this.databomb;
1857
- }
1858
-
1859
- isWU() {
1860
- return !!this.WUID;
1861
- }
1862
-
1863
- isDatabomb() {
1864
- return !!this.databomb;
1865
- }
1866
-
1867
- getQualifiedID() {
1868
- return this.id;
1869
- }
1870
-
1871
- getOutputs() {
1872
- return this._outputs;
1873
- }
1874
-
1875
- getUpdatesVisualizations() {
1876
- const retVal = [];
1877
- for (const key in this._outputs) {
1878
- this._outputs[key].getUpdatesVisualizations().forEach(function (visualization) {
1879
- retVal.push(visualization);
1880
- });
1881
- }
1882
- return retVal;
1883
- }
1884
-
1885
- accept(visitor) {
1886
- visitor.visit(this);
1887
- for (const key in this._outputs) {
1888
- this._outputs[key].accept(visitor);
1889
- }
1890
- }
1891
-
1892
- calcRequest(request, fillInMissing) {
1893
- const retVal = {};
1894
- this.filters.forEach(function (item) {
1895
- item.calcRequest(retVal, request, fillInMissing);
1896
- });
1897
- // TODO - Workaround HIPIE issue where it omits filters at datasource level ---
1898
- this._outputArray.forEach(function (output) {
1899
- output.filters.forEach(function (item) {
1900
- item.calcRequest(retVal, request, fillInMissing);
1901
- });
1902
- });
1903
- return retVal;
1904
- }
1905
-
1906
- fetchData(request, updates) {
1907
- const myTransactionID = ++transactionID;
1908
- transactionQueue.push(myTransactionID);
1909
-
1910
- let dsRequest = request;
1911
- dsRequest = this.calcRequest(request, this.isRoxie());
1912
- dsRequest.refresh = request.refresh || false;
1913
- if ((window as any).__hpcc_debug) {
1914
- console.warn("fetchData: " + JSON.stringify(updates) + "(" + JSON.stringify(request) + ")");
1915
- }
1916
- for (const key in dsRequest) {
1917
- if (dsRequest[key] === undefined) {
1918
- delete dsRequest[key];
1919
- }
1920
- }
1921
- const now = Date.now();
1922
- this.marshaller.commsEvent(this, "request", dsRequest);
1923
- const context = this;
1924
- return new Promise(function (resolve, reject) {
1925
- context.comms.call(dsRequest).then(function (_response) {
1926
- const response = JSON.parse(JSON.stringify(_response));
1927
- const intervalHandle = setInterval(function () {
1928
- if (transactionQueue[0] === myTransactionID && Date.now() - now >= 500) { // 500 is to allow for all "clear" transitions to complete...
1929
- clearTimeout(intervalHandle);
1930
- context.processResponse(response, dsRequest, updates).then(function () {
1931
- transactionQueue.shift();
1932
- resolve(response);
1933
- context.marshaller.commsEvent(context, "response", dsRequest, response);
1934
- ++context._loadedCount;
1935
- });
1936
- }
1937
- }, 100);
1938
- }).catch(function (e) {
1939
- context.marshaller.commsEvent(context, "error", dsRequest, e);
1940
- reject(e);
1941
- });
1942
- });
1943
- }
1944
-
1945
- processResponse(response, request, updates) {
1946
- const lowerResponse = {};
1947
- for (const responseKey in response) {
1948
- lowerResponse[responseKey.toLowerCase()] = response[responseKey];
1949
- }
1950
- const promises = [];
1951
- for (const key in this._outputs) {
1952
- const from = this._outputs[key].id;
1953
- if (Utility.exists(from, response)) {
1954
- if (!Utility.exists(from + _CHANGED, response) || (Utility.exists(from + _CHANGED, response) && response[from + _CHANGED].length && response[from + _CHANGED][0][from + _CHANGED])) {
1955
- promises.push(this._outputs[key].setData(response[from], updates));
1956
- } else {
1957
- // TODO - I Suspect there is a HIPIE/Roxie issue here (empty request)
1958
- promises.push(this._outputs[key].vizNotify(updates));
1959
- }
1960
- } else if (Utility.exists(from, lowerResponse)) {
1961
- console.warn("DDL 'Datasource.From' case is Incorrect");
1962
- if (!Utility.exists(from + _CHANGED, lowerResponse) || (Utility.exists(from + _CHANGED, lowerResponse) && response[from + _CHANGED].length && lowerResponse[from + _CHANGED][0][from + _CHANGED])) {
1963
- promises.push(this._outputs[key].setData(lowerResponse[from], updates));
1964
- } else {
1965
- // TODO - I Suspect there is a HIPIE/Roxie issue here (empty request)
1966
- promises.push(this._outputs[key].vizNotify(updates));
1967
- }
1968
- } else {
1969
- const responseItems = [];
1970
- for (const responseKey2 in response) {
1971
- responseItems.push(responseKey2);
1972
- }
1973
- console.warn("Unable to locate '" + from + "' in response {" + responseItems.join(", ") + "}");
1974
- }
1975
- }
1976
- return Promise.all(promises);
1977
- }
1978
-
1979
- isLoaded() {
1980
- return this._loadedCount > 0;
1981
- }
1982
-
1983
- serializeState() {
1984
- return {
1985
- };
1986
- }
1987
-
1988
- deserializeState(state) {
1989
- if (!state) return;
1990
- }
1991
- }
1992
-
1993
- // Dashboard ---
1994
- export function Dashboard(this: any, marshaller, dashboard, proxyMappings, timeout?) {
1995
- this.marshaller = marshaller;
1996
- this.id = dashboard.id;
1997
- this.title = dashboard.title;
1998
-
1999
- this._datasources = {};
2000
- this._datasourceArray = [];
2001
- this._datasourceTotal = 0;
2002
- if (dashboard.datasources) {
2003
- dashboard.datasources.forEach(item => {
2004
- this.createDatasource(item, proxyMappings, timeout);
2005
- });
2006
- }
2007
- this._datasourceTotal = this._datasourceArray.length;
2008
-
2009
- this._visualizations = {};
2010
- this._visualizationArray = [];
2011
- dashboard.visualizations.forEach(item => {
2012
- this.createVisualization(item);
2013
- });
2014
- this._visualizationTotal = this._visualizationArray.length;
2015
- }
2016
-
2017
- Dashboard.prototype.createDatasource = function (ddlDatasouce) {
2018
- let retVal = this._datasources[ddlDatasouce.id];
2019
- if (!retVal) {
2020
- retVal = this.marshaller.createDatasource(ddlDatasouce);
2021
- this._datasources[ddlDatasouce.id] = retVal;
2022
- this._datasourceArray.push(retVal);
2023
- }
2024
- this._datasourceTotal = this._datasourceArray.length;
2025
- return retVal;
2026
- };
2027
-
2028
- Dashboard.prototype.createVisualization = function (ddlVisualization, parentVisualization) {
2029
- const retVal = new Visualization(this, ddlVisualization, parentVisualization);
2030
- this._visualizations[ddlVisualization.id] = retVal;
2031
- this._visualizationArray.push(retVal);
2032
- this.marshaller.appendVisualization(retVal);
2033
- return retVal;
2034
- };
2035
-
2036
- Dashboard.prototype.loadedPromise = function () {
2037
- return Promise.all(this._visualizationArray.map(function (visualization) { return visualization.loadedPromise(); }));
2038
- };
2039
-
2040
- Dashboard.prototype.getQualifiedID = function () {
2041
- return this.id;
2042
- };
2043
-
2044
- Dashboard.prototype.getDatasources = function () {
2045
- return this._datasources;
2046
- };
2047
-
2048
- Dashboard.prototype.getDatasourceArray = function () {
2049
- return this._datasourceArray;
2050
- };
2051
-
2052
- Dashboard.prototype.getDatasource = function (id) {
2053
- return this._datasources[id] || this.marshaller.getDatasource(id);
2054
- };
2055
-
2056
- Dashboard.prototype.getDataSourceArray = function () {
2057
- return this._datasourceArray;
2058
- };
2059
-
2060
- Dashboard.prototype.getVisualization = function (id) {
2061
- return this._visualizations[id] || this.marshaller.getVisualization(id);
2062
- };
2063
-
2064
- Dashboard.prototype.getVisualizations = function () {
2065
- return this._visualizations;
2066
- };
2067
-
2068
- Dashboard.prototype.getVisualizationArray = function () {
2069
- return this._visualizationArray;
2070
- };
2071
-
2072
- Dashboard.prototype.getVisualizationTotal = function () {
2073
- return this._visualizationTotal;
2074
- };
2075
-
2076
- Dashboard.prototype.accept = function (visitor) {
2077
- visitor.visit(this);
2078
- for (const key in this._datasources) {
2079
- this._datasources[key].accept(visitor);
2080
- }
2081
- this._visualizationArray.forEach(function (item) {
2082
- item.accept(visitor);
2083
- }, this);
2084
- };
2085
-
2086
- Dashboard.prototype.primeData = function (state) {
2087
- const fetchDataOptimizer = new VisualizationRequestOptimizer(true);
2088
- this.getVisualizationArray().forEach(function (visualization) {
2089
- // Clear all charts back to their default values ---
2090
- visualization.clear();
2091
- visualization.update();
2092
- if (state && state[visualization.id]) {
2093
- if (Utility.exists("source.mappings.mappings", visualization)) {
2094
- for (const key in visualization.source.mappings.mappings) {
2095
- if (state[visualization.id][visualization.source.mappings.mappings[key]]) {
2096
- visualization._widgetState.row[key] = state[visualization.id][visualization.source.mappings.mappings[key]];
2097
- visualization._widgetState.selected = true;
2098
- }
2099
- }
2100
- }
2101
- }
2102
- });
2103
- this.getVisualizationArray().forEach(function (visualization) {
2104
- const inputVisualizations = visualization.getInputVisualizations();
2105
- const datasource = visualization.source.getDatasource();
2106
- let hasInputSelection = false;
2107
- inputVisualizations.forEach(function (inViz) {
2108
- if (inViz.hasSelection()) {
2109
- const request = inViz.calcRequestFor(visualization);
2110
- request.refresh = true;
2111
- fetchDataOptimizer.appendRequest(datasource, request, visualization);
2112
- hasInputSelection = true;
2113
- }
2114
- });
2115
- if (!hasInputSelection && ((datasource && datasource.isRoxie()) || inputVisualizations.length === 0)) {
2116
- fetchDataOptimizer.appendRequest(datasource, { refresh: true }, visualization);
2117
- }
2118
- });
2119
- return fetchDataOptimizer.fetchData();
2120
- };
2121
-
2122
- Dashboard.prototype.serializeState = function () {
2123
- const retVal = {
2124
- datasources: {},
2125
- visualizations: {}
2126
- };
2127
- for (const key in this._datasources) {
2128
- retVal.datasources[key] = this._datasources[key].serializeState();
2129
- }
2130
- for (const vizKey in this._visualizations) {
2131
- retVal.visualizations[vizKey] = this._visualizations[vizKey].serializeState();
2132
- }
2133
- return retVal;
2134
- };
2135
-
2136
- Dashboard.prototype.deserializeState = function (state) {
2137
- if (!state) return;
2138
- for (const key in this._datasources) {
2139
- if (state.datasources[key]) {
2140
- this._datasources[key].deserializeState(state.datasources[key]);
2141
- }
2142
- }
2143
- for (const vizKey in this._visualizations) {
2144
- if (state.visualizations[vizKey]) {
2145
- this._visualizations[vizKey].deserializeState(state.visualizations[vizKey]);
2146
- }
2147
- }
2148
- };
2149
-
2150
- // Marshaller ---
2151
- export function Marshaller(this: any) {
2152
- Class.call(this);
2153
-
2154
- this._proxyMappings = {};
2155
- this._widgetMappings = d3Map();
2156
- this._clearDataOnUpdate = true;
2157
- this._propogateClear = false;
2158
- this.id = "Marshaller";
2159
- this._missingDataString = "";
2160
- this.dashboards = {};
2161
- this.dashboardArray = [];
2162
-
2163
- this._datasources = {};
2164
- this._datasourceArray = [];
2165
- this._visualizations = {};
2166
- this._visualizationArray = [];
2167
- }
2168
- Marshaller.prototype = Object.create(Class.prototype);
2169
- Marshaller.prototype.constructor = Marshaller;
2170
-
2171
- Marshaller.prototype.commsDataLoaded = function () {
2172
- for (let i = 0; i < this.dashboardArray.length; i++) {
2173
- for (const ds in this.dashboardArray[i].getDatasources()) {
2174
- if (!this.dashboardArray[i].getDatasource(ds).isLoaded()) {
2175
- return false;
2176
- }
2177
- }
2178
- }
2179
- return true;
2180
- };
2181
-
2182
- Marshaller.prototype.accept = function (visitor) {
2183
- visitor.visit(this);
2184
- for (const key2 in this._datasources) {
2185
- this._datasources[key2].accept(visitor);
2186
- }
2187
- this.dashboardTotal = 0;
2188
- for (const key in this.dashboards) {
2189
- this.dashboards[key].accept(visitor);
2190
- ++this.dashboardTotal;
2191
- }
2192
- };
2193
-
2194
- Marshaller.prototype.url = function (url, callback) {
2195
- this.espUrl = new Comms.ESPUrl()
2196
- .url(url)
2197
- ;
2198
- let transport = null;
2199
- let hipieResultName = "HIPIE_DDL";
2200
- if (this.espUrl.isWorkunitResult()) {
2201
- hipieResultName = this.espUrl.param("ResultName");
2202
- transport = new Comms.HIPIEWorkunit()
2203
- .url(url)
2204
- .proxyMappings(this._proxyMappings)
2205
- .timeout(this._timeout)
2206
- ;
2207
- } else {
2208
- transport = new Comms.HIPIERoxie()
2209
- .url(url)
2210
- .proxyMappings(this._proxyMappings)
2211
- .timeout(this._timeout)
2212
- ;
2213
- }
2214
-
2215
- const context = this;
2216
- transport.fetchResults().then(function (response) {
2217
- if (Utility.exists(hipieResultName, response)) {
2218
- return transport.fetchResult(hipieResultName).then(function (ddlResponse) {
2219
- const json = ddlResponse[0][hipieResultName];
2220
- context.parse(json, function () {
2221
- callback(response);
2222
- });
2223
- }).catch(function (e) {
2224
- context.commsEvent(context, "error", hipieResultName, e);
2225
- });
2226
- }
2227
- }).catch(function (e) {
2228
- context.commsEvent(context, "error", "fetchResults", e);
2229
- });
2230
- };
2231
-
2232
- Marshaller.prototype.proxyMappings = function (_) {
2233
- if (!arguments.length) return this._proxyMappings;
2234
- this._proxyMappings = _;
2235
- return this;
2236
- };
2237
-
2238
- Marshaller.prototype.timeout = function (_) {
2239
- if (!arguments.length) return this._timeout;
2240
- this._timeout = _;
2241
- return this;
2242
- };
2243
-
2244
- Marshaller.prototype.widgetMappings = function (_) {
2245
- if (!arguments.length) return this._widgetMappings;
2246
- this._widgetMappings = _;
2247
- return this;
2248
- };
2249
-
2250
- Marshaller.prototype.clearDataOnUpdate = function (_) {
2251
- if (!arguments.length) return this._clearDataOnUpdate;
2252
- this._clearDataOnUpdate = _;
2253
- return this;
2254
- };
2255
-
2256
- Marshaller.prototype.propogateClear = function (_) {
2257
- if (!arguments.length) return this._propogateClear;
2258
- this._propogateClear = _;
2259
- return this;
2260
- };
2261
-
2262
- Marshaller.prototype.missingDataString = function (_) {
2263
- if (!arguments.length) return this._missingDataString;
2264
- this._missingDataString = _;
2265
- return this;
2266
- };
2267
-
2268
- Marshaller.prototype.parse = function (json, callback) {
2269
- const context = this;
2270
- this._json = json;
2271
- this._jsonParsed = JSON.parse(this._json);
2272
-
2273
- // Global Datasources ---
2274
- this._datasources = {};
2275
- this._datasourceArray = [];
2276
- if (this._jsonParsed.datasources) {
2277
- this._jsonParsed.datasources.forEach(function (item) {
2278
- context.createDatasource(item);
2279
- });
2280
- }
2281
-
2282
- this.dashboards = {};
2283
- this.dashboardArray = [];
2284
- this._visualizations = {};
2285
- this._visualizationArray = [];
2286
- const dashboards = this._jsonParsed.dashboards || this._jsonParsed;
2287
- dashboards.forEach(function (item) {
2288
- const newDashboard = new Dashboard(context, item, context._proxyMappings, context._timeout);
2289
- context.dashboards[item.id] = newDashboard;
2290
- context.dashboardArray.push(newDashboard);
2291
- });
2292
- this.dashboardTotal = this.dashboardArray.length;
2293
- this._visualizationArray.forEach(function (ddlViz) {
2294
- ddlViz.on("processEvent", function (eventID, event, row, col, selected) {
2295
- context.vizEvent(ddlViz.widget, eventID, row, col, selected);
2296
- });
2297
- });
2298
- this._datasourceTotal = this._datasourceArray.length;
2299
-
2300
- this.ready(callback);
2301
- return this;
2302
- };
2303
-
2304
- Marshaller.prototype.dashboardsLoaded = function () {
2305
- return Promise.all(this.dashboardArray.map(function (dashboard) { return dashboard.loadedPromise(); }));
2306
- };
2307
-
2308
- Marshaller.prototype.createDatasource = function (ddlDatasouce: DDL1.IAnyDatasource) {
2309
- let retVal = this._datasources[ddlDatasouce.id];
2310
- if (!retVal) {
2311
- retVal = new Datasource(this, ddlDatasouce, this._proxyMappings, this._timeout);
2312
- this._datasources[ddlDatasouce.id] = retVal;
2313
- this._datasourceArray.push(retVal);
2314
- }
2315
- this._datasourceTotal = this._datasourceArray.length;
2316
- return retVal;
2317
- };
2318
-
2319
- Marshaller.prototype.getDatasource = function (id) {
2320
- return this._datasources[id];
2321
- };
2322
-
2323
- Marshaller.prototype.getDatasources = function () {
2324
- return this._datasources;
2325
- };
2326
-
2327
- Marshaller.prototype.getDatasourceArray = function () {
2328
- return this._datasourceArray;
2329
- };
2330
-
2331
- Marshaller.prototype.appendVisualization = function (visualization) {
2332
- this._visualizations[visualization.id] = visualization;
2333
- this._visualizationArray.push(visualization);
2334
- };
2335
-
2336
- Marshaller.prototype.getVisualization = function (id) {
2337
- return this._visualizations[id];
2338
- };
2339
-
2340
- Marshaller.prototype.appendDataSource = function (datasource) {
2341
- this._datasources[datasource.id] = datasource;
2342
- this._datasourceArray.push(datasource);
2343
- };
2344
-
2345
- Marshaller.prototype.getVisualizations = function () {
2346
- return this._visualizations;
2347
- };
2348
-
2349
- Marshaller.prototype.getVisualizationArray = function () {
2350
- return this._visualizationArray;
2351
- };
2352
-
2353
- Marshaller.prototype.getWidget = function (id) {
2354
- return this._widgetMappings.get(id);
2355
- };
2356
-
2357
- Marshaller.prototype.on = function (eventID, func) {
2358
- const context = this;
2359
- this.overrideMethod(eventID, function (origFunc, args) {
2360
- const retVal = origFunc.apply(context, args);
2361
- return func.apply(context, args) || retVal;
2362
- });
2363
- return this;
2364
- };
2365
-
2366
- Marshaller.prototype.ready = function (callback) {
2367
- if (!callback) {
2368
- return;
2369
- }
2370
- this.dashboardsLoaded().then(function () {
2371
- callback();
2372
- });
2373
- };
2374
-
2375
- Marshaller.prototype.vizEvent = function (sourceWidget, eventID, row, col, selected) {
2376
- console.warn("Marshaller.vizEvent: " + sourceWidget.id() + "-" + eventID);
2377
- };
2378
-
2379
- Marshaller.prototype.commsEvent = function (ddlSource, eventID, request, response) {
2380
- switch (eventID) {
2381
- case "request":
2382
- if ((window as any).__hpcc_debug) {
2383
- console.warn("Marshaller.commsEvent: " + ddlSource.id + "-" + eventID + ": " + JSON.stringify(request));
2384
- }
2385
- break;
2386
- case "response":
2387
- case "error":
2388
- if ((window as any).__hpcc_debug) {
2389
- console.warn("Marshaller.commsEvent: " + ddlSource.id + "-" + eventID + ": " + JSON.stringify(response));
2390
- }
2391
- break;
2392
- default:
2393
- if ((window as any).__hpcc_debug) {
2394
- console.warn("Marshaller.commsEvent: " + JSON.stringify(arguments));
2395
- }
2396
- break;
2397
-
2398
- }
2399
- };
2400
-
2401
- Marshaller.prototype.createDatabomb = function () {
2402
- const retVal = {};
2403
- this.dashboardArray.forEach(function (dashboard) {
2404
- for (const key in dashboard.getDatasources()) {
2405
- const comms = dashboard.getDatasource(key).comms;
2406
- retVal[key] = {};
2407
- for (const key2 in comms._hipieResults) {
2408
- const hipieResult = comms._hipieResults[key2];
2409
- retVal[key][key2] = comms._resultNameCache[hipieResult.from];
2410
- }
2411
- }
2412
- });
2413
- return retVal;
2414
- };
2415
-
2416
- Marshaller.prototype.primeData = function (state) {
2417
- const promises = this.dashboardArray.map(function (dashboard) {
2418
- return dashboard.primeData(state);
2419
- });
2420
- return Promise.all(promises);
2421
- };
2422
-
2423
- Marshaller.prototype.serializeState = function () {
2424
- const retVal = {};
2425
- this.dashboardArray.forEach(function (dashboard, idx) {
2426
- retVal[dashboard.id] = dashboard.serializeState();
2427
- });
2428
- return retVal;
2429
- };
2430
-
2431
- Marshaller.prototype.deserializeState = function (state) {
2432
- if (!state) return;
2433
- this.dashboardArray.forEach(function (dashboard, idx) {
2434
- dashboard.deserializeState(state[dashboard.id]);
2435
- });
2436
- return this;
2437
- };
1
+ import { Class, Database, Utility, Widget } from "@hpcc-js/common";
2
+ import { MultiChart } from "@hpcc-js/composite";
3
+ import { DDL1 } from "@hpcc-js/ddl-shim";
4
+ import { Comms, Table } from "@hpcc-js/other";
5
+ import { map as d3Map } from "d3-collection";
6
+
7
+ declare const require: any;
8
+
9
+ const LOADING = "...loading...";
10
+ const _CHANGED = "_changed";
11
+
12
+ function faCharFix(faChar) {
13
+ if (faChar) {
14
+ return String.fromCharCode(parseInt(faChar));
15
+ }
16
+ return faChar;
17
+ }
18
+
19
+ function hipieType2DBType(hipieType) {
20
+ switch (hipieType) {
21
+ case "bool":
22
+ case "boolean":
23
+ return "boolean";
24
+ case "integer":
25
+ case "float":
26
+ case "double":
27
+ return "number";
28
+ case "date":
29
+ case "time":
30
+ return "time";
31
+ case "geohash":
32
+ return "geohash";
33
+ case "dataset":
34
+ return "dataset";
35
+ case "visualization":
36
+ return "widget";
37
+ default:
38
+ if (hipieType) {
39
+ if (hipieType.indexOf("unsigned") === 0) {
40
+ return "number";
41
+ } else if (hipieType.indexOf("integer") === 0) {
42
+ return "number";
43
+ } else if (hipieType.indexOf("real") === 0) {
44
+ return "number";
45
+ } else if (hipieType.indexOf("string") === 0) {
46
+ return "string";
47
+ }
48
+ }
49
+ }
50
+ if ((window as any).__hpcc_debug) {
51
+ console.warn("unknown hipieType: " + hipieType);
52
+ }
53
+ return "string";
54
+ }
55
+
56
+ // Mappings ---
57
+ function SourceMappings(this: any, visualization, mappings) {
58
+ this.visualization = visualization;
59
+ const newMappings = {};
60
+ for (const key in mappings) {
61
+ if (mappings[key] instanceof Array) {
62
+ mappings[key].forEach(function (mapingItem, idx) {
63
+ newMappings[idx === 0 ? key : key + "_" + idx] = mapingItem;
64
+ });
65
+ } else {
66
+ newMappings[key] = mappings[key];
67
+ }
68
+ }
69
+ this.mappings = newMappings;
70
+ this.hasMappings = false;
71
+ this.reverseMappings = {};
72
+ this.columns = [];
73
+ this.columnsIdx = {};
74
+ this.columnsRHS = [];
75
+ this.columnsRHSIdx = {};
76
+ }
77
+
78
+ SourceMappings.prototype.init = function () {
79
+ for (const key in this.mappings) {
80
+ this.reverseMappings[this.mappings[key]] = key;
81
+ if (this.columnsIdx[key] === undefined) {
82
+ this.columns.push(key);
83
+ this.columnsIdx[key] = this.columns.length - 1;
84
+ }
85
+ this.columnsRHS[this.columnsIdx[key]] = this.mappings[key];
86
+ this.columnsRHSIdx[this.mappings[key]] = this.columnsIdx[key];
87
+ this.hasMappings = true;
88
+ }
89
+ };
90
+
91
+ SourceMappings.prototype.init = function () {
92
+ for (const key in this.mappings) {
93
+ this.reverseMappings[this.mappings[key]] = key;
94
+ if (this.columnsIdx[key] === undefined) {
95
+ this.columns.push(key);
96
+ this.columnsIdx[key] = this.columns.length - 1;
97
+ }
98
+ this.columnsRHS[this.columnsIdx[key]] = this.mappings[key];
99
+ this.columnsRHSIdx[this.mappings[key]] = this.columnsIdx[key];
100
+ this.hasMappings = true;
101
+ }
102
+ };
103
+
104
+ SourceMappings.prototype.getFields = function () {
105
+ if (this.visualization.fields()) {
106
+ return Object.keys(this.mappings).map(key => {
107
+ const field = this.visualization.field(key);
108
+ if (!field) {
109
+ console.warn("Unknown mapping field: " + key);
110
+ }
111
+ return new Database.Field(field.id())
112
+ .type(field.jsType())
113
+ .label(this.reverseMappings[field.id()])
114
+ ;
115
+ });
116
+ }
117
+ return null;
118
+ };
119
+
120
+ SourceMappings.prototype.contains = function (key) {
121
+ return this.mappings[key] !== undefined;
122
+ };
123
+
124
+ SourceMappings.prototype.doMap = function (item) {
125
+ const retVal = [];
126
+ for (const key in this.mappings) {
127
+ const rhsKey = this.mappings[key];
128
+ try {
129
+ let val = item[rhsKey];
130
+ if (val === undefined) {
131
+ val = item[rhsKey.toLowerCase()];
132
+ }
133
+ retVal[this.columnsIdx[key]] = val;
134
+ } catch (e) {
135
+ console.warn("Invalid Mapping: " + this.visualization.id + " [" + rhsKey + "->" + item + "]");
136
+ }
137
+ }
138
+ return retVal;
139
+ };
140
+
141
+ SourceMappings.prototype.doReverseMap = function (item) {
142
+ const retVal = {};
143
+ for (const key in this.mappings) {
144
+ const rhsKey = this.mappings[key];
145
+ try {
146
+ let val = item[key];
147
+ if (val === undefined) {
148
+ val = item[key.toLowerCase()];
149
+ }
150
+ retVal[rhsKey] = val;
151
+ } catch (e) {
152
+ console.warn("Invalid Mapping: " + this.visualization.id + " [" + key + "->" + item + "]");
153
+ }
154
+ }
155
+ return retVal;
156
+ };
157
+
158
+ SourceMappings.prototype.doMapAll = function (data) {
159
+ return data.hipieMappings(this.columnsRHS.map(col => {
160
+ return this.visualization.field(col);
161
+ }), this.visualization.dashboard.marshaller.missingDataString());
162
+ };
163
+
164
+ SourceMappings.prototype.getMap = function (key) {
165
+ return this.mappings[key];
166
+ };
167
+
168
+ SourceMappings.prototype.getReverseMap = function (key) {
169
+ return this.reverseMappings[key];
170
+ };
171
+
172
+ SourceMappings.prototype.hipieMapSortArray = function (sort) {
173
+ return sort.map(sortField => {
174
+ let reverse = false;
175
+ if (sortField.indexOf("-") === 0) {
176
+ sortField = sortField.substring(1);
177
+ reverse = true;
178
+ }
179
+ const fieldIdx = this.columnsRHS.indexOf(sortField);
180
+ if (fieldIdx < 0) {
181
+ console.warn("SourceMappings.prototype.hipieMapSortArray: Invalid sort array - " + sortField);
182
+ }
183
+ return {
184
+ idx: fieldIdx,
185
+ reverse
186
+ };
187
+ }).filter(function (d) { return d.idx >= 0; });
188
+ };
189
+
190
+ function ChartMappings(this: any, visualization, mappings) {
191
+ SourceMappings.call(this, visualization, mappings);
192
+ this.columns = ["label", "weight"];
193
+ this.columnsIdx = { label: 0, weight: 1 };
194
+ this.init();
195
+ }
196
+ ChartMappings.prototype = Object.create(SourceMappings.prototype);
197
+
198
+ function ChoroMappings(this: any, visualization, mappings) {
199
+ SourceMappings.call(this, visualization, mappings);
200
+ if (mappings.state) {
201
+ this.columns = ["state", "weight"];
202
+ this.columnsIdx = { state: 0, weight: 1 };
203
+ } else if (mappings.county) {
204
+ this.columns = ["county", "weight"];
205
+ this.columnsIdx = { county: 0, weight: 1 };
206
+ } else if (mappings.geohash) {
207
+ this.columns = ["geohash", "weight"];
208
+ this.columnsIdx = { geohash: 0, weight: 1 };
209
+ }
210
+ this.init();
211
+ }
212
+ ChoroMappings.prototype = Object.create(SourceMappings.prototype);
213
+
214
+ function ChoroMappings2(this: any, visualization, mappings) {
215
+ SourceMappings.call(this, visualization, mappings);
216
+ if (mappings.state) {
217
+ this.columns = ["state"];
218
+ this.columnsIdx = { state: 0 };
219
+ } else if (mappings.county) {
220
+ this.columns = ["county"];
221
+ this.columnsIdx = { county: 0 };
222
+ } else if (mappings.geohash) {
223
+ this.columns = ["geohash", "label"];
224
+ this.columnsIdx = { geohash: 0, label: 1 };
225
+ }
226
+ const weightOffset = this.columns.length;
227
+ if (mappings.weight instanceof Array) {
228
+ mappings.weight.forEach((w, i) => {
229
+ this.columns.push(w);
230
+ this.columnsIdx[i === 0 ? "weight" : "weight_" + i] = i + weightOffset;
231
+ });
232
+ }
233
+ this.init();
234
+ }
235
+ ChoroMappings2.prototype = Object.create(SourceMappings.prototype);
236
+
237
+ function HeatMapMappings(this: any, visualization, mappings) {
238
+ SourceMappings.call(this, visualization, mappings);
239
+ this.columns = ["x", "y", "weight"];
240
+ this.columnsIdx = { x: 0, y: 1, weight: 2 };
241
+ this.init();
242
+ }
243
+ HeatMapMappings.prototype = Object.create(SourceMappings.prototype);
244
+
245
+ function LineMappings(this: any, visualization, mappings) {
246
+ const newMappings = {
247
+ label: mappings.x[0]
248
+ };
249
+ mappings.y.forEach(function (item, idx) {
250
+ newMappings[item] = item;
251
+ });
252
+ SourceMappings.call(this, visualization, newMappings);
253
+ this.init();
254
+ }
255
+ LineMappings.prototype = Object.create(SourceMappings.prototype);
256
+
257
+ function TableMappings(this: any, visualization, mappings) {
258
+ const newMappings = {};
259
+ for (const key in mappings) {
260
+ mappings[key].forEach(function (mapingItem, idx) {
261
+ newMappings[visualization.label[idx]] = mapingItem;
262
+ });
263
+ }
264
+ SourceMappings.call(this, visualization, newMappings);
265
+ this.init();
266
+ }
267
+ TableMappings.prototype = Object.create(SourceMappings.prototype);
268
+
269
+ TableMappings.prototype.init = function () {
270
+ this.visualization.label.forEach((label, idx) => {
271
+ this.reverseMappings[this.mappings[label]] = label;
272
+ this.columns.push(label);
273
+ this.columnsIdx[label] = idx;
274
+ this.columnsRHS[idx] = this.mappings[label];
275
+ this.columnsRHSIdx[this.mappings[label]] = idx;
276
+ this.hasMappings = true;
277
+ });
278
+ };
279
+
280
+ TableMappings.prototype.doMapAll = function (data) {
281
+ let retVal = SourceMappings.prototype.doMapAll.apply(this, arguments);
282
+ if (retVal instanceof Array) {
283
+ const columnsRHSIdx = this.visualization.source.getColumnsRHSIdx();
284
+ this.visualization.fields().forEach(field => {
285
+ const fieldType = field.jsType();
286
+ const colIdx = columnsRHSIdx[field.id()];
287
+ if (colIdx === undefined) {
288
+ console.warn("Invalid Mapping: " + field.id());
289
+ } else {
290
+ retVal = retVal.map((row) => {
291
+ let cell = row[colIdx];
292
+ if (cell && cell.Row) {
293
+ cell = cell.Row;
294
+ }
295
+ if (cell instanceof Array) {
296
+ switch (fieldType) {
297
+ case "dataset":
298
+ const columns = [];
299
+ const columnsIdx = {};
300
+ const data2 = cell.map(function (row2, idx) {
301
+ const retVal2 = [];
302
+ retVal2.length = columns.length;
303
+ for (const key in row2) {
304
+ if (idx === 0) {
305
+ columnsIdx[key] = columns.length;
306
+ columns.push(key);
307
+ }
308
+ retVal2[columnsIdx[key]] = row2[key];
309
+ }
310
+ return retVal2;
311
+ });
312
+ const table = new Table()
313
+ .columns(columns)
314
+ .data(data2)
315
+ ;
316
+ row[colIdx] = table;
317
+ break;
318
+ case "widget":
319
+ const viz = this.visualization.vizDeclarations[field.localVisualizationID()];
320
+ const output = viz.source.getOutput();
321
+ const db = output.db;
322
+ output.setData(cell, []);
323
+ const widget = viz.widget;
324
+ const newWidget = new widget.constructor()
325
+ .showToolbar(false)
326
+ .chartType(widget.chartType())
327
+ .chartTypeDefaults(widget.chartTypeDefaults())
328
+ .columns(viz.source.getColumns())
329
+ .data(viz.source.getData())
330
+ ;
331
+ output.db = db;
332
+ row[colIdx] = newWidget;
333
+ break;
334
+ }
335
+ }
336
+ return row;
337
+ });
338
+ }
339
+ });
340
+ }
341
+ return retVal;
342
+ };
343
+
344
+ function GraphMappings(this: any, visualization, mappings, link) {
345
+ SourceMappings.call(this, visualization, mappings);
346
+ this.icon = visualization.icon || {};
347
+ this.fields = visualization.fields();
348
+ this.columns = ["uid", "label", "weight", "flags"];
349
+ this.columnsIdx = { uid: 0, label: 1, weight: 2, flags: 3 };
350
+ this.init();
351
+ this.link = link;
352
+ this.linkMappings = new SourceMappings(visualization, this.link.mappings);
353
+ this.linkMappings.columns = ["uid"];
354
+ this.linkMappings.columnsIdx = { uid: 0, label: 1 };
355
+ this.visualization = visualization;
356
+ }
357
+ GraphMappings.prototype = Object.create(SourceMappings.prototype);
358
+
359
+ GraphMappings.prototype.calcIconInfo = function (flag, origItem, forAnnotation) {
360
+ const retVal = {};
361
+ function mapStruct(struct, retVal2) {
362
+ if (struct) {
363
+ for (const key in struct) {
364
+ switch (key) {
365
+ case "faChar":
366
+ retVal2.faChar = faCharFix(struct.faChar);
367
+ break;
368
+ default:
369
+ if (forAnnotation && key.indexOf("icon_") === 0) { // Backward compatability
370
+ console.warn("Deprecated flag property: " + key);
371
+ retVal2[key.split("icon_")[1]] = struct[key];
372
+ } else {
373
+ retVal2[key] = struct[key];
374
+ }
375
+ }
376
+ }
377
+ }
378
+ }
379
+ if (origItem && origItem[flag.fieldid] && flag.valuemappings) {
380
+ const annotationInfo = flag.valuemappings[origItem[flag.fieldid]];
381
+ mapStruct(annotationInfo, retVal);
382
+ }
383
+
384
+ for (const _key in retVal) { // jshint ignore:line
385
+ return retVal;
386
+ }
387
+ return null;
388
+ };
389
+
390
+ GraphMappings.prototype.doMapAll = function (db) {
391
+ const data = db.jsonObj();
392
+ const context = this;
393
+ const vertexMap = {};
394
+ const vertices = [];
395
+ const megaChart = this.visualization.widget;
396
+ const graph = megaChart.chart();
397
+ function getVertex(item, origItem?) {
398
+ const id = "uid_" + item[0];
399
+ let retVal = vertexMap[id];
400
+ if (!retVal && origItem) {
401
+ retVal = new graph.Vertex()
402
+ .faChar((context.icon && context.icon.faChar ? faCharFix(context.icon.faChar) : "\uf128"))
403
+ .text(item[1] ? item[1] : "")
404
+ .data(item)
405
+ ;
406
+ retVal.__hpcc_uid = item[0];
407
+ vertexMap[id] = retVal;
408
+ vertices.push(retVal);
409
+
410
+ // Icon ---
411
+ const iconInfo = context.calcIconInfo(context.visualization.icon, origItem, false);
412
+ if (iconInfo) {
413
+ for (const key in iconInfo) {
414
+ if (retVal[key]) {
415
+ retVal[key](iconInfo[key]);
416
+ }
417
+ }
418
+ }
419
+
420
+ // Annotations ---
421
+ const annotations = [];
422
+ context.visualization.flags.forEach(function (flag) {
423
+ const iconInfo2 = context.calcIconInfo(flag, origItem, true);
424
+ if (iconInfo2) {
425
+ annotations.push(iconInfo2);
426
+ }
427
+ });
428
+ retVal.annotationIcons(annotations);
429
+ }
430
+ return retVal;
431
+ }
432
+ const edges = [];
433
+ data.forEach(function (item) {
434
+ const mappedItem = context.doMap(item);
435
+ getVertex(mappedItem, item);
436
+ });
437
+ data.forEach(function (item) {
438
+ const mappedItem = context.doMap(item);
439
+ const vertex = getVertex(mappedItem, item);
440
+ if (item[context.link.childfile] && item[context.link.childfile] instanceof Array) {
441
+ const childItems = item[context.link.childfile];
442
+ childItems.forEach(function (childItem, i) {
443
+ const childMappedItem = context.linkMappings.doMap(childItem);
444
+ const childVertex = getVertex(childMappedItem);
445
+ if (childVertex && vertex.id() !== childVertex.id()) {
446
+ const edge = new graph.Edge()
447
+ .sourceVertex(vertex)
448
+ .targetVertex(childVertex)
449
+ .sourceMarker("circle")
450
+ .targetMarker("arrow")
451
+ .text(childMappedItem[1] ? childMappedItem[1] : "")
452
+ .data(childMappedItem)
453
+ ;
454
+ const linkcolor = graph.linkcolor_default();
455
+ if (linkcolor && linkcolor.fieldid) {
456
+ edge.strokeColor(childItem[linkcolor.fieldid]);
457
+ }
458
+ const linktooltip = graph.linkcolor_default();
459
+ if (linktooltip && linktooltip.fieldid) {
460
+ edge.tooltip(childItem[linktooltip.fieldid]);
461
+ }
462
+ edges.push(edge);
463
+ }
464
+ });
465
+ }
466
+ });
467
+ return { vertices, edges, merge: false };
468
+ };
469
+
470
+ // Viz Source ---
471
+ function Source(this: any, visualization, source) {
472
+ this.visualization = visualization;
473
+ if (source) {
474
+ this._id = source.id;
475
+ this._output = source.output;
476
+ this.mappings = null;
477
+ if (!source.mappings) {
478
+ console.warn("no mappings for:" + visualization.id + "->" + source.id);
479
+ }
480
+ switch (this.visualization.type) {
481
+ case "LINE":
482
+ this.mappings = new LineMappings(this.visualization, source.mappings);
483
+ break;
484
+ case "TABLE":
485
+ this.mappings = new TableMappings(this.visualization, source.mappings);
486
+ break;
487
+ case "GRAPH":
488
+ this.mappings = new GraphMappings(this.visualization, source.mappings, source.link);
489
+ break;
490
+ case "CHORO":
491
+ if (source.mappings.weight instanceof Array && source.mappings.weight.length) {
492
+ this.mappings = new ChoroMappings2(this.visualization, source.mappings);
493
+ if (source.mappings.weight.length > 1) {
494
+ this.visualization.type = "LINE";
495
+ }
496
+ } else {
497
+ this.mappings = new ChoroMappings(this.visualization, source.mappings);
498
+ }
499
+ break;
500
+ case "HEAT_MAP":
501
+ this.mappings = new HeatMapMappings(this.visualization, source.mappings);
502
+ break;
503
+ default:
504
+ this.mappings = new ChartMappings(this.visualization, source.mappings);
505
+ break;
506
+ }
507
+ this.first = source.first;
508
+ this.reverse = source.reverse;
509
+ this.sort = source.sort;
510
+ this.properties = source.properties;
511
+ }
512
+ }
513
+
514
+ Source.prototype.getQualifiedID = function () {
515
+ return this.visualization.getQualifiedID() + "." + this._id;
516
+ };
517
+
518
+ Source.prototype.exists = function () {
519
+ return this._id;
520
+ };
521
+
522
+ Source.prototype.getDatasource = function () {
523
+ return this.visualization.dashboard.getDatasource(this._id);
524
+ };
525
+
526
+ Source.prototype.getOutput = function () {
527
+ const datasource = this.getDatasource();
528
+ if (datasource && datasource._outputs) {
529
+ return datasource._outputs[this._output];
530
+ }
531
+ return null;
532
+ };
533
+
534
+ Source.prototype.hasData = function () {
535
+ return this.getOutput().db ? true : false;
536
+ };
537
+
538
+ Source.prototype.getFields = function () {
539
+ return this.mappings.getFields();
540
+ };
541
+
542
+ Source.prototype.getColumnsRHS = function () {
543
+ return this.mappings.columnsRHS;
544
+ };
545
+
546
+ Source.prototype.getColumnsRHSIdx = function () {
547
+ return this.mappings.columnsRHSIdx;
548
+ };
549
+
550
+ Source.prototype.getColumns = function () {
551
+ return this.mappings && this.mappings.columns ? this.mappings.columns : [];
552
+ };
553
+
554
+ Source.prototype.getData = function () {
555
+ const db = this.getOutput().db;
556
+ const retVal = this.mappings.doMapAll(db);
557
+ if (retVal.length && this.sort) {
558
+ Utility.multiSort(retVal, this.mappings.hipieMapSortArray(this.sort));
559
+ }
560
+ if (this.reverse) {
561
+ retVal.reverse();
562
+ }
563
+ if (this.first && retVal.length > this.first) {
564
+ retVal.length = this.first;
565
+ }
566
+ return retVal;
567
+ };
568
+
569
+ Source.prototype.getXTitle = function () {
570
+ return this.mappings.columns[0];
571
+ };
572
+
573
+ Source.prototype.getYTitle = function () {
574
+ return this.mappings.columns.filter(function (d, i) { return i > 0; }).join(" / ");
575
+ };
576
+
577
+ Source.prototype.getMap = function (col) {
578
+ return (this.mappings && this.mappings.hasMappings) ? this.mappings.getMap(col) : col;
579
+ };
580
+
581
+ Source.prototype.getReverseMap = function (col) {
582
+ return (this.mappings && this.mappings.hasMappings) ? this.mappings.getReverseMap(col) : col;
583
+ };
584
+
585
+ // Viz Events ---
586
+ function EventUpdate(this: any, event, update, defMappings) {
587
+ this.event = event;
588
+ this.dashboard = event.visualization.dashboard;
589
+ this._col = update.col;
590
+ this._visualization = update.visualization;
591
+ this._instance = update.instance;
592
+ this._datasource = update.datasource;
593
+ this._merge = update.merge;
594
+ this._mappings = update.mappings || defMappings;
595
+ }
596
+
597
+ EventUpdate.prototype.getDatasource = function () {
598
+ return this.dashboard.getDatasource(this._datasource);
599
+ };
600
+
601
+ EventUpdate.prototype.getVisualization = function () {
602
+ return this.dashboard.getVisualization(this._visualization);
603
+ };
604
+
605
+ EventUpdate.prototype.mapData = function (row) {
606
+ const retVal = {};
607
+ if (row) {
608
+ for (const key in this._mappings) {
609
+ const origKey = this.getReverseMap(key);
610
+ retVal[this._mappings[key]] = row[origKey];
611
+ }
612
+ }
613
+ return retVal;
614
+ };
615
+
616
+ EventUpdate.prototype.getMap = function (col) {
617
+ return this.event.visualization.source.getMap(col);
618
+ };
619
+
620
+ EventUpdate.prototype.getReverseMap = function (col) {
621
+ return this.event.visualization.source.getReverseMap(col);
622
+ };
623
+
624
+ EventUpdate.prototype.selectedRow = function () {
625
+ if (this.event.visualization.hasSelection()) {
626
+ return this.event.visualization._widgetState.row;
627
+ }
628
+ return {};
629
+ };
630
+
631
+ EventUpdate.prototype.mapSelected = function () {
632
+ return this.mapData(this.selectedRow());
633
+ };
634
+
635
+ EventUpdate.prototype.calcRequestFor = function (visualization) {
636
+ const retVal = {};
637
+ const updateVisualization = this.getVisualization();
638
+ updateVisualization.getInputVisualizations().forEach(function (inViz, idx) {
639
+ // Calc request for each visualization to be updated ---
640
+ const changed = inViz === visualization;
641
+ inViz.getUpdatesForVisualization(updateVisualization).forEach(function (inVizUpdateObj) {
642
+ // Gather all contributing "input visualization events" for the visualization that is to be updated ---
643
+ const inVizRequest = inVizUpdateObj.mapSelected();
644
+ for (const key in inVizRequest) {
645
+ if (retVal[key] && retVal[key] !== inVizRequest[key]) {
646
+ console.warn("Duplicate Filter with mismatched value (defaulting to 'first' or 'first changed' instance): " + key);
647
+ if (changed) {
648
+ retVal[key] = inVizRequest[key];
649
+ retVal[key + _CHANGED] = changed;
650
+ }
651
+ } else {
652
+ retVal[key] = inVizRequest[key];
653
+ retVal[key + _CHANGED] = changed;
654
+ }
655
+ }
656
+ });
657
+ });
658
+ return retVal;
659
+ };
660
+
661
+ function Event(this: any, visualization, eventID, event) {
662
+ this.visualization = visualization;
663
+ this.eventID = eventID;
664
+ this._updates = [];
665
+ this._mappings = event.mappings;
666
+ if (event) {
667
+ this._updates = event.updates.map(updateInfo => {
668
+ return new EventUpdate(this, updateInfo, event.mappings);
669
+ });
670
+ }
671
+ }
672
+
673
+ Event.prototype.exists = function () {
674
+ return this._updates.length;
675
+ };
676
+
677
+ Event.prototype.getUpdates = function () {
678
+ return this._updates.filter(updateInfo => {
679
+ if (!updateInfo._col) return true;
680
+ return updateInfo._col === updateInfo.getMap(this.visualization._widgetState.col);
681
+ });
682
+ };
683
+
684
+ Event.prototype.getUpdatesDatasources = function () {
685
+ const dedup = {};
686
+ const retVal = [];
687
+ this.getUpdatesVisualizations().forEach(function (item, idx) {
688
+ const datasource = item.source.getDatasource();
689
+ if (datasource && !dedup[datasource.id]) {
690
+ dedup[datasource.id] = true;
691
+ retVal.push(datasource);
692
+ }
693
+ }, this);
694
+ return retVal;
695
+ };
696
+
697
+ Event.prototype.getUpdatesVisualizations = function () {
698
+ const dedup = {};
699
+ const retVal = [];
700
+ this._updates.forEach(function (updateObj, idx) {
701
+ const visualization = updateObj.getVisualization();
702
+ if (!dedup[visualization.id]) {
703
+ dedup[visualization.id] = true;
704
+ retVal.push(visualization);
705
+ }
706
+ }, this);
707
+ return retVal;
708
+ };
709
+
710
+ Event.prototype.fetchData = function () {
711
+ const fetchDataOptimizer = new VisualizationRequestOptimizer();
712
+ this.getUpdates().forEach(updateObj => {
713
+ fetchDataOptimizer.appendRequest(updateObj.getDatasource(), updateObj.calcRequestFor(this.visualization), updateObj.getVisualization());
714
+ });
715
+ return fetchDataOptimizer.fetchData();
716
+ };
717
+
718
+ function Events(this: any, visualization, events) {
719
+ this.visualization = visualization;
720
+ this.events = {};
721
+ for (const key in events) {
722
+ this.events[key] = new Event(visualization, key, events[key]);
723
+ }
724
+ }
725
+
726
+ Events.prototype.setWidget = function (widget) {
727
+ const context = this;
728
+ for (const key in this.events) {
729
+ if (widget["vertex_" + key]) {
730
+ widget["vertex_" + key] = function (row, col, selected) {
731
+ context.visualization.processEvent(key, context.events[key], row, col, selected);
732
+ };
733
+ }
734
+ if (widget[key]) {
735
+ widget[key] = function (row, col, selected) {
736
+ context.visualization.processEvent(key, context.events[key], row, col, selected);
737
+ };
738
+ }
739
+ }
740
+ };
741
+
742
+ Events.prototype.exists = function () {
743
+ return this._updates !== undefined;
744
+ };
745
+
746
+ Events.prototype.getUpdates = function () {
747
+ let retVal = [];
748
+ for (const key in this.events) {
749
+ retVal = retVal.concat(this.events[key].getUpdates());
750
+ }
751
+ return retVal;
752
+ };
753
+
754
+ Events.prototype.getUpdatesDatasources = function () {
755
+ let retVal = [];
756
+ for (const key in this.events) {
757
+ retVal = retVal.concat(this.events[key].getUpdatesDatasources());
758
+ }
759
+ return retVal;
760
+ };
761
+
762
+ Events.prototype.getUpdatesVisualizations = function () {
763
+ let retVal = [];
764
+ for (const key in this.events) {
765
+ retVal = retVal.concat(this.events[key].getUpdatesVisualizations());
766
+ }
767
+ return retVal;
768
+ };
769
+
770
+ // Visualization Field---
771
+ function Field(this: any, ddlField) {
772
+ this._id = ddlField.id;
773
+ this._label = ddlField.label;
774
+ this._properties = ddlField.properties || {};
775
+ }
776
+ Field.prototype = Object.create(Class.prototype);
777
+ Field.prototype.constructor = Field;
778
+
779
+ Field.prototype.id = function () {
780
+ return this._id;
781
+ };
782
+
783
+ Field.prototype.label = function () {
784
+ return this._properties.label || this._label;
785
+ };
786
+
787
+ Field.prototype.type = function () {
788
+ return this._properties.type || "";
789
+ };
790
+
791
+ Field.prototype.jsType = function () {
792
+ return hipieType2DBType(this.type());
793
+ };
794
+
795
+ Field.prototype.charttype = function (_) {
796
+ if (!arguments.length) return this._properties.charttype || "";
797
+ this._properties.charttype = _;
798
+ return this;
799
+ };
800
+
801
+ Field.prototype.localVisualizationID = function () {
802
+ return this._properties.localVisualizationID || "";
803
+ };
804
+
805
+ Field.prototype.enumvals = function () {
806
+ return this._properties.enumvals; // Return undefined if non existent
807
+ };
808
+
809
+ Field.prototype.hasDefault = function () {
810
+ return this.default() !== undefined;
811
+ };
812
+
813
+ Field.prototype.default = function () {
814
+ if (this.type() === "range") {
815
+ return this._properties.default || ["", ""];
816
+ }
817
+ if (this._properties.default instanceof Array && this._properties.default.length) {
818
+ return this._properties.default[0];
819
+ }
820
+ return this._properties.default || "";
821
+ };
822
+
823
+ Field.prototype.hasFunction = function () {
824
+ return this.function() !== undefined;
825
+ };
826
+
827
+ Field.prototype.function = function () {
828
+ return this._properties.function;
829
+ };
830
+
831
+ Field.prototype.params = function () {
832
+ const retVal = [];
833
+ const params = this._properties.params || {};
834
+ for (const key in params) {
835
+ retVal.push(params[key]);
836
+ }
837
+ return retVal;
838
+ };
839
+
840
+ Field.prototype.properties = function () {
841
+ return this._properties;
842
+ };
843
+
844
+ // Visualization ---
845
+ function requirePromise(this: any, packageID) {
846
+ return new Promise((resolve, reject) => {
847
+ if (require) {
848
+ require([packageID], Package => {
849
+ resolve.call(this, Package);
850
+ });
851
+ } else {
852
+ reject("No require.");
853
+ }
854
+ });
855
+ }
856
+
857
+ function legacyRequire(this: any, packageArr, callback) {
858
+ const promises = packageArr.map(function (packageID) {
859
+ if (packageID.indexOf("../") === 0) {
860
+ const parts = packageID.split("/");
861
+ return requirePromise("@hpcc-js/" + parts[1]).then(function (Package) {
862
+ return Package[parts[2]];
863
+ });
864
+ }
865
+ return requirePromise(packageID);
866
+ });
867
+ Promise.all(promises).then(packages => {
868
+ callback.apply(this, packages);
869
+ });
870
+ }
871
+
872
+ export class Visualization extends Class {
873
+ protected dashboard;
874
+ parentVisualization;
875
+ protected type;
876
+ protected id;
877
+ protected label;
878
+ protected icon;
879
+ protected flags;
880
+ protected title;
881
+ protected _fields;
882
+ protected _fieldsMap;
883
+ properties;
884
+ protected source;
885
+ protected events;
886
+ protected layers;
887
+ protected hasVizDeclarations;
888
+ protected vizDeclarations;
889
+ widget;
890
+ protected _widgetState;
891
+
892
+ constructor(dashboard, visualization, parentVisualization) {
893
+ super();
894
+
895
+ this.dashboard = dashboard;
896
+ this.parentVisualization = parentVisualization;
897
+ this.type = visualization.type;
898
+ this.id = visualization.id;
899
+
900
+ switch (this.type) {
901
+ case "TABLE":
902
+ this.label = (visualization).label;
903
+ break;
904
+ case "GRAPH":
905
+ this.label = (visualization).label;
906
+ this.icon = (visualization).icon || { faChar: "\uf128" };
907
+ this.flags = (visualization).flag || [];
908
+ break;
909
+ }
910
+ this.title = visualization.title || visualization.id;
911
+ this._fields = (visualization.fields || []).map(function (field) {
912
+ return new Field(field);
913
+ });
914
+ this._fieldsMap = {};
915
+ this._fields.forEach(field => {
916
+ this._fieldsMap[field.id()] = field;
917
+ });
918
+
919
+ this.properties = visualization.properties || (visualization.source ? visualization.source.properties : null) || {};
920
+ this.source = new Source(this, visualization.source);
921
+ this.events = new Events(this, visualization.events);
922
+ this.layers = [];
923
+ this.hasVizDeclarations = false;
924
+ this.vizDeclarations = {};
925
+ if (this.type === "CHORO") {
926
+ this.layers = (visualization.visualizations || []).map(innerViz => {
927
+ return dashboard.createVisualization(innerViz, this);
928
+ });
929
+ } else {
930
+ (visualization.visualizations || []).forEach(innerViz => {
931
+ this.vizDeclarations[innerViz.id] = dashboard.createVisualization(innerViz, this);
932
+ this.hasVizDeclarations = true;
933
+ });
934
+ }
935
+ const context = this;
936
+ switch (this.type) {
937
+ case "CHORO":
938
+ let chartType = visualization.properties && visualization.properties.charttype ? visualization.properties.charttype : "";
939
+ if (parentVisualization) {
940
+ switch (chartType) {
941
+ case "MAP_PINS":
942
+ this.loadWidget("../map/Pins", function (widget) {
943
+ try {
944
+ widget
945
+ .id(visualization.id)
946
+ .columns(context.source.getColumns())
947
+ .geohashColumn("geohash")
948
+ .tooltipColumn("label")
949
+ .fillColor(visualization.color ? visualization.color : null)
950
+ .projection("albersUsaPr")
951
+ ;
952
+ } catch (e) {
953
+ console.warn("Unexpected widget type: " + widget.classID());
954
+ }
955
+ });
956
+ break;
957
+ }
958
+ } else {
959
+ chartType = chartType || "CHORO";
960
+ if (chartType === "CHORO") {
961
+ if (this.source.mappings.contains("state")) {
962
+ chartType = "CHORO_USSTATES";
963
+ } else if (this.source.mappings.contains("county")) {
964
+ chartType = "CHORO_USCOUNTIES";
965
+ } else if (this.source.mappings.contains("country")) {
966
+ chartType = "CHORO_COUNTRIES";
967
+ }
968
+ }
969
+ Promise.all(context.layers.map(function (layer) { return layer.loadedPromise(); })).then(function () {
970
+ context.loadWidget("../composite/MegaChart", function (widget) {
971
+ const layers = context.layers.map(function (layer) { return layer.widget; });
972
+ try {
973
+ switch (widget.classID()) {
974
+ case "composite_MegaChart":
975
+ widget
976
+ .id(visualization.id)
977
+ .showChartSelect_default(false)
978
+ .chartType_default(chartType)
979
+ .chartTypeDefaults({
980
+ autoScaleMode: layers.length ? "data" : "mesh"
981
+ })
982
+ .chartTypeProperties({
983
+ layers
984
+ })
985
+ ;
986
+ break;
987
+ default:
988
+ widget
989
+ .id(visualization.id)
990
+ .autoScaleMode(layers.length ? "data" : "mesh")
991
+ .layers(layers)
992
+ ;
993
+ break;
994
+ }
995
+ } catch (e) {
996
+ console.warn("Unexpected widget type: " + widget.classID());
997
+ }
998
+ });
999
+ });
1000
+ }
1001
+ break;
1002
+ case "2DCHART":
1003
+ case "PIE":
1004
+ case "BUBBLE":
1005
+ case "BAR":
1006
+ case "WORD_CLOUD":
1007
+ this.loadWidget("../composite/MegaChart", function (widget) {
1008
+ try {
1009
+ widget
1010
+ .id(visualization.id)
1011
+ .chartType_default(context.properties.chartType || context.properties.charttype || context.type)
1012
+ ;
1013
+ } catch (e) {
1014
+ console.warn("Unexpected widget type: " + widget.classID());
1015
+ }
1016
+ });
1017
+ break;
1018
+ case "LINE":
1019
+ this.loadWidget("../composite/MegaChart", function (widget) {
1020
+ try {
1021
+ widget
1022
+ .id(visualization.id)
1023
+ .chartType_default(context.properties.chartType || context.properties.charttype || context.type)
1024
+ ;
1025
+ } catch (e) {
1026
+ console.warn("Unexpected widget type: " + widget.classID());
1027
+ }
1028
+ });
1029
+ break;
1030
+ case "TABLE":
1031
+ this.loadWidget("../composite/MegaChart", function (widget) {
1032
+ try {
1033
+ widget
1034
+ .id(visualization.id)
1035
+ .showChartSelect_default(false)
1036
+ .chartType_default("TABLE")
1037
+ ;
1038
+ } catch (e) {
1039
+ console.warn("Unexpected widget type: " + widget.classID());
1040
+ }
1041
+ });
1042
+ break;
1043
+ case "SLIDER":
1044
+ this.loadWidget("../form/Slider", function (widget) {
1045
+ try {
1046
+ widget
1047
+ .id(visualization.id)
1048
+ ;
1049
+ if (visualization.range) {
1050
+ let selectionLabel = "";
1051
+ if (Utility.exists("events.click.updates", visualization) && visualization.events.click.updates.length) {
1052
+ for (const key in visualization.events.click.updates[0].mappings) {
1053
+ selectionLabel = key;
1054
+ break;
1055
+ }
1056
+ }
1057
+ widget
1058
+ .low_default(+visualization.range[0])
1059
+ .high_default(+visualization.range[1])
1060
+ .step_default(+visualization.range[2])
1061
+ .selectionLabel_default(selectionLabel)
1062
+ .selectionLabel(selectionLabel)
1063
+ ;
1064
+ }
1065
+ } catch (e) {
1066
+ console.warn("Unexpected widget type: " + widget.classID());
1067
+ }
1068
+ });
1069
+ break;
1070
+ case "GRAPH":
1071
+ this.loadWidget("../composite/MegaChart", function (widget) {
1072
+ try {
1073
+ widget
1074
+ .id(visualization.id)
1075
+ .showChartSelect_default(false)
1076
+ .chartType_default("GRAPH")
1077
+ .chartTypeDefaults({
1078
+ layout: "ForceDirected2",
1079
+ applyScaleOnLayout: true
1080
+ })
1081
+ ;
1082
+ } catch (e) {
1083
+ console.warn("Unexpected widget type: " + widget.classID());
1084
+ }
1085
+ });
1086
+ break;
1087
+ case "FORM":
1088
+ this.loadWidgets(["../form/Form", "../form/Input", "../form/Button", "../form/CheckBox", "../form/ColorInput", "../form/Radio", "../form/Range", "../form/Select", "../form/Slider", "../form/TextArea", "../form/InputRange"], function (widget, widgetClasses) {
1089
+ const Input = widgetClasses[1];
1090
+ const CheckBox = widgetClasses[3];
1091
+ const Radio = widgetClasses[5];
1092
+ const Select = widgetClasses[7];
1093
+ const TextArea = widgetClasses[9];
1094
+ const InputRange = widgetClasses[10];
1095
+
1096
+ try {
1097
+ widget
1098
+ .id(visualization.id)
1099
+ .inputs(context.fields().map(function (field) {
1100
+
1101
+ const selectOptions = [];
1102
+ let options = [];
1103
+ let inp;
1104
+ if (!field.charttype() && field.type() === "range") {
1105
+ // TODO - Verify with @DL
1106
+ field.charttype("RANGE");
1107
+ }
1108
+ switch (field.charttype()) {
1109
+ case "TEXT":
1110
+ inp = new Input()
1111
+ .type_default("text")
1112
+ ;
1113
+ break;
1114
+ case "TEXTAREA":
1115
+ inp = new TextArea();
1116
+ break;
1117
+ case "CHECKBOX":
1118
+ inp = new CheckBox();
1119
+ break;
1120
+ case "RADIO":
1121
+ inp = new Radio();
1122
+ break;
1123
+ case "HIDDEN":
1124
+ inp = new Input()
1125
+ .type_default("hidden")
1126
+ ;
1127
+ break;
1128
+ case "RANGE":
1129
+ inp = new InputRange();
1130
+ break;
1131
+ default:
1132
+ if (field.enumvals()) {
1133
+ inp = new Select();
1134
+ options = field.enumvals();
1135
+ for (const val in options) {
1136
+ selectOptions.push([val, options[val]]);
1137
+ }
1138
+ } else {
1139
+ inp = new Input()
1140
+ .type_default("text")
1141
+ ;
1142
+ }
1143
+ break;
1144
+ }
1145
+
1146
+ inp
1147
+ .name_default(field.id())
1148
+ .label_default(field.label())
1149
+ .value_default(field.default()) // TODO Hippie support for multiple default values (checkbox only)
1150
+ ;
1151
+
1152
+ if (inp instanceof CheckBox || inp instanceof Radio) { // change this to instanceof?
1153
+ const vals = Object.keys(field.enumvals());
1154
+ inp.selectOptions_default(vals);
1155
+ } else if (selectOptions.length) {
1156
+ inp.selectOptions_default(selectOptions);
1157
+ }
1158
+
1159
+ return inp;
1160
+ }))
1161
+ ;
1162
+ } catch (e) {
1163
+ console.warn("Unexpected widget type: " + widget.classID());
1164
+ }
1165
+ });
1166
+ break;
1167
+ case "HEAT_MAP":
1168
+ this.loadWidgets(["../other/HeatMap"], function (widget) {
1169
+ try {
1170
+ widget
1171
+ .id(visualization.id)
1172
+ .image_default(context.properties.imageUrl)
1173
+ ;
1174
+ } catch (e) {
1175
+ console.warn("Unexpected widget type: " + widget.classID());
1176
+ }
1177
+ });
1178
+ break;
1179
+ default:
1180
+ this.loadWidget("../common/TextBox", function (widget) {
1181
+ try {
1182
+ widget
1183
+ .id(visualization.id)
1184
+ .text_default(context.id + "\n" + "TODO: " + context.type)
1185
+ ;
1186
+ } catch (e) {
1187
+ console.warn("Unexpected widget type: " + widget.classID());
1188
+ }
1189
+ });
1190
+ break;
1191
+ }
1192
+ }
1193
+
1194
+ getQualifiedID() {
1195
+ return this.id;
1196
+ }
1197
+
1198
+ fields() {
1199
+ return this._fields;
1200
+ }
1201
+
1202
+ hasField(id) {
1203
+ return this.field[id] !== undefined;
1204
+ }
1205
+
1206
+ field(id) {
1207
+ return this._fieldsMap[id];
1208
+ }
1209
+
1210
+ loadedPromise() {
1211
+ const context = this;
1212
+ return new Promise<void>(function (resolve, reject) {
1213
+ const intervalHandle = setInterval(function () {
1214
+ if (context.isLoaded()) {
1215
+ clearInterval(intervalHandle);
1216
+ resolve();
1217
+ }
1218
+ }, 100);
1219
+ });
1220
+ }
1221
+
1222
+ isLoading() {
1223
+ return this.widget === null;
1224
+ }
1225
+
1226
+ isLoaded() {
1227
+ return this.widget instanceof Widget;
1228
+ }
1229
+
1230
+ loadMegaChartWidget(widgetPath, callback) {
1231
+ this.loadWidgets(["../composite/MegaChart", widgetPath], function (megaChart, widgets) {
1232
+ const chart = new widgets[1]();
1233
+ megaChart
1234
+ .chartType_default(MultiChart.prototype._allChartTypesByClass[chart.classID()].id)
1235
+ .chart(chart)
1236
+ ;
1237
+ if (callback) {
1238
+ callback(megaChart, chart, widgets);
1239
+ }
1240
+ });
1241
+ }
1242
+
1243
+ loadWidget(widgetPath, callback) {
1244
+ this.loadWidgets([widgetPath], callback);
1245
+ }
1246
+
1247
+ loadWidgets(widgetPaths, callback) {
1248
+ this.widget = null;
1249
+
1250
+ const context = this;
1251
+ legacyRequire(widgetPaths, function (WidgetClass) {
1252
+ const existingWidget = context.dashboard.marshaller.getWidget(context.id);
1253
+ if (existingWidget) {
1254
+ if (WidgetClass.prototype._class !== existingWidget.classID()) {
1255
+ console.warn("Unexpected persisted widget type (old persist string?)");
1256
+ }
1257
+ context.setWidget(existingWidget);
1258
+ } else {
1259
+ context.setWidget(new WidgetClass());
1260
+ }
1261
+ if (callback) {
1262
+ callback(context.widget, arguments);
1263
+ }
1264
+ });
1265
+ }
1266
+
1267
+ setWidget(widget) {
1268
+ this.widget = widget;
1269
+ this.events.setWidget(widget);
1270
+ if (this.widget.columns) {
1271
+ const columns = this.source.getColumns();
1272
+ this.widget.columns(columns, true);
1273
+ }
1274
+ for (const key in this.properties) {
1275
+ switch (widget.classID()) {
1276
+ case "chart_MultiChart":
1277
+ case "composite_MegaChart":
1278
+ if (widget[key + "_default"]) {
1279
+ widget[key + "_default"](this.properties[key]);
1280
+ }
1281
+ widget.chartTypeDefaults()[key] = this.properties[key];
1282
+ break;
1283
+ default:
1284
+ if (this.widget[key + "_default"]) {
1285
+ try {
1286
+ this.widget[key + "_default"](this.properties[key]);
1287
+ } catch (e) {
1288
+ console.warn("Invalid Property:" + this.id + ".properties." + key);
1289
+ }
1290
+ }
1291
+ }
1292
+ }
1293
+ return this.widget;
1294
+ }
1295
+
1296
+ accept(visitor) {
1297
+ visitor.visit(this);
1298
+ }
1299
+
1300
+ getUpdates() {
1301
+ return this.events.getUpdates();
1302
+ }
1303
+
1304
+ getUpdatesForDatasource(otherDatasource) {
1305
+ return this.events.getUpdates().filter(function (updateObj) {
1306
+ return updateObj.getDatasource() === otherDatasource;
1307
+ });
1308
+ }
1309
+
1310
+ getUpdatesForVisualization(otherViz) {
1311
+ return this.events.getUpdates().filter(function (updateObj) {
1312
+ return updateObj.getVisualization() === otherViz;
1313
+ });
1314
+ }
1315
+
1316
+ getInputFields(mapped?): any {
1317
+ const retVal = {};
1318
+ const updatedBy = this.getInputVisualizations();
1319
+ updatedBy.forEach(viz => {
1320
+ if (viz.hasSelection()) {
1321
+ viz.getUpdatesForVisualization(this).forEach(function (updateObj) {
1322
+ const sel = mapped ? updateObj.mapSelected() : updateObj.selectedRow();
1323
+ for (const key in sel) {
1324
+ retVal[key] = sel[key];
1325
+ }
1326
+ });
1327
+ }
1328
+ });
1329
+ return retVal;
1330
+ }
1331
+
1332
+ update(params?) {
1333
+ let titleWidget = null;
1334
+ if (!this.parentVisualization) {
1335
+ titleWidget = this.widget;
1336
+ while (titleWidget && !titleWidget.title) {
1337
+ titleWidget = titleWidget.locateParentWidget();
1338
+ }
1339
+ }
1340
+
1341
+ if (!params) {
1342
+ params = "";
1343
+ let titleFormatStr = "";
1344
+ if (titleWidget && titleWidget.ddlParamsFormat) {
1345
+ titleFormatStr = titleWidget.ddlParamsFormat();
1346
+ }
1347
+
1348
+ const dedupParams = {};
1349
+ if (titleFormatStr) {
1350
+ params = Utility.template(titleFormatStr, this.getInputFields());
1351
+ } else {
1352
+ const paramsArr = [];
1353
+ const mappedData = this.getInputFields(true);
1354
+ for (const key in mappedData) {
1355
+ if (mappedData[key]) {
1356
+ if (!dedupParams[key]) {
1357
+ dedupParams[key] = true;
1358
+ paramsArr.push(mappedData[key]);
1359
+ }
1360
+ }
1361
+ }
1362
+ params = paramsArr.join(", ");
1363
+ }
1364
+ }
1365
+
1366
+ const context = this;
1367
+ return new Promise<void>(function (resolve, reject) {
1368
+ if (titleWidget) {
1369
+ const title = titleWidget.title();
1370
+ const titleParts = title.split(" (");
1371
+ titleWidget
1372
+ .title(titleParts[0] + (params.trim() ? " (" + params + ")" : ""))
1373
+ .render(function () {
1374
+ resolve();
1375
+ })
1376
+ ;
1377
+ } else {
1378
+ let ddlViz = context;
1379
+ while (ddlViz.parentVisualization) {
1380
+ ddlViz = ddlViz.parentVisualization;
1381
+ }
1382
+ ddlViz.widget.render(function () {
1383
+ resolve();
1384
+ });
1385
+ }
1386
+ if (context.dashboard.marshaller.propogateClear()) {
1387
+ context.events.getUpdatesVisualizations().forEach(function (updatedViz) {
1388
+ updatedViz.update();
1389
+ });
1390
+ }
1391
+ });
1392
+ }
1393
+
1394
+ notify() {
1395
+ if (this.widget) {
1396
+ const data = this.source.hasData() ? this.source.getData() : [];
1397
+ this.widget.data(data);
1398
+ if (this.type === "GRAPH" && data.vertices) {
1399
+ const ipFields = this.getInputFields(true);
1400
+ data.vertices.filter(function (v) {
1401
+ return v.__hpcc_uid === ipFields.treeuid;
1402
+ }).forEach(function (v) {
1403
+ v.centroid(true);
1404
+ });
1405
+ }
1406
+ return this.update();
1407
+ }
1408
+ return Promise.resolve();
1409
+ }
1410
+
1411
+ clear() {
1412
+ this._widgetState = {
1413
+ row: {},
1414
+ selected: false
1415
+ };
1416
+ this.fields().forEach(field => {
1417
+ if (field.hasDefault()) {
1418
+ this._widgetState.row[field.id()] = field.default();
1419
+ this._widgetState.selected = true;
1420
+ }
1421
+ });
1422
+ if (this.widget && this.dashboard.marshaller.clearDataOnUpdate()) {
1423
+ this.widget.data([]);
1424
+ }
1425
+ if (this.dashboard.marshaller.propogateClear()) {
1426
+ this.events.getUpdatesVisualizations().forEach(function (updatedViz) {
1427
+ updatedViz.clear();
1428
+ });
1429
+ }
1430
+ }
1431
+
1432
+ on(eventID, func) {
1433
+ const context = this;
1434
+ this.overrideMethod(eventID, function (origFunc, args) {
1435
+ origFunc.apply(context, args);
1436
+ setTimeout(function () {
1437
+ func.apply(context, args);
1438
+ }, 0);
1439
+ });
1440
+ return this;
1441
+ }
1442
+
1443
+ calcRequestFor(visualization) {
1444
+ let retVal = {};
1445
+ this.getUpdatesForVisualization(visualization).forEach(function (updatesObj) {
1446
+ // TODO: When we support more than "click" this will need enhancment...
1447
+ retVal = updatesObj.calcRequestFor(visualization);
1448
+ });
1449
+ return retVal;
1450
+ }
1451
+
1452
+ processEvent(eventID, event, row, col, selected) {
1453
+ this._widgetState = {
1454
+ row,
1455
+ col,
1456
+ selected: selected === undefined ? true : selected
1457
+ };
1458
+ const context = this;
1459
+ setTimeout(function () {
1460
+ event.fetchData().then(function (promises) {
1461
+ context.dashboard.marshaller.vizEvent(context.widget, "post_" + eventID, row, col, selected);
1462
+ });
1463
+ }, 0);
1464
+ }
1465
+
1466
+ hasSelection() {
1467
+ return this._widgetState && this._widgetState.selected;
1468
+ }
1469
+
1470
+ selection() {
1471
+ if (this.hasSelection()) {
1472
+ return this._widgetState.row;
1473
+ }
1474
+ return null;
1475
+ }
1476
+
1477
+ reverseMappedSelection() {
1478
+ if (this.hasSelection()) {
1479
+ return this.source.mappings ? this.source.mappings.doReverseMap(this._widgetState.row) : this._widgetState.row;
1480
+ }
1481
+ return null;
1482
+ }
1483
+
1484
+ getInputVisualizations() {
1485
+ return this.dashboard.marshaller.getVisualizationArray().filter(viz => {
1486
+ const updates = viz.events.getUpdatesVisualizations();
1487
+ if (updates.indexOf(this) >= 0) {
1488
+ return true;
1489
+ }
1490
+ return false;
1491
+ });
1492
+ }
1493
+
1494
+ serializeState() {
1495
+ const state: any = {
1496
+ widgetState: this._widgetState
1497
+ };
1498
+ if (this.widget) {
1499
+ if (this.widget.serializeState) {
1500
+ state.widget = this.widget.serializeState();
1501
+ } else if (this.widget.data) {
1502
+ state.widget = {
1503
+ data: this.widget.data()
1504
+ };
1505
+ }
1506
+ }
1507
+ return state;
1508
+ }
1509
+
1510
+ deserializeState(state) {
1511
+ if (state) {
1512
+ this._widgetState = state.widgetState;
1513
+ if (this.widget && state.widget) {
1514
+ if (this.widget.deserializeState) {
1515
+ this.widget.deserializeState(state.widget);
1516
+ } else if (this.widget.data && state.widget.data) {
1517
+ this.widget.data(state.widget.data);
1518
+ }
1519
+ }
1520
+ }
1521
+ return this;
1522
+ }
1523
+ }
1524
+
1525
+ // Output ---
1526
+ function Filter(this: any, datasource, ddlFilter: string | DDL1.IFilter) {
1527
+ this.datasource = datasource;
1528
+ if (typeof ddlFilter === "string") {
1529
+ ddlFilter = {
1530
+ fieldid: ddlFilter,
1531
+ nullable: true,
1532
+ rule: "=="
1533
+ };
1534
+ }
1535
+ this.fieldid = ddlFilter.fieldid;
1536
+ this.nullable = ddlFilter.nullable;
1537
+ this.rule = ddlFilter.rule || "==";
1538
+ this.minid = ddlFilter.minid;
1539
+ this.maxid = ddlFilter.maxid;
1540
+ this.calcRequestFieldID();
1541
+ }
1542
+
1543
+ Filter.prototype.calcRequestFieldID = function () {
1544
+ this._requestFieldID = this.fieldid;
1545
+ this._requestMinID = this.minid;
1546
+ this._requestMaxID = this.maxid;
1547
+ switch (this.rule) {
1548
+ case "<":
1549
+ case "<=":
1550
+ if (Utility.endsWith(this.fieldid, "-max")) {
1551
+ this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_max" : "");
1552
+ }
1553
+ break;
1554
+ case ">":
1555
+ case ">=":
1556
+ if (Utility.endsWith(this.fieldid, "-min")) {
1557
+ this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_min" : "");
1558
+ }
1559
+ break;
1560
+ case "set":
1561
+ if (Utility.endsWith(this.fieldid, "-set")) {
1562
+ this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_set" : "");
1563
+ }
1564
+ break;
1565
+ case "range":
1566
+ if (Utility.endsWith(this.minid, "-min")) {
1567
+ this._requestMinID = this.minid.substring(0, this.minid.length - 4) + (this.datasource.isRoxie() ? "_min" : "");
1568
+ }
1569
+ if (Utility.endsWith(this.maxid, "-max")) {
1570
+ this._requestMaxID = this.maxid.substring(0, this.maxid.length - 4) + (this.datasource.isRoxie() ? "_max" : "");
1571
+ }
1572
+ break;
1573
+ }
1574
+ };
1575
+
1576
+ Filter.prototype.isRange = function () {
1577
+ return this.rule === "range";
1578
+ };
1579
+
1580
+ Filter.prototype.isSet = function () {
1581
+ return this.rule === "set";
1582
+ };
1583
+
1584
+ Filter.prototype._calcRequest = function (filteredRequest, request, fieldid, requestFieldID, value) {
1585
+ if (!this.datasource.isRoxie()) {
1586
+ // Ignore requestFieldID, until filtering WU results
1587
+ // Otherwise there are many fieldID collisions
1588
+ requestFieldID = fieldid;
1589
+ }
1590
+ filteredRequest[requestFieldID + _CHANGED] = request[fieldid + _CHANGED] || false;
1591
+ if (filteredRequest[requestFieldID] !== value) {
1592
+ filteredRequest[requestFieldID] = value;
1593
+ }
1594
+ };
1595
+
1596
+ Filter.prototype.calcRequest = function (filteredRequest, request, fillInMissing) {
1597
+ if (!fillInMissing && request[this.fieldid] === undefined) {
1598
+ return;
1599
+ }
1600
+ const value = request[this.fieldid] === undefined ? null : request[this.fieldid];
1601
+ if (this.isRange()) {
1602
+ if (value instanceof Array && value.length === 2) {
1603
+ this._calcRequest(filteredRequest, request, this.minid, this._requestMinID, value[0]);
1604
+ this._calcRequest(filteredRequest, request, this.maxid, this._requestMaxID, value[1]);
1605
+ }
1606
+ } else {
1607
+ this._calcRequest(filteredRequest, request, this.fieldid, this._requestFieldID, value);
1608
+ if (this.isSet() && this.datasource.isRoxie()) {
1609
+ // TODO in the future the value should be an array ---
1610
+ filteredRequest[this._requestFieldID + ".Item$"] = filteredRequest[this._requestFieldID];
1611
+ delete filteredRequest[this._requestFieldID];
1612
+ }
1613
+ }
1614
+ };
1615
+
1616
+ Filter.prototype.matches = function (row, value): boolean {
1617
+ if (value === undefined || value === null || value === "") {
1618
+ return this.nullable;
1619
+ }
1620
+ let rowValue = row[this._requestFieldID];
1621
+ if (rowValue === undefined) {
1622
+ rowValue = row[this._requestFieldID.toLowerCase()];
1623
+ }
1624
+ if (rowValue === undefined) {
1625
+ console.warn("Empty cell value: '" + this._requestFieldID + "'");
1626
+ return false;
1627
+ }
1628
+ switch (this.rule) {
1629
+ case "<":
1630
+ if (rowValue.localeCompare) {
1631
+ return rowValue.localeCompare(value) < 0;
1632
+ }
1633
+ return rowValue < value;
1634
+ case ">":
1635
+ if (rowValue.localeCompare) {
1636
+ return rowValue.localeCompare(value) > 0;
1637
+ }
1638
+ return rowValue > value;
1639
+ case "<=":
1640
+ if (rowValue.localeCompare) {
1641
+ return rowValue.localeCompare(value) <= 0;
1642
+ }
1643
+ return rowValue <= value;
1644
+ case ">=":
1645
+ if (rowValue.localeCompare) {
1646
+ return rowValue.localeCompare(value) >= 0;
1647
+ }
1648
+ return rowValue >= value;
1649
+ case "!=":
1650
+ case "notequals":
1651
+ return rowValue != value; // jshint ignore:line
1652
+ case "set":
1653
+ if (value instanceof Array) {
1654
+ return value.indexOf(rowValue) >= 0;
1655
+ }
1656
+ return value == rowValue; // jshint ignore:line
1657
+ case "==":
1658
+ return value == rowValue; // jshint ignore:line
1659
+ default:
1660
+ console.warn("Unknown filter rule: '" + this.rule + "'");
1661
+ return value == rowValue; // jshint ignore:line
1662
+ }
1663
+ };
1664
+
1665
+ export class Output {
1666
+
1667
+ datasource;
1668
+ id;
1669
+ from;
1670
+ protected notify;
1671
+ filters;
1672
+ protected db;
1673
+
1674
+ constructor(datasource, output) {
1675
+ this.datasource = datasource;
1676
+ this.id = output.id;
1677
+ this.from = output.from;
1678
+ this.notify = output.notify || [];
1679
+ this.filters = (output.filter || []).map(filter => {
1680
+ return new Filter(this.datasource, filter);
1681
+ });
1682
+ }
1683
+
1684
+ getQualifiedID() {
1685
+ return this.datasource.getQualifiedID() + "." + this.id;
1686
+ }
1687
+
1688
+ getUpdatesVisualizations() {
1689
+ const retVal = [];
1690
+ this.notify.forEach(item => {
1691
+ retVal.push(this.datasource.marshaller.getVisualization(item));
1692
+ });
1693
+ return retVal;
1694
+ }
1695
+
1696
+ accept(visitor) {
1697
+ visitor.visit(this);
1698
+ }
1699
+
1700
+ vizNotify(updates) {
1701
+ const promises = [];
1702
+ this.notify.filter(function (item) {
1703
+ return !updates || updates.indexOf(item) >= 0;
1704
+ }).forEach(item => {
1705
+ const viz = this.datasource.marshaller.getVisualization(item);
1706
+ promises.push(viz.notify());
1707
+ });
1708
+ return Promise.all(promises);
1709
+ }
1710
+
1711
+ setData(data, updates) {
1712
+ this.db = new Database.Grid().jsonObj(data);
1713
+ return this.vizNotify(updates);
1714
+ }
1715
+ }
1716
+
1717
+ // FetchData Optimizers ---
1718
+ function DatasourceRequestOptimizer(this: any) {
1719
+ this.datasourceRequests = {
1720
+ };
1721
+ }
1722
+
1723
+ DatasourceRequestOptimizer.prototype.appendRequest = function (updateDatasource, request, updateVisualization) {
1724
+ const datasourceRequestID = updateDatasource.id + "(" + JSON.stringify(request) + ")";
1725
+ if (!this.datasourceRequests[datasourceRequestID]) {
1726
+ this.datasourceRequests[datasourceRequestID] = {
1727
+ updateDatasource,
1728
+ request,
1729
+ updates: []
1730
+ };
1731
+ } else if ((window as any).__hpcc_debug) {
1732
+ console.warn("Optimized duplicate fetch: " + datasourceRequestID);
1733
+ }
1734
+ const datasourceOptimizedItem = this.datasourceRequests[datasourceRequestID];
1735
+ if (datasourceOptimizedItem.updates.indexOf(updateVisualization.id) < 0) {
1736
+ datasourceOptimizedItem.updates.push(updateVisualization.id);
1737
+ }
1738
+ };
1739
+
1740
+ DatasourceRequestOptimizer.prototype.fetchData = function () {
1741
+ const promises = [];
1742
+ for (const key in this.datasourceRequests) {
1743
+ const item = this.datasourceRequests[key];
1744
+ promises.push(item.updateDatasource.fetchData(item.request, item.updates));
1745
+ }
1746
+ return Promise.all(promises);
1747
+ };
1748
+
1749
+ function VisualizationRequestOptimizer(this: any, skipClear?) {
1750
+ this.skipClear = skipClear;
1751
+ this.visualizationRequests = {
1752
+ };
1753
+ }
1754
+
1755
+ VisualizationRequestOptimizer.prototype.appendRequest = function (updateDatasource, request, updateVisualization) {
1756
+ if (updateDatasource && updateVisualization) {
1757
+ const visualizationRequestID = updateVisualization.id + "(" + updateDatasource.id + ")";
1758
+ if (!this.visualizationRequests[visualizationRequestID]) {
1759
+ this.visualizationRequests[visualizationRequestID] = {
1760
+ updateVisualization,
1761
+ updateDatasource,
1762
+ request: {}
1763
+ };
1764
+ } else if ((window as any).__hpcc_debug) {
1765
+ console.warn("Optimized duplicate fetch: " + visualizationRequestID);
1766
+ }
1767
+ const visualizationOptimizedItem = this.visualizationRequests[visualizationRequestID];
1768
+ Utility.mixin(visualizationOptimizedItem.request, request);
1769
+ }
1770
+ };
1771
+
1772
+ VisualizationRequestOptimizer.prototype.fetchData = function () {
1773
+ const datasourceRequestOptimizer = new DatasourceRequestOptimizer();
1774
+ for (const key in this.visualizationRequests) {
1775
+ const item = this.visualizationRequests[key];
1776
+ if (!this.skipClear && item.updateVisualization.type !== "GRAPH") {
1777
+ item.updateVisualization.clear();
1778
+ }
1779
+ item.updateVisualization.update(LOADING);
1780
+ datasourceRequestOptimizer.appendRequest(item.updateDatasource, item.request, item.updateVisualization);
1781
+ }
1782
+ return datasourceRequestOptimizer.fetchData();
1783
+ };
1784
+
1785
+ // Datasource ---
1786
+ let transactionID = 0;
1787
+ const transactionQueue = [];
1788
+ export class Datasource {
1789
+
1790
+ protected marshaller;
1791
+ id;
1792
+ protected WUID;
1793
+ protected URL;
1794
+ databomb;
1795
+ protected filters;
1796
+ protected _loadedCount;
1797
+ protected _outputs;
1798
+ protected _outputArray;
1799
+ comms;
1800
+ protected _loadedCount2;
1801
+ protected _loadedCount3;
1802
+ protected _loadedCount4;
1803
+
1804
+ constructor(marshaller, datasource: DDL1.IAnyDatasource, proxyMappings, timeout) {
1805
+ this.marshaller = marshaller;
1806
+ this.id = datasource.id;
1807
+ if (DDL1.isWorkunitDatasource(datasource)) {
1808
+ this.WUID = datasource.WUID;
1809
+ } else if (DDL1.isHipieDatasource(datasource)) {
1810
+ this.URL = (marshaller.espUrl && marshaller.espUrl.url()) ? marshaller.espUrl.url() : datasource.URL;
1811
+ } else if (DDL1.isDatabombDatasource(datasource)) {
1812
+ this.databomb = datasource.databomb;
1813
+ }
1814
+ this.filters = (datasource.filter || []).map(filter => {
1815
+ return new Filter(this, filter);
1816
+ });
1817
+ this._loadedCount = 0;
1818
+
1819
+ const context = this;
1820
+ this._outputs = {};
1821
+ this._outputArray = [];
1822
+ const hipieResults = [];
1823
+ datasource.outputs.forEach(item => {
1824
+ const output = new Output(context, item);
1825
+ context._outputs[item.id] = output;
1826
+ context._outputArray.push(output);
1827
+ hipieResults.push({
1828
+ id: item.id,
1829
+ from: item.from,
1830
+ filters: output.filters || this.filters
1831
+ });
1832
+ });
1833
+
1834
+ if (this.WUID) {
1835
+ this.comms = new Comms.HIPIEWorkunit()
1836
+ .url(this.URL)
1837
+ .proxyMappings(proxyMappings)
1838
+ .timeout(timeout)
1839
+ .hipieResults(hipieResults)
1840
+ ;
1841
+ } else if (this.databomb) {
1842
+ this.comms = new Comms.HIPIEDatabomb()
1843
+ .hipieResults(hipieResults)
1844
+ ;
1845
+ } else if (DDL1.isHipieDatasource(datasource)) {
1846
+ this.comms = new Comms.HIPIERoxie()
1847
+ .url(datasource.URL)
1848
+ .proxyMappings(proxyMappings)
1849
+ .timeout(timeout)
1850
+ .hipieResults(hipieResults)
1851
+ ;
1852
+ }
1853
+ }
1854
+
1855
+ isRoxie() {
1856
+ return !this.WUID && !this.databomb;
1857
+ }
1858
+
1859
+ isWU() {
1860
+ return !!this.WUID;
1861
+ }
1862
+
1863
+ isDatabomb() {
1864
+ return !!this.databomb;
1865
+ }
1866
+
1867
+ getQualifiedID() {
1868
+ return this.id;
1869
+ }
1870
+
1871
+ getOutputs() {
1872
+ return this._outputs;
1873
+ }
1874
+
1875
+ getUpdatesVisualizations() {
1876
+ const retVal = [];
1877
+ for (const key in this._outputs) {
1878
+ this._outputs[key].getUpdatesVisualizations().forEach(function (visualization) {
1879
+ retVal.push(visualization);
1880
+ });
1881
+ }
1882
+ return retVal;
1883
+ }
1884
+
1885
+ accept(visitor) {
1886
+ visitor.visit(this);
1887
+ for (const key in this._outputs) {
1888
+ this._outputs[key].accept(visitor);
1889
+ }
1890
+ }
1891
+
1892
+ calcRequest(request, fillInMissing) {
1893
+ const retVal = {};
1894
+ this.filters.forEach(function (item) {
1895
+ item.calcRequest(retVal, request, fillInMissing);
1896
+ });
1897
+ // TODO - Workaround HIPIE issue where it omits filters at datasource level ---
1898
+ this._outputArray.forEach(function (output) {
1899
+ output.filters.forEach(function (item) {
1900
+ item.calcRequest(retVal, request, fillInMissing);
1901
+ });
1902
+ });
1903
+ return retVal;
1904
+ }
1905
+
1906
+ fetchData(request, updates) {
1907
+ const myTransactionID = ++transactionID;
1908
+ transactionQueue.push(myTransactionID);
1909
+
1910
+ let dsRequest = request;
1911
+ dsRequest = this.calcRequest(request, this.isRoxie());
1912
+ dsRequest.refresh = request.refresh || false;
1913
+ if ((window as any).__hpcc_debug) {
1914
+ console.warn("fetchData: " + JSON.stringify(updates) + "(" + JSON.stringify(request) + ")");
1915
+ }
1916
+ for (const key in dsRequest) {
1917
+ if (dsRequest[key] === undefined) {
1918
+ delete dsRequest[key];
1919
+ }
1920
+ }
1921
+ const now = Date.now();
1922
+ this.marshaller.commsEvent(this, "request", dsRequest);
1923
+ const context = this;
1924
+ return new Promise(function (resolve, reject) {
1925
+ context.comms.call(dsRequest).then(function (_response) {
1926
+ const response = JSON.parse(JSON.stringify(_response));
1927
+ const intervalHandle = setInterval(function () {
1928
+ if (transactionQueue[0] === myTransactionID && Date.now() - now >= 500) { // 500 is to allow for all "clear" transitions to complete...
1929
+ clearTimeout(intervalHandle);
1930
+ context.processResponse(response, dsRequest, updates).then(function () {
1931
+ transactionQueue.shift();
1932
+ resolve(response);
1933
+ context.marshaller.commsEvent(context, "response", dsRequest, response);
1934
+ ++context._loadedCount;
1935
+ });
1936
+ }
1937
+ }, 100);
1938
+ }).catch(function (e) {
1939
+ context.marshaller.commsEvent(context, "error", dsRequest, e);
1940
+ reject(e);
1941
+ });
1942
+ });
1943
+ }
1944
+
1945
+ processResponse(response, request, updates) {
1946
+ const lowerResponse = {};
1947
+ for (const responseKey in response) {
1948
+ lowerResponse[responseKey.toLowerCase()] = response[responseKey];
1949
+ }
1950
+ const promises = [];
1951
+ for (const key in this._outputs) {
1952
+ const from = this._outputs[key].id;
1953
+ if (Utility.exists(from, response)) {
1954
+ if (!Utility.exists(from + _CHANGED, response) || (Utility.exists(from + _CHANGED, response) && response[from + _CHANGED].length && response[from + _CHANGED][0][from + _CHANGED])) {
1955
+ promises.push(this._outputs[key].setData(response[from], updates));
1956
+ } else {
1957
+ // TODO - I Suspect there is a HIPIE/Roxie issue here (empty request)
1958
+ promises.push(this._outputs[key].vizNotify(updates));
1959
+ }
1960
+ } else if (Utility.exists(from, lowerResponse)) {
1961
+ console.warn("DDL 'Datasource.From' case is Incorrect");
1962
+ if (!Utility.exists(from + _CHANGED, lowerResponse) || (Utility.exists(from + _CHANGED, lowerResponse) && response[from + _CHANGED].length && lowerResponse[from + _CHANGED][0][from + _CHANGED])) {
1963
+ promises.push(this._outputs[key].setData(lowerResponse[from], updates));
1964
+ } else {
1965
+ // TODO - I Suspect there is a HIPIE/Roxie issue here (empty request)
1966
+ promises.push(this._outputs[key].vizNotify(updates));
1967
+ }
1968
+ } else {
1969
+ const responseItems = [];
1970
+ for (const responseKey2 in response) {
1971
+ responseItems.push(responseKey2);
1972
+ }
1973
+ console.warn("Unable to locate '" + from + "' in response {" + responseItems.join(", ") + "}");
1974
+ }
1975
+ }
1976
+ return Promise.all(promises);
1977
+ }
1978
+
1979
+ isLoaded() {
1980
+ return this._loadedCount > 0;
1981
+ }
1982
+
1983
+ serializeState() {
1984
+ return {
1985
+ };
1986
+ }
1987
+
1988
+ deserializeState(state) {
1989
+ if (!state) return;
1990
+ }
1991
+ }
1992
+
1993
+ // Dashboard ---
1994
+ export function Dashboard(this: any, marshaller, dashboard, proxyMappings, timeout?) {
1995
+ this.marshaller = marshaller;
1996
+ this.id = dashboard.id;
1997
+ this.title = dashboard.title;
1998
+
1999
+ this._datasources = {};
2000
+ this._datasourceArray = [];
2001
+ this._datasourceTotal = 0;
2002
+ if (dashboard.datasources) {
2003
+ dashboard.datasources.forEach(item => {
2004
+ this.createDatasource(item, proxyMappings, timeout);
2005
+ });
2006
+ }
2007
+ this._datasourceTotal = this._datasourceArray.length;
2008
+
2009
+ this._visualizations = {};
2010
+ this._visualizationArray = [];
2011
+ dashboard.visualizations.forEach(item => {
2012
+ this.createVisualization(item);
2013
+ });
2014
+ this._visualizationTotal = this._visualizationArray.length;
2015
+ }
2016
+
2017
+ Dashboard.prototype.createDatasource = function (ddlDatasouce) {
2018
+ let retVal = this._datasources[ddlDatasouce.id];
2019
+ if (!retVal) {
2020
+ retVal = this.marshaller.createDatasource(ddlDatasouce);
2021
+ this._datasources[ddlDatasouce.id] = retVal;
2022
+ this._datasourceArray.push(retVal);
2023
+ }
2024
+ this._datasourceTotal = this._datasourceArray.length;
2025
+ return retVal;
2026
+ };
2027
+
2028
+ Dashboard.prototype.createVisualization = function (ddlVisualization, parentVisualization) {
2029
+ const retVal = new Visualization(this, ddlVisualization, parentVisualization);
2030
+ this._visualizations[ddlVisualization.id] = retVal;
2031
+ this._visualizationArray.push(retVal);
2032
+ this.marshaller.appendVisualization(retVal);
2033
+ return retVal;
2034
+ };
2035
+
2036
+ Dashboard.prototype.loadedPromise = function () {
2037
+ return Promise.all(this._visualizationArray.map(function (visualization) { return visualization.loadedPromise(); }));
2038
+ };
2039
+
2040
+ Dashboard.prototype.getQualifiedID = function () {
2041
+ return this.id;
2042
+ };
2043
+
2044
+ Dashboard.prototype.getDatasources = function () {
2045
+ return this._datasources;
2046
+ };
2047
+
2048
+ Dashboard.prototype.getDatasourceArray = function () {
2049
+ return this._datasourceArray;
2050
+ };
2051
+
2052
+ Dashboard.prototype.getDatasource = function (id) {
2053
+ return this._datasources[id] || this.marshaller.getDatasource(id);
2054
+ };
2055
+
2056
+ Dashboard.prototype.getDataSourceArray = function () {
2057
+ return this._datasourceArray;
2058
+ };
2059
+
2060
+ Dashboard.prototype.getVisualization = function (id) {
2061
+ return this._visualizations[id] || this.marshaller.getVisualization(id);
2062
+ };
2063
+
2064
+ Dashboard.prototype.getVisualizations = function () {
2065
+ return this._visualizations;
2066
+ };
2067
+
2068
+ Dashboard.prototype.getVisualizationArray = function () {
2069
+ return this._visualizationArray;
2070
+ };
2071
+
2072
+ Dashboard.prototype.getVisualizationTotal = function () {
2073
+ return this._visualizationTotal;
2074
+ };
2075
+
2076
+ Dashboard.prototype.accept = function (visitor) {
2077
+ visitor.visit(this);
2078
+ for (const key in this._datasources) {
2079
+ this._datasources[key].accept(visitor);
2080
+ }
2081
+ this._visualizationArray.forEach(function (item) {
2082
+ item.accept(visitor);
2083
+ }, this);
2084
+ };
2085
+
2086
+ Dashboard.prototype.primeData = function (state) {
2087
+ const fetchDataOptimizer = new VisualizationRequestOptimizer(true);
2088
+ this.getVisualizationArray().forEach(function (visualization) {
2089
+ // Clear all charts back to their default values ---
2090
+ visualization.clear();
2091
+ visualization.update();
2092
+ if (state && state[visualization.id]) {
2093
+ if (Utility.exists("source.mappings.mappings", visualization)) {
2094
+ for (const key in visualization.source.mappings.mappings) {
2095
+ if (state[visualization.id][visualization.source.mappings.mappings[key]]) {
2096
+ visualization._widgetState.row[key] = state[visualization.id][visualization.source.mappings.mappings[key]];
2097
+ visualization._widgetState.selected = true;
2098
+ }
2099
+ }
2100
+ }
2101
+ }
2102
+ });
2103
+ this.getVisualizationArray().forEach(function (visualization) {
2104
+ const inputVisualizations = visualization.getInputVisualizations();
2105
+ const datasource = visualization.source.getDatasource();
2106
+ let hasInputSelection = false;
2107
+ inputVisualizations.forEach(function (inViz) {
2108
+ if (inViz.hasSelection()) {
2109
+ const request = inViz.calcRequestFor(visualization);
2110
+ request.refresh = true;
2111
+ fetchDataOptimizer.appendRequest(datasource, request, visualization);
2112
+ hasInputSelection = true;
2113
+ }
2114
+ });
2115
+ if (!hasInputSelection && ((datasource && datasource.isRoxie()) || inputVisualizations.length === 0)) {
2116
+ fetchDataOptimizer.appendRequest(datasource, { refresh: true }, visualization);
2117
+ }
2118
+ });
2119
+ return fetchDataOptimizer.fetchData();
2120
+ };
2121
+
2122
+ Dashboard.prototype.serializeState = function () {
2123
+ const retVal = {
2124
+ datasources: {},
2125
+ visualizations: {}
2126
+ };
2127
+ for (const key in this._datasources) {
2128
+ retVal.datasources[key] = this._datasources[key].serializeState();
2129
+ }
2130
+ for (const vizKey in this._visualizations) {
2131
+ retVal.visualizations[vizKey] = this._visualizations[vizKey].serializeState();
2132
+ }
2133
+ return retVal;
2134
+ };
2135
+
2136
+ Dashboard.prototype.deserializeState = function (state) {
2137
+ if (!state) return;
2138
+ for (const key in this._datasources) {
2139
+ if (state.datasources[key]) {
2140
+ this._datasources[key].deserializeState(state.datasources[key]);
2141
+ }
2142
+ }
2143
+ for (const vizKey in this._visualizations) {
2144
+ if (state.visualizations[vizKey]) {
2145
+ this._visualizations[vizKey].deserializeState(state.visualizations[vizKey]);
2146
+ }
2147
+ }
2148
+ };
2149
+
2150
+ // Marshaller ---
2151
+ export function Marshaller(this: any) {
2152
+ Class.call(this);
2153
+
2154
+ this._proxyMappings = {};
2155
+ this._widgetMappings = d3Map();
2156
+ this._clearDataOnUpdate = true;
2157
+ this._propogateClear = false;
2158
+ this.id = "Marshaller";
2159
+ this._missingDataString = "";
2160
+ this.dashboards = {};
2161
+ this.dashboardArray = [];
2162
+
2163
+ this._datasources = {};
2164
+ this._datasourceArray = [];
2165
+ this._visualizations = {};
2166
+ this._visualizationArray = [];
2167
+ }
2168
+ Marshaller.prototype = Object.create(Class.prototype);
2169
+ Marshaller.prototype.constructor = Marshaller;
2170
+
2171
+ Marshaller.prototype.commsDataLoaded = function () {
2172
+ for (let i = 0; i < this.dashboardArray.length; i++) {
2173
+ for (const ds in this.dashboardArray[i].getDatasources()) {
2174
+ if (!this.dashboardArray[i].getDatasource(ds).isLoaded()) {
2175
+ return false;
2176
+ }
2177
+ }
2178
+ }
2179
+ return true;
2180
+ };
2181
+
2182
+ Marshaller.prototype.accept = function (visitor) {
2183
+ visitor.visit(this);
2184
+ for (const key2 in this._datasources) {
2185
+ this._datasources[key2].accept(visitor);
2186
+ }
2187
+ this.dashboardTotal = 0;
2188
+ for (const key in this.dashboards) {
2189
+ this.dashboards[key].accept(visitor);
2190
+ ++this.dashboardTotal;
2191
+ }
2192
+ };
2193
+
2194
+ Marshaller.prototype.url = function (url, callback) {
2195
+ this.espUrl = new Comms.ESPUrl()
2196
+ .url(url)
2197
+ ;
2198
+ let transport = null;
2199
+ let hipieResultName = "HIPIE_DDL";
2200
+ if (this.espUrl.isWorkunitResult()) {
2201
+ hipieResultName = this.espUrl.param("ResultName");
2202
+ transport = new Comms.HIPIEWorkunit()
2203
+ .url(url)
2204
+ .proxyMappings(this._proxyMappings)
2205
+ .timeout(this._timeout)
2206
+ ;
2207
+ } else {
2208
+ transport = new Comms.HIPIERoxie()
2209
+ .url(url)
2210
+ .proxyMappings(this._proxyMappings)
2211
+ .timeout(this._timeout)
2212
+ ;
2213
+ }
2214
+
2215
+ const context = this;
2216
+ transport.fetchResults().then(function (response) {
2217
+ if (Utility.exists(hipieResultName, response)) {
2218
+ return transport.fetchResult(hipieResultName).then(function (ddlResponse) {
2219
+ const json = ddlResponse[0][hipieResultName];
2220
+ context.parse(json, function () {
2221
+ callback(response);
2222
+ });
2223
+ }).catch(function (e) {
2224
+ context.commsEvent(context, "error", hipieResultName, e);
2225
+ });
2226
+ }
2227
+ }).catch(function (e) {
2228
+ context.commsEvent(context, "error", "fetchResults", e);
2229
+ });
2230
+ };
2231
+
2232
+ Marshaller.prototype.proxyMappings = function (_) {
2233
+ if (!arguments.length) return this._proxyMappings;
2234
+ this._proxyMappings = _;
2235
+ return this;
2236
+ };
2237
+
2238
+ Marshaller.prototype.timeout = function (_) {
2239
+ if (!arguments.length) return this._timeout;
2240
+ this._timeout = _;
2241
+ return this;
2242
+ };
2243
+
2244
+ Marshaller.prototype.widgetMappings = function (_) {
2245
+ if (!arguments.length) return this._widgetMappings;
2246
+ this._widgetMappings = _;
2247
+ return this;
2248
+ };
2249
+
2250
+ Marshaller.prototype.clearDataOnUpdate = function (_) {
2251
+ if (!arguments.length) return this._clearDataOnUpdate;
2252
+ this._clearDataOnUpdate = _;
2253
+ return this;
2254
+ };
2255
+
2256
+ Marshaller.prototype.propogateClear = function (_) {
2257
+ if (!arguments.length) return this._propogateClear;
2258
+ this._propogateClear = _;
2259
+ return this;
2260
+ };
2261
+
2262
+ Marshaller.prototype.missingDataString = function (_) {
2263
+ if (!arguments.length) return this._missingDataString;
2264
+ this._missingDataString = _;
2265
+ return this;
2266
+ };
2267
+
2268
+ Marshaller.prototype.parse = function (json, callback) {
2269
+ const context = this;
2270
+ this._json = json;
2271
+ this._jsonParsed = JSON.parse(this._json);
2272
+
2273
+ // Global Datasources ---
2274
+ this._datasources = {};
2275
+ this._datasourceArray = [];
2276
+ if (this._jsonParsed.datasources) {
2277
+ this._jsonParsed.datasources.forEach(function (item) {
2278
+ context.createDatasource(item);
2279
+ });
2280
+ }
2281
+
2282
+ this.dashboards = {};
2283
+ this.dashboardArray = [];
2284
+ this._visualizations = {};
2285
+ this._visualizationArray = [];
2286
+ const dashboards = this._jsonParsed.dashboards || this._jsonParsed;
2287
+ dashboards.forEach(function (item) {
2288
+ const newDashboard = new Dashboard(context, item, context._proxyMappings, context._timeout);
2289
+ context.dashboards[item.id] = newDashboard;
2290
+ context.dashboardArray.push(newDashboard);
2291
+ });
2292
+ this.dashboardTotal = this.dashboardArray.length;
2293
+ this._visualizationArray.forEach(function (ddlViz) {
2294
+ ddlViz.on("processEvent", function (eventID, event, row, col, selected) {
2295
+ context.vizEvent(ddlViz.widget, eventID, row, col, selected);
2296
+ });
2297
+ });
2298
+ this._datasourceTotal = this._datasourceArray.length;
2299
+
2300
+ this.ready(callback);
2301
+ return this;
2302
+ };
2303
+
2304
+ Marshaller.prototype.dashboardsLoaded = function () {
2305
+ return Promise.all(this.dashboardArray.map(function (dashboard) { return dashboard.loadedPromise(); }));
2306
+ };
2307
+
2308
+ Marshaller.prototype.createDatasource = function (ddlDatasouce: DDL1.IAnyDatasource) {
2309
+ let retVal = this._datasources[ddlDatasouce.id];
2310
+ if (!retVal) {
2311
+ retVal = new Datasource(this, ddlDatasouce, this._proxyMappings, this._timeout);
2312
+ this._datasources[ddlDatasouce.id] = retVal;
2313
+ this._datasourceArray.push(retVal);
2314
+ }
2315
+ this._datasourceTotal = this._datasourceArray.length;
2316
+ return retVal;
2317
+ };
2318
+
2319
+ Marshaller.prototype.getDatasource = function (id) {
2320
+ return this._datasources[id];
2321
+ };
2322
+
2323
+ Marshaller.prototype.getDatasources = function () {
2324
+ return this._datasources;
2325
+ };
2326
+
2327
+ Marshaller.prototype.getDatasourceArray = function () {
2328
+ return this._datasourceArray;
2329
+ };
2330
+
2331
+ Marshaller.prototype.appendVisualization = function (visualization) {
2332
+ this._visualizations[visualization.id] = visualization;
2333
+ this._visualizationArray.push(visualization);
2334
+ };
2335
+
2336
+ Marshaller.prototype.getVisualization = function (id) {
2337
+ return this._visualizations[id];
2338
+ };
2339
+
2340
+ Marshaller.prototype.appendDataSource = function (datasource) {
2341
+ this._datasources[datasource.id] = datasource;
2342
+ this._datasourceArray.push(datasource);
2343
+ };
2344
+
2345
+ Marshaller.prototype.getVisualizations = function () {
2346
+ return this._visualizations;
2347
+ };
2348
+
2349
+ Marshaller.prototype.getVisualizationArray = function () {
2350
+ return this._visualizationArray;
2351
+ };
2352
+
2353
+ Marshaller.prototype.getWidget = function (id) {
2354
+ return this._widgetMappings.get(id);
2355
+ };
2356
+
2357
+ Marshaller.prototype.on = function (eventID, func) {
2358
+ const context = this;
2359
+ this.overrideMethod(eventID, function (origFunc, args) {
2360
+ const retVal = origFunc.apply(context, args);
2361
+ return func.apply(context, args) || retVal;
2362
+ });
2363
+ return this;
2364
+ };
2365
+
2366
+ Marshaller.prototype.ready = function (callback) {
2367
+ if (!callback) {
2368
+ return;
2369
+ }
2370
+ this.dashboardsLoaded().then(function () {
2371
+ callback();
2372
+ });
2373
+ };
2374
+
2375
+ Marshaller.prototype.vizEvent = function (sourceWidget, eventID, row, col, selected) {
2376
+ console.warn("Marshaller.vizEvent: " + sourceWidget.id() + "-" + eventID);
2377
+ };
2378
+
2379
+ Marshaller.prototype.commsEvent = function (ddlSource, eventID, request, response) {
2380
+ switch (eventID) {
2381
+ case "request":
2382
+ if ((window as any).__hpcc_debug) {
2383
+ console.warn("Marshaller.commsEvent: " + ddlSource.id + "-" + eventID + ": " + JSON.stringify(request));
2384
+ }
2385
+ break;
2386
+ case "response":
2387
+ case "error":
2388
+ if ((window as any).__hpcc_debug) {
2389
+ console.warn("Marshaller.commsEvent: " + ddlSource.id + "-" + eventID + ": " + JSON.stringify(response));
2390
+ }
2391
+ break;
2392
+ default:
2393
+ if ((window as any).__hpcc_debug) {
2394
+ console.warn("Marshaller.commsEvent: " + JSON.stringify(arguments));
2395
+ }
2396
+ break;
2397
+
2398
+ }
2399
+ };
2400
+
2401
+ Marshaller.prototype.createDatabomb = function () {
2402
+ const retVal = {};
2403
+ this.dashboardArray.forEach(function (dashboard) {
2404
+ for (const key in dashboard.getDatasources()) {
2405
+ const comms = dashboard.getDatasource(key).comms;
2406
+ retVal[key] = {};
2407
+ for (const key2 in comms._hipieResults) {
2408
+ const hipieResult = comms._hipieResults[key2];
2409
+ retVal[key][key2] = comms._resultNameCache[hipieResult.from];
2410
+ }
2411
+ }
2412
+ });
2413
+ return retVal;
2414
+ };
2415
+
2416
+ Marshaller.prototype.primeData = function (state) {
2417
+ const promises = this.dashboardArray.map(function (dashboard) {
2418
+ return dashboard.primeData(state);
2419
+ });
2420
+ return Promise.all(promises);
2421
+ };
2422
+
2423
+ Marshaller.prototype.serializeState = function () {
2424
+ const retVal = {};
2425
+ this.dashboardArray.forEach(function (dashboard, idx) {
2426
+ retVal[dashboard.id] = dashboard.serializeState();
2427
+ });
2428
+ return retVal;
2429
+ };
2430
+
2431
+ Marshaller.prototype.deserializeState = function (state) {
2432
+ if (!state) return;
2433
+ this.dashboardArray.forEach(function (dashboard, idx) {
2434
+ dashboard.deserializeState(state[dashboard.id]);
2435
+ });
2436
+ return this;
2437
+ };