@datarailsshared/dr_renderer 1.2.391 → 1.2.393

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,11 @@ This project was generated by amazing Datarails R&D team
13
13
  let default_colors = ["#106bd0", "#00cee8", "#95c8d8", "#89cff0", "#FE746D", "#6ADC4C", "#9B9AD9", "#ff8000", "#C11B12", "#5a41f9"];
14
14
  let hr = dr_renderer.getInitHighchartsRenderer($, document, default_colors, Highcharts);
15
15
 
16
+ ## Development
17
+ ### Types
18
+ To be able to compile types with `npm run build:types` you need to install typescript globally:
19
+
20
+ ```npm i -g typescript```
16
21
 
17
22
  ## Publish to npm
18
23
  Just merge to prod branch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarailsshared/dr_renderer",
3
- "version": "1.2.391",
3
+ "version": "1.2.393",
4
4
  "description": "DataRails charts and tables renderer",
5
5
  "keywords": [
6
6
  "datarails",
@@ -10,7 +10,8 @@
10
10
  ],
11
11
  "scripts": {
12
12
  "login": "npm login",
13
- "test": "jest --coverage"
13
+ "test": "jest --coverage",
14
+ "build:types": "tsc --build --verbose"
14
15
  },
15
16
  "author": "Sergey Spivakov",
16
17
  "repository": {
@@ -159,8 +159,67 @@ let initDRPivotTable = function($, window, document) {
159
159
  };
160
160
 
161
161
  DRPivotData.prototype.getInsight = function(colKey, rowKey) {
162
- const insightInfo = _.find(this.insights, insight => insight.colKey === colKey && insight.rowKey === rowKey);
163
- return _.get(insightInfo, 'insight', null);
162
+ const key = [rowKey, colKey].join(delim);
163
+ return this.insights.get(key);
164
+ }
165
+
166
+ DRPivotData.prototype.getAttrsKeys = function(record, attrs) {
167
+ const keys = [];
168
+ for (let k = 0; k < attrs.length; k++) {
169
+ const attr = attrs[k];
170
+ if (record.hasOwnProperty(attr)) {
171
+ keys.push(record[attr] != null ? record[attr] : 'null');
172
+ }
173
+ }
174
+ return keys;
175
+ }
176
+
177
+ DRPivotData.prototype.getFlatKey = function(record, attrs) {
178
+ const keys = this.getAttrsKeys(record, attrs);
179
+ return keys.join(delim);
180
+ }
181
+
182
+ DRPivotData.prototype.buildInsights = function(rows, useServerTotalsCalculation) {
183
+ for (let index = 0; index < rows.length; index++) {
184
+ const record = rows[index];
185
+ const insight = record.insight;
186
+ delete record.insight;
187
+
188
+ if (!insight) continue;
189
+
190
+ if (useServerTotalsCalculation) {
191
+ const flatRowKey = this.getFlatKey(record, this.rowAttrs);
192
+ const flatColKey = this.getFlatKey(record, this.colAttrs);
193
+
194
+ if (flatRowKey || flatColKey) {
195
+ this.insights.set([flatRowKey, flatColKey].join(delim), insight);
196
+ }
197
+ continue;
198
+ }
199
+
200
+ const recordValues = _.values(record);
201
+ const containsAverage = _.includes(recordValues, 'DR_Average');
202
+ const containsOthers = _.includes(recordValues, 'DR_Others');
203
+
204
+ const rowKey = processKey(record, this.rowTotals, this.rowKeys, this.rowAttrs, containsAverage, containsOthers, (function(_this) {
205
+ return function(key) {
206
+ return _this.aggregator(_this, key, []);
207
+ };
208
+ })(this));
209
+
210
+ const colKey = processKey(record, this.colTotals, this.colKeys, this.colAttrs, containsAverage, containsOthers, (function(_this) {
211
+ return function(key) {
212
+ return _this.aggregator(_this, [], key);
213
+ };
214
+ })(this));
215
+
216
+ const flatRowKey = rowKey.join(delim);
217
+ const flatColKey = colKey.join(delim);
218
+
219
+ if (flatRowKey || flatColKey) {
220
+ this.insights.set([flatRowKey, flatColKey].join(delim), insight);
221
+ }
222
+ }
164
223
  }
165
224
 
166
225
  DRPivotData.prototype.processRecord = function(record, useTotalsCalculation) {
@@ -183,21 +242,8 @@ let initDRPivotTable = function($, window, document) {
183
242
  };
184
243
  })(this);
185
244
 
186
- let rowKey = [];
187
- for (k = 0; k < this.rowAttrs.length; k++) {
188
- let attr = this.rowAttrs[k];
189
- if (record.hasOwnProperty(attr)) {
190
- rowKey.push((ref = record[attr]) != null ? ref : "null");
191
- }
192
- }
193
-
194
- let colKey = [];
195
- for (k = 0; k < this.colAttrs.length; k++) {
196
- let attr = this.colAttrs[k];
197
- if (record.hasOwnProperty(attr)) {
198
- colKey.push((ref = record[attr]) != null ? ref : "null");
199
- }
200
- }
245
+ const rowKey = this.getAttrsKeys(record, this.rowAttrs);
246
+ const colKey = this.getAttrsKeys(record, this.colAttrs);
201
247
 
202
248
  let flatRowKey = rowKey.join(delim);
203
249
  let flatColKey = colKey.join(delim);
@@ -232,11 +278,7 @@ let initDRPivotTable = function($, window, document) {
232
278
  }
233
279
 
234
280
  if (insight && (flatRowKey || flatColKey)) {
235
- this.insights.push({
236
- colKey: flatColKey,
237
- rowKey: flatRowKey,
238
- insight: insight,
239
- });
281
+ this.insights.set([flatRowKey, flatColKey].join(delim), insight);
240
282
  }
241
283
  return;
242
284
  }
@@ -266,11 +308,7 @@ let initDRPivotTable = function($, window, document) {
266
308
  const flatColKeyForInsight = colKey.join(delim);
267
309
 
268
310
  if (flatRowKeyForInsight || flatColKeyForInsight) {
269
- this.insights.push({
270
- colKey: flatColKeyForInsight,
271
- rowKey: flatRowKeyForInsight,
272
- insight: insight,
273
- });
311
+ this.insights.set([flatRowKeyForInsight, flatColKeyForInsight].join(delim), insight);
274
312
  }
275
313
  }
276
314
 
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @typedef {Object} HighChartsRenderer
3
+ * @property {(rows: Rows, options: GTROptions, isTable: boolean, widget: any, pivotModel?: PivotModel) => string} rhPivotViewV2
4
+ */
5
+
6
+ /**
7
+ * @typedef {Object} PivotUtilities
8
+ * @property {(rows: Rows, options: GTROptions) => PivotModel} getPivotDataModel
9
+ */
10
+
11
+ /**
12
+ * @typedef {Object} JQuery
13
+ * @property {PivotUtilities} pivotUtilities
14
+ */
15
+
16
+ /**
17
+ * @typedef {Object} PivotModel
18
+ * @property {(rows: Rows, useTotalsCalculation: boolean) => void} buildInsights
19
+ */
20
+
21
+ /**
22
+ * @typedef {Object} GTROptions
23
+ */
24
+
25
+ /**
26
+ * @typedef {Record<string, Record<string, number | string> | number | string>[]} Rows - BE data response
27
+ */
28
+
29
+ export class GraphTableRenderer {
30
+ /**
31
+ * @type {PivotModel | undefined}
32
+ */
33
+ #pivotModel;
34
+
35
+ /**
36
+ * @type {GTROptions | null}
37
+ */
38
+ #options = null;
39
+
40
+ /**
41
+ * @type {Record<string, Record<string, number | string> | number | string>[]}
42
+ *
43
+ */
44
+ #rows = [];
45
+
46
+ /**
47
+ * Utility properties
48
+ */
49
+ /**
50
+ * @type {HighChartsRenderer}
51
+ */
52
+ #hcr;
53
+ /**
54
+ * @type {JQuery}
55
+ */
56
+ #$;
57
+ /**
58
+ * @type {PivotUtilities}
59
+ */
60
+ #pivotUtilities;
61
+
62
+ /**
63
+ *
64
+ * @param {HighChartsRenderer} hcr
65
+ * @param {JQuery} $
66
+ */
67
+ constructor(hcr, $) {
68
+ this.#hcr = hcr;
69
+ this.#$ = $;
70
+ this.#pivotUtilities = this.#$.pivotUtilities;
71
+ }
72
+
73
+ /**
74
+ * Creates Pivot Data Model that works we BE data response to aggregate data to render with Chart and Table
75
+ * @param {Rows} rows BE data response
76
+ * @param {GTROptions} options
77
+ * @returns {this}
78
+ */
79
+ createPivotModel(rows, options) {
80
+ this.#options = options;
81
+ this.#rows = rows;
82
+ this.#pivotModel = this.#pivotUtilities.getPivotDataModel(rows, options);
83
+ return this;
84
+ }
85
+
86
+ /**
87
+ * @returns {void}
88
+ */
89
+ disposePivotModel() {
90
+ this.#pivotModel = undefined;
91
+ }
92
+
93
+ /**
94
+ * @see createPivotModel
95
+ * @returns {PivotModel | undefined}
96
+ */
97
+ getPivotModel() {
98
+ return this.#pivotModel;
99
+ }
100
+
101
+ renderTable(widget = null) {
102
+ return this.#hcr.rhPivotViewV2(this.#rows, this.#options || {}, true, widget, this.#pivotModel);
103
+ }
104
+
105
+ renderChart(widget = null) {
106
+ return this.#hcr.rhPivotViewV2(this.#rows, this.#options || {}, false, widget, this.#pivotModel);
107
+ }
108
+ }
109
+
110
+ export default GraphTableRenderer;
@@ -629,8 +629,9 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
629
629
 
630
630
  if (!is_drill_down_pie && labelOptions.show_out_of_x_axis) {
631
631
  const axisTotal = pivotData.getAggregator([], cols).value();
632
- const outOfAxisPercentages = axisTotal ? Math.round(value / axisTotal * 100) + '%' : '';
633
- outOfAxisPercentages && percentageArray.push(outOfAxisPercentages);
632
+ if (value && axisTotal) {
633
+ percentageArray.push(Math.round(value / axisTotal * 100) + '%');
634
+ }
634
635
  }
635
636
 
636
637
  if (labelOptions.show_out_of_data_series) {
@@ -4695,6 +4696,9 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
4695
4696
  }
4696
4697
  };
4697
4698
 
4699
+ /**
4700
+ * Support rhPivotViewV2 version
4701
+ */
4698
4702
  highchartsRenderer.rhPivotView = function (rowData, options, isTable = false, widget = null) {
4699
4703
  if (!rowData || !rowData) {
4700
4704
  if (options.onlyOptions) {
@@ -4858,6 +4862,168 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
4858
4862
  return result;
4859
4863
  };
4860
4864
 
4865
+ highchartsRenderer.rhPivotViewV2 = function (rowData, options, isTable = false, widget = null, pivotData) {
4866
+ if (!rowData) {
4867
+ if (options.onlyOptions) {
4868
+ return {};
4869
+ }
4870
+ return null;
4871
+ }
4872
+
4873
+ const isWalktrough = lodash.get(widget, 'chart_type') === highchartsRenderer.CHART_TYPES.WATERFALL_WALKTHROUGH;
4874
+ const isBreakdown = lodash.get(widget, 'chart_type')=== highchartsRenderer.CHART_TYPES.WATERFALL_BREAKDOWN;
4875
+ const isWaterfall = isWalktrough || isBreakdown;
4876
+
4877
+ if (isWaterfall) {
4878
+ const maxCategories = highchartsRenderer.waterfallConstants[widget.chart_type].maxCategoriesCount;
4879
+ const minCategories = highchartsRenderer.waterfallConstants[widget.chart_type].minCategoriesCount;
4880
+ let uniqueCategories = [];
4881
+
4882
+ if (isBreakdown) {
4883
+ uniqueCategories = lodash.filter(
4884
+ lodash.uniq(
4885
+ lodash.map(rowData, row => row[widget.cols[0].name])
4886
+ ),
4887
+ value => !!value
4888
+ );
4889
+ } else {
4890
+ uniqueCategories = lodash.filter(
4891
+ lodash.get(widget, 'options.walkthrough_options.values.walkthrough'),
4892
+ (category) => category.trend !== 'total'
4893
+ );
4894
+ }
4895
+ if (uniqueCategories && ((maxCategories && uniqueCategories.length > maxCategories)
4896
+ || (minCategories && uniqueCategories.length < minCategories))) {
4897
+ options.error_has_occurred = true;
4898
+ const breakdownText = `Please adjust your dashboard's reference date or filter selections as \
4899
+ the quantity of data doesn't match the limit of at least ${ minCategories } values.`;
4900
+ const walkthroughText = `Please adjust your dashboard's reference date and filter selections as \
4901
+ the quantity of data doesn't match the chart's ${ minCategories }-${ maxCategories } value limit.`;
4902
+
4903
+ options.error_params = {
4904
+ title: 'Data Conflict',
4905
+ text: isBreakdown ? breakdownText : walkthroughText,
4906
+ class: uniqueCategories.length < minCategories ? 'waterfall-nodata' : 'waterfall-too-much-data',
4907
+ }
4908
+
4909
+ return highchartsRenderer.getNoDataResult(options.rendererOptions, true);
4910
+ }
4911
+ }
4912
+
4913
+ if (rowData.length == 0) {
4914
+ if (options.onlyOptions) {
4915
+ return {};
4916
+ }
4917
+
4918
+ options.error_has_occurred = true;
4919
+ options.error_params = highchartsRenderer.widgetPlaceholders.nodata;
4920
+ return highchartsRenderer.getNoDataResult(options.rendererOptions);
4921
+ }
4922
+
4923
+ if (rowData.length > highchartsRenderer.MAX_ROWS_FOR_SHOW_RESULTS) {
4924
+ if (options.onlyOptions) {
4925
+ return {};
4926
+ }
4927
+
4928
+ options.error_has_occurred = true;
4929
+ options.error_params = highchartsRenderer.widgetPlaceholders.tooMuchData;
4930
+ return highchartsRenderer.getNoDataResult(options.rendererOptions, true);
4931
+ }
4932
+
4933
+ var tmp = $.pivotUtilities.aggregatorTemplates;
4934
+ var defaults, e, result, opts, optsFiltered;
4935
+ defaults = {
4936
+ cols: [],
4937
+ rows: [],
4938
+ vals: [],
4939
+ filter: function () {
4940
+ return true;
4941
+ },
4942
+ aggregator: tmp.count()(),
4943
+ aggregatorName: "Count",
4944
+ sorters: function () {
4945
+ },
4946
+ derivedAttributes: {},
4947
+ renderer: $.pivotUtilities.subtotal_renderers,
4948
+ rendererOptions: null,
4949
+ localeStrings: $.pivotUtilities.locales.en.localeStrings,
4950
+ onlyOptions: false
4951
+ };
4952
+
4953
+ opts = $.extend(defaults, options);
4954
+ highchartsRenderer.sanitizeOptions(opts);
4955
+ options.rendererOptions.labelsConvertFunction = highchartsRenderer.getFieldNameForTable(options);
4956
+ opts.isTable = isTable;
4957
+ if (isTable == true && options.rendererOptions.chartOptions && options.rendererOptions.chartOptions.table_options && options.rendererOptions.chartOptions.table_options.transpose_table == true) {
4958
+ var temp_cols = opts.cols;
4959
+ opts.cols = opts.rows;
4960
+ opts.rows = temp_cols;
4961
+ }
4962
+
4963
+ optsFiltered = $.extend(defaults, opts);
4964
+ result = null;
4965
+ try {
4966
+ const isTranspose = lodash.get(opts, 'rendererOptions.chartOptions.table_options.transpose_table', false);
4967
+ opts.getFormattedColKeys = isTranspose ? highchartsRenderer.getFormattedRowKeys : highchartsRenderer.getFormattedColKeys;
4968
+ opts.getFormattedRowKeys = isTranspose ? highchartsRenderer.getFormattedColKeys : highchartsRenderer.getFormattedRowKeys;
4969
+
4970
+ pivotData.sortByValueAttrs = [];
4971
+ try {
4972
+ if (options && options.onlyOptions) {
4973
+ if (!opts.rendererOptions) {
4974
+ opts.rendererOptions = {};
4975
+ }
4976
+ opts.rendererOptions.onlyOptions = true;
4977
+ }
4978
+
4979
+ if (!highchartsRenderer.sortHasBeenDoneOnBE(lodash.get(widget, 'pivot.keysObject'))) {
4980
+ const sortByValueSettings = lodash.filter(
4981
+ lodash.get(widget, 'options.sortingFields', []),
4982
+ sortingField => lodash.includes(['field_values', 'variance'], lodash.get(sortingField, 'sorting.sort_by'))
4983
+ );
4984
+
4985
+ if (sortByValueSettings.length) {
4986
+ pivotData.sortByValueAttrs = lodash.map(sortByValueSettings, fieldSorting => fieldSorting.name);
4987
+ let new_sorting_function = highchartsRenderer.generateSortingFunctionByValues(sortByValueSettings, pivotData, opts, widget);
4988
+ opts.sorters = new_sorting_function;
4989
+ optsFiltered.sorters = new_sorting_function;
4990
+ pivotData.sorters = new_sorting_function;
4991
+
4992
+ if (lodash.isObject(lodash.get(widget, 'pivot'))) {
4993
+ widget.pivot.sorters = new_sorting_function;
4994
+ }
4995
+ }
4996
+ }
4997
+
4998
+ result = opts.renderer(pivotData, opts.rendererOptions);
4999
+ } catch (_error) {
5000
+ e = _error;
5001
+ if (typeof console !== "undefined" && console !== null) {
5002
+ console.error(e.stack);
5003
+ }
5004
+ result = $("<span>").html(opts.localeStrings.renderError);
5005
+ if (options.onlyOptions) {
5006
+ result = {};
5007
+ }
5008
+ }
5009
+
5010
+ if (lodash.isObject(lodash.get(widget, 'pivot'))) {
5011
+ widget.pivot.sortByValueAttrs = pivotData.sortByValueAttrs;
5012
+ }
5013
+ } catch (_error) {
5014
+ e = _error;
5015
+ if (typeof console !== "undefined" && console !== null) {
5016
+ console.error(e.stack);
5017
+ }
5018
+ result = $("<span>").html(opts.localeStrings.computeError);
5019
+ if (options.onlyOptions) {
5020
+ result = {};
5021
+ }
5022
+ }
5023
+
5024
+ return result;
5025
+ };
5026
+
4861
5027
  /******** Convertors *******/
4862
5028
 
4863
5029
  highchartsRenderer.getOnlyIncludedOfField = function (filedObj) {
package/src/pivottable.js CHANGED
@@ -688,7 +688,7 @@ let initPivotTable = function($, window, document) {
688
688
  return true;
689
689
  });
690
690
  this.tree = {};
691
- this.insights = [];
691
+ this.insights = new Map();
692
692
 
693
693
  this.isKeysSortingDoneOnBackendSide = opts.keysObject && typeof opts.keysObject === 'object' && helpers.backendSortingKeysAreNotEmpty(opts.keysObject);
694
694
  if (this.isKeysSortingDoneOnBackendSide) {
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "declaration": true,
4
+ "allowJs": true,
5
+ "declarationDir": "./types",
6
+ "checkJs": true,
7
+ "moduleResolution": "Node16",
8
+ "module": "Node16",
9
+ "target": "esnext",
10
+ "emitDeclarationOnly": true,
11
+ "strict": true
12
+ },
13
+ "include": ["./src/graph-table-renderer.js"],
14
+ "exclude": ["node_modules"]
15
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @typedef {Object} HighChartsRenderer
3
+ * @property {(rows: Rows, options: GTROptions, isTable: boolean, widget: any, pivotModel?: PivotModel) => string} rhPivotViewV2
4
+ */
5
+ /**
6
+ * @typedef {Object} PivotUtilities
7
+ * @property {(rows: Rows, options: GTROptions) => PivotModel} getPivotDataModel
8
+ */
9
+ /**
10
+ * @typedef {Object} JQuery
11
+ * @property {PivotUtilities} pivotUtilities
12
+ */
13
+ /**
14
+ * @typedef {Object} PivotModel
15
+ * @property {(rows: Rows, useTotalsCalculation: boolean) => void} buildInsights
16
+ */
17
+ /**
18
+ * @typedef {Object} GTROptions
19
+ */
20
+ /**
21
+ * @typedef {Record<string, Record<string, number | string> | number | string>[]} Rows - BE data response
22
+ */
23
+ export class GraphTableRenderer {
24
+ /**
25
+ *
26
+ * @param {HighChartsRenderer} hcr
27
+ * @param {JQuery} $
28
+ */
29
+ constructor(hcr: HighChartsRenderer, $: JQuery);
30
+ /**
31
+ * Creates Pivot Data Model that works we BE data response to aggregate data to render with Chart and Table
32
+ * @param {Rows} rows BE data response
33
+ * @param {GTROptions} options
34
+ * @returns {this}
35
+ */
36
+ createPivotModel(rows: Rows, options: GTROptions): this;
37
+ /**
38
+ * @returns {void}
39
+ */
40
+ disposePivotModel(): void;
41
+ /**
42
+ * @see createPivotModel
43
+ * @returns {PivotModel | undefined}
44
+ */
45
+ getPivotModel(): PivotModel | undefined;
46
+ renderTable(widget?: null): string;
47
+ renderChart(widget?: null): string;
48
+ #private;
49
+ }
50
+ export default GraphTableRenderer;
51
+ export type HighChartsRenderer = {
52
+ rhPivotViewV2: (rows: Rows, options: GTROptions, isTable: boolean, widget: any, pivotModel?: PivotModel) => string;
53
+ };
54
+ export type PivotUtilities = {
55
+ getPivotDataModel: (rows: Rows, options: GTROptions) => PivotModel;
56
+ };
57
+ export type JQuery = {
58
+ pivotUtilities: PivotUtilities;
59
+ };
60
+ export type PivotModel = {
61
+ buildInsights: (rows: Rows, useTotalsCalculation: boolean) => void;
62
+ };
63
+ export type GTROptions = Object;
64
+ /**
65
+ * - BE data response
66
+ */
67
+ export type Rows = Record<string, Record<string, number | string> | number | string>[];
@@ -0,0 +1 @@
1
+ export * from './graph-table-renderer';