@datarailsshared/dr_renderer 1.5.19 → 1.5.39

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarailsshared/dr_renderer",
3
- "version": "1.5.19",
3
+ "version": "1.5.39",
4
4
  "description": "DataRails charts and tables renderer",
5
5
  "keywords": [
6
6
  "datarails",
@@ -73,6 +73,7 @@ function isShowingEmptyValues(additionOptions) {
73
73
  return !additionOptions || !additionOptions.chart || additionOptions.chart.dislay_empty_values !== false;
74
74
  }
75
75
 
76
+ const DELIMER = ' , '
76
77
  const FEATURES = {
77
78
  ENABLE_NEW_WIDGET_VALUE_FORMATTING: 'enable_new_widget_value_formatting',
78
79
  FORMAT_DATES_AS_OTHER_AXIS_TYPES: 'format_dates_as_other_axis_types',
@@ -91,5 +92,6 @@ module.exports = {
91
92
  removeSVGTextCorrection,
92
93
  disableLegendInteractionIfRequired,
93
94
  isShowingEmptyValues,
94
- FEATURES
95
+ FEATURES,
96
+ DELIMER
95
97
  }
@@ -1,4 +1,5 @@
1
- const { DR_SCENARIO } = require('./smart_queries_helper');
1
+ const { DR_SCENARIO, getSqAggregator } = require('./smart_queries_helper');
2
+ const { DELIMER } = require('./dr-renderer-helpers');
2
3
  const { TooMuchDataError } = require('./errors');
3
4
 
4
5
  let initDRPivotTable = function($, window, document) {
@@ -10,13 +11,12 @@ let initDRPivotTable = function($, window, document) {
10
11
  const newTableColors = ['rgb(127, 196, 255)', 'rgb(200, 243,243)', 'rgb(247, 161, 173)', 'rgb(255, 237, 178)', 'rgb(221, 239, 255)',
11
12
  'rgb(171, 216, 255)', 'rgb(174, 231, 220)', 'rgb(227, 255, 236)', 'rgb(162, 215, 227)', 'rgb(223, 239, 236)'];
12
13
 
13
- var delim = " , ";
14
14
  const useNewUx = document.ReportHippo && document.ReportHippo && document.ReportHippo.user &&
15
15
  document.ReportHippo.user.organization.settings && document.ReportHippo.user.organization.settings.use_new_ux;
16
16
  // const numberOfRows = 500; // change to activate the handsontable when num of rows bigger then this.
17
17
 
18
18
  const isFlatKeyInPivotKeys = function(keys, flatKey) {
19
- return keys.some(key => key.join(delim) === flatKey);
19
+ return keys.some(key => key.join(DELIMER) === flatKey);
20
20
  };
21
21
 
22
22
  DRPivotData = (function(superClass) {
@@ -138,7 +138,7 @@ let initDRPivotTable = function($, window, document) {
138
138
  for (k = 0, len = attrs.length; k < len; k++) {
139
139
  attr = attrs[k];
140
140
  key.push((ref = record[attr]) != null ? ref : "null");
141
- flatKey = key.join(delim);
141
+ flatKey = key.join(DELIMER);
142
142
  if (!totals[flatKey]) {
143
143
  totals[flatKey] = getAggregator(key.slice());
144
144
  addKey = true;
@@ -174,7 +174,7 @@ let initDRPivotTable = function($, window, document) {
174
174
 
175
175
  DRPivotData.prototype.getFlatKey = function(record, attrs) {
176
176
  const keys = this.getAttrsKeys(record, attrs);
177
- return keys.join(delim);
177
+ return keys.join(DELIMER);
178
178
  }
179
179
 
180
180
  DRPivotData.prototype.processRecord = function(record, isSmartQueriesEnabled) {
@@ -196,8 +196,8 @@ let initDRPivotTable = function($, window, document) {
196
196
  const rowKey = this.getAttrsKeys(record, this.rowAttrs);
197
197
  const colKey = this.getAttrsKeys(record, this.colAttrs);
198
198
 
199
- let flatRowKey = rowKey.join(delim);
200
- let flatColKey = colKey.join(delim);
199
+ let flatRowKey = rowKey.join(DELIMER);
200
+ let flatColKey = colKey.join(DELIMER);
201
201
 
202
202
  if (this.keysLength === rowKey.length + colKey.length) {
203
203
  if (!this.isKeysSortingDoneOnBackendSide && !isFlatKeyInPivotKeys(this.rowKeys, flatRowKey)) {
@@ -232,8 +232,8 @@ let initDRPivotTable = function($, window, document) {
232
232
  DRPivotData.prototype.getAggregator = function(rowKey, colKey) {
233
233
  var agg, flatColKey, flatRowKey;
234
234
  let hebrewMarkRegex = new RegExp(String.fromCharCode(8206), 'g');
235
- flatRowKey = rowKey.join(delim).replace(hebrewMarkRegex, '');
236
- flatColKey = colKey.join(delim).replace(hebrewMarkRegex, '');
235
+ flatRowKey = rowKey.join(DELIMER).replace(hebrewMarkRegex, '');
236
+ flatColKey = colKey.join(DELIMER).replace(hebrewMarkRegex, '');
237
237
  if (rowKey.length === 0 && colKey.length === 0) {
238
238
  agg = this.allTotal;
239
239
  } else if (rowKey.length === 0) {
@@ -241,7 +241,8 @@ let initDRPivotTable = function($, window, document) {
241
241
  } else if (colKey.length === 0) {
242
242
  agg = this.rowTotals[flatRowKey];
243
243
  } else {
244
- agg = this.tree[flatRowKey][flatColKey];
244
+ const sqAgg = this.isSmartQueriesEnabled ? getSqAggregator(this.tree, rowKey, flatColKey) : null;
245
+ agg = sqAgg || this.tree[flatRowKey][flatColKey];
245
246
  }
246
247
  return agg != null ? agg : {
247
248
  value: (function() {
@@ -880,7 +881,7 @@ let initDRPivotTable = function($, window, document) {
880
881
  descendants: lastCol,
881
882
  leaves: 1,
882
883
  key: key,
883
- flatKey: key.join(delim)
884
+ flatKey: key.join(DELIMER)
884
885
  };
885
886
  headers.push(node);
886
887
  rMark[0] = node;
@@ -900,7 +901,7 @@ let initDRPivotTable = function($, window, document) {
900
901
  descendants: lastCol - c,
901
902
  leaves: 1,
902
903
  key: key,
903
- flatKey: key.join(delim)
904
+ flatKey: key.join(DELIMER)
904
905
  };
905
906
  rMark[c] = node;
906
907
  rMark[c - 1].children.push(node);
@@ -941,7 +942,7 @@ let initDRPivotTable = function($, window, document) {
941
942
  descendants: 0,
942
943
  leaves: 0,
943
944
  key: key,
944
- flatKey: key.join(delim)
945
+ flatKey: key.join(DELIMER)
945
946
  };
946
947
 
947
948
  headers.push(node);
@@ -964,7 +965,7 @@ let initDRPivotTable = function($, window, document) {
964
965
  descendants: 0,
965
966
  leaves: 0,
966
967
  key: key,
967
- flatKey: key.join(delim)
968
+ flatKey: key.join(DELIMER)
968
969
  };
969
970
  if (c === 0) {
970
971
  headers.push(node);
@@ -1272,7 +1273,7 @@ let initDRPivotTable = function($, window, document) {
1272
1273
  "rowspan": rowHeader.descendants + 1,
1273
1274
  "colspan": colspan
1274
1275
  });
1275
- if (opts.chartOptions.isSmartQueriesEnabled) {
1276
+ if (pivotData.isSmartQueriesEnabled) {
1276
1277
  th.textContent = th.textContent.replace(DR_SCENARIO.Forecast, 'Forecast Smart Query');
1277
1278
  }
1278
1279
  if (opts.chartOptions.table_options.hide_nulls_in_headers) {
@@ -1506,8 +1507,9 @@ let initDRPivotTable = function($, window, document) {
1506
1507
  for (l = 0, len1 = colHeaderCols.length; l < len1; l++) {
1507
1508
  colHeader = colHeaderCols[l];
1508
1509
  flatColKey = colHeader.flatKey;
1509
- if(tree && tree[flatRowKey] && tree[flatRowKey][flatColKey]){
1510
- ref8 = tree[flatRowKey][flatColKey]
1510
+ const sqAgg = pivotData.isSmartQueriesEnabled && tree ? getSqAggregator(tree, rowHeader.key, flatColKey) : null;
1511
+ if(sqAgg || (tree && tree[flatRowKey] && tree[flatRowKey][flatColKey])){
1512
+ ref8 = sqAgg || tree[flatRowKey][flatColKey]
1511
1513
  }
1512
1514
  else{
1513
1515
  ref8 = null;
@@ -1522,13 +1524,6 @@ let initDRPivotTable = function($, window, document) {
1522
1524
  }
1523
1525
  };
1524
1526
  val = aggregator.value();
1525
-
1526
- if (opts.chartOptions.isSmartQueriesEnabled && flatRowKey.split(' , ').includes(DR_SCENARIO.Forecast)) {
1527
- const actualsRow = tree[flatRowKey.replace(DR_SCENARIO.Forecast, DR_SCENARIO.SQ_Actuals)] || {};
1528
- if (actualsRow && actualsRow[flatColKey]) {
1529
- val += (actualsRow[flatColKey] && actualsRow[flatColKey].value()) || 0;
1530
- }
1531
- }
1532
1527
  isColSubtotal = colHeader.children.length !== 0;
1533
1528
  style = "pvtVal";
1534
1529
  if (isColSubtotal) {
@@ -1571,9 +1566,6 @@ let initDRPivotTable = function($, window, document) {
1571
1566
  }
1572
1567
 
1573
1568
  val = totalAggregator.value();
1574
- if (opts.chartOptions.isSmartQueriesEnabled && flatRowKey.split(' , ').includes(DR_SCENARIO.Forecast)) {
1575
- val += _.get(rowTotals[flatRowKey.replace(DR_SCENARIO.Forecast, DR_SCENARIO.SQ_Actuals)], 'value', () => null)() || 0;
1576
- }
1577
1569
  style = "pvtTotal rowTotal";
1578
1570
  if (isRowSubtotal) {
1579
1571
  style += " pvtRowSubtotal";
@@ -1694,7 +1686,7 @@ let initDRPivotTable = function($, window, document) {
1694
1686
  };
1695
1687
  removeRowHeaderNullValue = function(h) {
1696
1688
  if (opts.chartOptions.table_options.hide_nulls_in_headers) {
1697
- h.th.innerHTML = h.th.innerHTML.replace('[null]' , '');
1689
+ h.th.innerHTML = h.th.innerHTML.replace('[null]', '');
1698
1690
  }
1699
1691
  };
1700
1692
  hideDescendantCol = function(d) {
@@ -2354,7 +2346,7 @@ let initDRPivotTable = function($, window, document) {
2354
2346
  }
2355
2347
 
2356
2348
  main = function(rowAttrs, rowKeys, colAttrs, colKeys, pivotData) {
2357
- if (opts.chartOptions.isSmartQueriesEnabled) {
2349
+ if (pivotData.isSmartQueriesEnabled) {
2358
2350
  rowKeys = rowKeys.filter(rowKey => !rowKey.includes(DR_SCENARIO.SQ_Actuals));
2359
2351
  rowKeys = Array.from(
2360
2352
  new Set(rowKeys.map(JSON.stringify))
@@ -2516,7 +2508,7 @@ let initDRPivotTable = function($, window, document) {
2516
2508
  };
2517
2509
 
2518
2510
  $.pivotUtilities.subtotal_renderers = NovixRenderer;
2519
- $.pivotUtilities.delim = delim;
2511
+ $.pivotUtilities.delim = DELIMER;
2520
2512
 
2521
2513
  $.pivotUtilities.getFormattedNumber = getFormattedNumber;
2522
2514
  $.pivotUtilities.sortDateStrings = sortDateStrings;
@@ -85,7 +85,7 @@ const CHART_TYPES = {
85
85
  }
86
86
 
87
87
  const HIGHCHARTS_CONSTANTS = {
88
- delimer: ' , ',
88
+ delimer: helpers.DELIMER,
89
89
  DRILL_BUTTON_FONT_SIZE: '16px',
90
90
  MAX_ROWS_FOR_AUTO_REFRESH: 100000,
91
91
  MAX_ROWS_FOR_SHOW_RESULTS: 10000,
@@ -1274,10 +1274,10 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
1274
1274
  row_n_keys = pivotData.getRowKeys(),
1275
1275
  col_n_keys = pivotData.getColKeys();
1276
1276
  const chartType = chartOptions && chartOptions.chart && chartOptions.chart.type ? chartOptions.chart.type : null;
1277
- const isCombiLineForecastChart = opts.chartOptions.isSmartQueriesEnabled;
1278
1277
  const indexOfScenarioCycleFilter = lodash.findIndex(pivotData.rowAttrs, (rowAttr) => rowAttr === 'Scenario Cycle');
1278
+ const withExtraScenarioCycle = pivotData.rowAttrs && row_n_keys[0] && pivotData.rowAttrs.length < row_n_keys[0].length
1279
1279
 
1280
- if (isChartTypeSupportedForSmartQuery(chartType) && pivotData.rowAttrs?.length < row_n_keys?.[0]?.length && indexOfScenarioCycleFilter > -1) {
1280
+ if (isChartTypeSupportedForSmartQuery(chartType) && withExtraScenarioCycle && indexOfScenarioCycleFilter > -1) {
1281
1281
  const indexOfScenarioFilter = row_n_keys[0].length - 1;
1282
1282
  for (let i = 0; i < row_n_keys?.length; i++) {
1283
1283
  row_n_keys[i].splice(indexOfScenarioFilter, 1);
@@ -1454,7 +1454,7 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
1454
1454
  col_n_keys.forEach(columnKey => {
1455
1455
  let totalKey = columnKey;
1456
1456
  if (lodash.isArray(columnKey)) {
1457
- totalKey = totalKey.join(' , ');
1457
+ totalKey = totalKey.join(helpers.DELIMER);
1458
1458
  }
1459
1459
  const value = pivotData.colTotals[totalKey] ? pivotData.colTotals[totalKey].value() : 0;
1460
1460
  newSeries.data.push(value);
@@ -1466,26 +1466,10 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
1466
1466
  chart_series = chart_series.concat(trendSerieses);
1467
1467
 
1468
1468
  highchartsRenderer.moveSeriesToSecondYAxisIfNeeded(chart_series, pivotData, chartOptions, additionOptions, opts, opts.total && opts.totalSeriesSettings && opts.totalSeriesSettings.secondaryAxis);
1469
- const smartQuerySeries = isChartTypeSupportedForSmartQuery(chartType)
1470
- ? smartQueriesHelper.createSingleDataSeriesForForecast(chart_series, opts.chartOptions, pivotData, isCombiLineForecastChart)
1471
- : null;
1472
1469
 
1473
- if (smartQuerySeries) {
1474
- if (chart_series.length > 1) {
1475
- if (isCombiLineForecastChart) {
1476
- chart_series = smartQuerySeries;
1477
- } else {
1478
- lodash.remove(chart_series, s =>
1479
- (s.name && lodash.includes(s.name, 'SQ_Actuals')) || s.name === 'Forecast'
1480
- );
1481
- chart_series.push(smartQuerySeries);
1482
- }
1483
- } else {
1484
- chart_series = [smartQuerySeries];
1485
- }
1486
- }
1470
+ if (!opts.chartOptions || !opts.chartOptions.chart || !opts.chartOptions.chart.smart_query || !pivotData.isSmartQueriesEnabled) return chart_series;
1487
1471
 
1488
- return chart_series;
1472
+ return smartQueriesHelper.handleForecastSeries(chart_series, opts.chartOptions, pivotData)
1489
1473
  };
1490
1474
 
1491
1475
  highchartsRenderer.ptCreateColumnSeries = function (pivotData, colors, onlyNumbers, isUniqueVals, isNotDrilldown, additionOptions, opts, chartOptions, chartType) {
@@ -4856,7 +4840,6 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
4856
4840
  dateValuesDictionary: pivotOptions ? pivotOptions.dateValuesDictionary : null,
4857
4841
  keysObject: pivotOptions ? pivotOptions.keysObject : null,
4858
4842
  isDrillDownDisabled: pivotOptions ? pivotOptions.isDrillDownDisabled : false,
4859
- pivotUiFnRemoved: pivotOptions ? pivotOptions.pivotUiFnRemoved : false,
4860
4843
  };
4861
4844
 
4862
4845
  if (!subopts.rendererOptions) {
@@ -10099,13 +10082,6 @@ let getHighchartsRenderer = function ($, document, Highcharts, default_colors, h
10099
10082
  e.point = lodash.cloneDeep(e.point);
10100
10083
  e.point.name = e.point.initialName;
10101
10084
  e.point.series.name = lodash.get(e.point.series, 'userOptions.initialName', e.point.series.name);
10102
- const seriesData = lodash.get(e.point.series, 'userOptions.data');
10103
- const initialSeriesName = seriesData
10104
- ? lodash.find(seriesData, obj => obj.name === e.point.name)
10105
- : null;
10106
- if (initialSeriesName && initialSeriesName.type && ['SQ_Actuals', 'Forecast'].includes(initialSeriesName.type)) {
10107
- e.point.series.name = 'Forecast';
10108
- }
10109
10085
  lodash.set(e, 'point.category.userOptions', e.point.initialName.toString().split(highchartsRenderer.delimer));
10110
10086
  }
10111
10087
 
package/src/pivottable.js CHANGED
@@ -1,4 +1,6 @@
1
+ const _ = require('lodash');
1
2
  const helpers = require('./dr-renderer-helpers');
3
+ const { DR_SCENARIO } = require('./smart_queries_helper');
2
4
  const { GenericRenderingError, GenericComputationalError} = require('./errors');
3
5
 
4
6
  // from pivottable@2.23.0
@@ -641,7 +643,7 @@ let initPivotTable = function($, window, document) {
641
643
  this.filter = (ref9 = opts.filter) != null ? ref9 : (function() {
642
644
  return true;
643
645
  });
644
- this.isSmartQueriesEnabled = opts.rendererOptions?.chartOptions?.isSmartQueriesEnabled || false;
646
+ this.isSmartQueriesEnabled = _.some(input, item => item.Scenario === DR_SCENARIO.SQ_Actuals);
645
647
  this.tree = {};
646
648
 
647
649
  this.isKeysSortingDoneOnBackendSide = opts.keysObject && typeof opts.keysObject === 'object' && helpers.backendSortingKeysAreNotEmpty(opts.keysObject);
@@ -666,7 +668,6 @@ let initPivotTable = function($, window, document) {
666
668
  this.getFormattedColKeys = (keys) => opts.getFormattedColKeys(this, keys);
667
669
  this.getFormattedRowKeys = (keys) => opts.getFormattedRowKeys(this, keys);
668
670
  this.isDrillDownDisabled = opts.isDrillDownDisabled;
669
- this.pivotUiFnRemoved = opts.pivotUiFnRemoved;
670
671
 
671
672
  PivotData.forEachRecord(this.input, this.derivedAttributes, (function(_this) {
672
673
  return function(record) {
@@ -1212,508 +1213,6 @@ let initPivotTable = function($, window, document) {
1212
1213
  return this.append(result);
1213
1214
  };
1214
1215
 
1215
- /*
1216
- Pivot Table UI: calls Pivot Table core above with options set by user
1217
- */
1218
- $.fn.pivotUI = function(input, inputOpts, overwrite, locale) {
1219
- if (!this.pivotUiFnRemoved) {
1220
- var a, aggregator, attr, attrLength, attrValues, c, colOrderArrow, defaults, e, existingOpts, fn1, i, initialRender, l, len1, len2, len3, localeDefaults, localeStrings, materializedInput, n, o, opts, ordering, pivotTable, recordsProcessed, ref, ref1, ref2, ref3, refresh, refreshDelayed, renderer, rendererControl, rowOrderArrow, shownAttributes, shownInAggregators, shownInDragDrop, tr1, tr2, uiTable, unused, unusedAttrsVerticalAutoCutoff, unusedAttrsVerticalAutoOverride, x;
1221
- if (overwrite == null) {
1222
- overwrite = false;
1223
- }
1224
- if (locale == null) {
1225
- locale = "en";
1226
- }
1227
- if (locales[locale] == null) {
1228
- locale = "en";
1229
- }
1230
- defaults = {
1231
- derivedAttributes: {},
1232
- aggregators: locales[locale].aggregators,
1233
- renderers: locales[locale].renderers,
1234
- hiddenAttributes: [],
1235
- hiddenFromAggregators: [],
1236
- hiddenFromDragDrop: [],
1237
- menuLimit: 500,
1238
- cols: [],
1239
- rows: [],
1240
- vals: [],
1241
- rowOrder: "key_a_to_z",
1242
- colOrder: "key_a_to_z",
1243
- dataClass: PivotData,
1244
- exclusions: {},
1245
- inclusions: {},
1246
- unusedAttrsVertical: 85,
1247
- autoSortUnusedAttrs: false,
1248
- onRefresh: null,
1249
- showUI: true,
1250
- filter: function() {
1251
- return true;
1252
- },
1253
- sorters: {}
1254
- };
1255
- localeStrings = $.extend(true, {}, locales.en.localeStrings, locales[locale].localeStrings);
1256
- localeDefaults = {
1257
- rendererOptions: {
1258
- localeStrings: localeStrings
1259
- },
1260
- localeStrings: localeStrings
1261
- };
1262
- existingOpts = this.data("pivotUIOptions");
1263
- if ((existingOpts == null) || overwrite) {
1264
- opts = $.extend(true, {}, localeDefaults, $.extend({}, defaults, inputOpts));
1265
- } else {
1266
- opts = existingOpts;
1267
- }
1268
- try {
1269
- attrValues = {};
1270
- materializedInput = [];
1271
- recordsProcessed = 0;
1272
- PivotData.forEachRecord(input, opts.derivedAttributes, function(record) {
1273
- var attr, base, ref, value;
1274
- if (!opts.filter(record)) {
1275
- return;
1276
- }
1277
- materializedInput.push(record);
1278
- for (attr in record) {
1279
- if (!hasProp.call(record, attr)) continue;
1280
- if (attrValues[attr] == null) {
1281
- attrValues[attr] = {};
1282
- if (recordsProcessed > 0) {
1283
- attrValues[attr]["null"] = recordsProcessed;
1284
- }
1285
- }
1286
- }
1287
- for (attr in attrValues) {
1288
- value = (ref = record[attr]) != null ? ref : "null";
1289
- if ((base = attrValues[attr])[value] == null) {
1290
- base[value] = 0;
1291
- }
1292
- attrValues[attr][value]++;
1293
- }
1294
- return recordsProcessed++;
1295
- });
1296
- uiTable = $("<table>", {
1297
- "class": "pvtUi"
1298
- }).attr("cellpadding", 5);
1299
- rendererControl = $("<td>").addClass("pvtUiCell");
1300
- renderer = $("<select>").addClass('pvtRenderer').appendTo(rendererControl).bind("change", function() {
1301
- return refresh();
1302
- });
1303
- ref = opts.renderers;
1304
- for (x in ref) {
1305
- if (!hasProp.call(ref, x)) continue;
1306
- $("<option>").val(x).html(x).appendTo(renderer);
1307
- }
1308
- unused = $("<td>").addClass('pvtAxisContainer pvtUnused pvtUiCell');
1309
- shownAttributes = (function() {
1310
- var results;
1311
- results = [];
1312
- for (a in attrValues) {
1313
- if (indexOf.call(opts.hiddenAttributes, a) < 0) {
1314
- results.push(a);
1315
- }
1316
- }
1317
- return results;
1318
- })();
1319
- shownInAggregators = (function() {
1320
- var l, len1, results;
1321
- results = [];
1322
- for (l = 0, len1 = shownAttributes.length; l < len1; l++) {
1323
- c = shownAttributes[l];
1324
- if (indexOf.call(opts.hiddenFromAggregators, c) < 0) {
1325
- results.push(c);
1326
- }
1327
- }
1328
- return results;
1329
- })();
1330
- shownInDragDrop = (function() {
1331
- var l, len1, results;
1332
- results = [];
1333
- for (l = 0, len1 = shownAttributes.length; l < len1; l++) {
1334
- c = shownAttributes[l];
1335
- if (indexOf.call(opts.hiddenFromDragDrop, c) < 0) {
1336
- results.push(c);
1337
- }
1338
- }
1339
- return results;
1340
- })();
1341
- unusedAttrsVerticalAutoOverride = false;
1342
- if (opts.unusedAttrsVertical === "auto") {
1343
- unusedAttrsVerticalAutoCutoff = 120;
1344
- } else {
1345
- unusedAttrsVerticalAutoCutoff = parseInt(opts.unusedAttrsVertical);
1346
- }
1347
- if (!isNaN(unusedAttrsVerticalAutoCutoff)) {
1348
- attrLength = 0;
1349
- for (l = 0, len1 = shownInDragDrop.length; l < len1; l++) {
1350
- a = shownInDragDrop[l];
1351
- attrLength += a.length;
1352
- }
1353
- unusedAttrsVerticalAutoOverride = attrLength > unusedAttrsVerticalAutoCutoff;
1354
- }
1355
- if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
1356
- unused.addClass('pvtVertList');
1357
- } else {
1358
- unused.addClass('pvtHorizList');
1359
- }
1360
- fn1 = function(attr) {
1361
- var attrElem, checkContainer, closeFilterBox, controls, filterItem, filterItemExcluded, finalButtons, hasExcludedItem, len2, n, placeholder, ref1, sorter, triangleLink, v, value, valueCount, valueList, values;
1362
- values = (function() {
1363
- var results;
1364
- results = [];
1365
- for (v in attrValues[attr]) {
1366
- results.push(v);
1367
- }
1368
- return results;
1369
- })();
1370
- hasExcludedItem = false;
1371
- valueList = $("<div>").addClass('pvtFilterBox').hide();
1372
- valueList.append($("<h4>").append($("<span>").text(attr), $("<span>").addClass("count").text("(" + values.length + ")")));
1373
- if (values.length > opts.menuLimit) {
1374
- valueList.append($("<p>").html(opts.localeStrings.tooMany));
1375
- } else {
1376
- if (values.length > 5) {
1377
- controls = $("<p>").appendTo(valueList);
1378
- sorter = getSort(opts.sorters, attr);
1379
- placeholder = opts.localeStrings.filterResults;
1380
- $("<input>", {
1381
- type: "text"
1382
- }).appendTo(controls).attr({
1383
- placeholder: placeholder,
1384
- "class": "pvtSearch"
1385
- }).bind("keyup", function() {
1386
- var accept, accept_gen, filter;
1387
- filter = $(this).val().toLowerCase().trim();
1388
- accept_gen = function(prefix, accepted) {
1389
- return function(v) {
1390
- var real_filter, ref1;
1391
- real_filter = filter.substring(prefix.length).trim();
1392
- if (real_filter.length === 0) {
1393
- return true;
1394
- }
1395
- return ref1 = Math.sign(sorter(v.toLowerCase(), real_filter)), indexOf.call(accepted, ref1) >= 0;
1396
- };
1397
- };
1398
- accept = filter.indexOf(">=") === 0 ? accept_gen(">=", [1, 0]) : filter.indexOf("<=") === 0 ? accept_gen("<=", [-1, 0]) : filter.indexOf(">") === 0 ? accept_gen(">", [1]) : filter.indexOf("<") === 0 ? accept_gen("<", [-1]) : filter.indexOf("~") === 0 ? function(v) {
1399
- if (filter.substring(1).trim().length === 0) {
1400
- return true;
1401
- }
1402
- return v.toLowerCase().match(filter.substring(1));
1403
- } : function(v) {
1404
- return v.toLowerCase().indexOf(filter) !== -1;
1405
- };
1406
- return valueList.find('.pvtCheckContainer p label span.value').each(function() {
1407
- if (accept($(this).text())) {
1408
- return $(this).parent().parent().show();
1409
- } else {
1410
- return $(this).parent().parent().hide();
1411
- }
1412
- });
1413
- });
1414
- controls.append($("<br>"));
1415
- $("<button>", {
1416
- type: "button"
1417
- }).appendTo(controls).html(opts.localeStrings.selectAll).bind("click", function() {
1418
- valueList.find("input:visible:not(:checked)").prop("checked", true).toggleClass("changed");
1419
- return false;
1420
- });
1421
- $("<button>", {
1422
- type: "button"
1423
- }).appendTo(controls).html(opts.localeStrings.selectNone).bind("click", function() {
1424
- valueList.find("input:visible:checked").prop("checked", false).toggleClass("changed");
1425
- return false;
1426
- });
1427
- }
1428
- checkContainer = $("<div>").addClass("pvtCheckContainer").appendTo(valueList);
1429
- ref1 = values.sort(getSort(opts.sorters, attr));
1430
- for (n = 0, len2 = ref1.length; n < len2; n++) {
1431
- value = ref1[n];
1432
- valueCount = attrValues[attr][value];
1433
- filterItem = $("<label>");
1434
- filterItemExcluded = false;
1435
- if (opts.inclusions[attr]) {
1436
- filterItemExcluded = (indexOf.call(opts.inclusions[attr], value) < 0);
1437
- } else if (opts.exclusions[attr]) {
1438
- filterItemExcluded = (indexOf.call(opts.exclusions[attr], value) >= 0);
1439
- }
1440
- hasExcludedItem || (hasExcludedItem = filterItemExcluded);
1441
- $("<input>").attr("type", "checkbox").addClass('pvtFilter').attr("checked", !filterItemExcluded).data("filter", [attr, value]).appendTo(filterItem).bind("change", function() {
1442
- return $(this).toggleClass("changed");
1443
- });
1444
- filterItem.append($("<span>").addClass("value").text(value));
1445
- filterItem.append($("<span>").addClass("count").text("(" + valueCount + ")"));
1446
- checkContainer.append($("<p>").append(filterItem));
1447
- }
1448
- }
1449
- closeFilterBox = function() {
1450
- if (valueList.find("[type='checkbox']").length > valueList.find("[type='checkbox']:checked").length) {
1451
- attrElem.addClass("pvtFilteredAttribute");
1452
- } else {
1453
- attrElem.removeClass("pvtFilteredAttribute");
1454
- }
1455
- valueList.find('.pvtSearch').val('');
1456
- valueList.find('.pvtCheckContainer p').show();
1457
- return valueList.hide();
1458
- };
1459
- finalButtons = $("<p>").appendTo(valueList);
1460
- if (values.length <= opts.menuLimit) {
1461
- $("<button>", {
1462
- type: "button"
1463
- }).text(opts.localeStrings.apply).appendTo(finalButtons).bind("click", function() {
1464
- if (valueList.find(".changed").removeClass("changed").length) {
1465
- refresh();
1466
- }
1467
- return closeFilterBox();
1468
- });
1469
- }
1470
- $("<button>", {
1471
- type: "button"
1472
- }).text(opts.localeStrings.cancel).appendTo(finalButtons).bind("click", function() {
1473
- valueList.find(".changed:checked").removeClass("changed").prop("checked", false);
1474
- valueList.find(".changed:not(:checked)").removeClass("changed").prop("checked", true);
1475
- return closeFilterBox();
1476
- });
1477
- triangleLink = $("<span>").addClass('pvtTriangle').html(" &#x25BE;").bind("click", function(e) {
1478
- var left, ref2, top;
1479
- ref2 = $(e.currentTarget).position(), left = ref2.left, top = ref2.top;
1480
- return valueList.css({
1481
- left: left + 10,
1482
- top: top + 10
1483
- }).show();
1484
- });
1485
- attrElem = $("<li>").addClass("axis_" + i).append($("<span>").addClass('pvtAttr').text(attr).data("attrName", attr).append(triangleLink));
1486
- if (hasExcludedItem) {
1487
- attrElem.addClass('pvtFilteredAttribute');
1488
- }
1489
- return unused.append(attrElem).append(valueList);
1490
- };
1491
- for (i in shownInDragDrop) {
1492
- if (!hasProp.call(shownInDragDrop, i)) continue;
1493
- attr = shownInDragDrop[i];
1494
- fn1(attr);
1495
- }
1496
- tr1 = $("<tr>").appendTo(uiTable);
1497
- aggregator = $("<select>").addClass('pvtAggregator').bind("change", function() {
1498
- return refresh();
1499
- });
1500
- ref1 = opts.aggregators;
1501
- for (x in ref1) {
1502
- if (!hasProp.call(ref1, x)) continue;
1503
- aggregator.append($("<option>").val(x).html(x));
1504
- }
1505
- ordering = {
1506
- key_a_to_z: {
1507
- rowSymbol: "&varr;",
1508
- colSymbol: "&harr;",
1509
- next: "value_a_to_z"
1510
- },
1511
- value_a_to_z: {
1512
- rowSymbol: "&darr;",
1513
- colSymbol: "&rarr;",
1514
- next: "value_z_to_a"
1515
- },
1516
- value_z_to_a: {
1517
- rowSymbol: "&uarr;",
1518
- colSymbol: "&larr;",
1519
- next: "key_a_to_z"
1520
- }
1521
- };
1522
- rowOrderArrow = $("<a>", {
1523
- role: "button"
1524
- }).addClass("pvtRowOrder").data("order", opts.rowOrder).html(ordering[opts.rowOrder].rowSymbol).bind("click", function() {
1525
- $(this).data("order", ordering[$(this).data("order")].next);
1526
- $(this).html(ordering[$(this).data("order")].rowSymbol);
1527
- return refresh();
1528
- });
1529
- colOrderArrow = $("<a>", {
1530
- role: "button"
1531
- }).addClass("pvtColOrder").data("order", opts.colOrder).html(ordering[opts.colOrder].colSymbol).bind("click", function() {
1532
- $(this).data("order", ordering[$(this).data("order")].next);
1533
- $(this).html(ordering[$(this).data("order")].colSymbol);
1534
- return refresh();
1535
- });
1536
- $("<td>").addClass('pvtVals pvtUiCell').appendTo(tr1).append(aggregator).append(rowOrderArrow).append(colOrderArrow).append($("<br>"));
1537
- $("<td>").addClass('pvtAxisContainer pvtHorizList pvtCols pvtUiCell').appendTo(tr1);
1538
- tr2 = $("<tr>").appendTo(uiTable);
1539
- tr2.append($("<td>").addClass('pvtAxisContainer pvtRows pvtUiCell').attr("valign", "top"));
1540
- pivotTable = $("<td>").attr("valign", "top").addClass('pvtRendererArea').appendTo(tr2);
1541
- if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
1542
- uiTable.find('tr:nth-child(1)').prepend(rendererControl);
1543
- uiTable.find('tr:nth-child(2)').prepend(unused);
1544
- } else {
1545
- uiTable.prepend($("<tr>").append(rendererControl).append(unused));
1546
- }
1547
- this.html(uiTable);
1548
- ref2 = opts.cols;
1549
- for (n = 0, len2 = ref2.length; n < len2; n++) {
1550
- x = ref2[n];
1551
- this.find(".pvtCols").append(this.find(".axis_" + ($.inArray(x, shownInDragDrop))));
1552
- }
1553
- ref3 = opts.rows;
1554
- for (o = 0, len3 = ref3.length; o < len3; o++) {
1555
- x = ref3[o];
1556
- this.find(".pvtRows").append(this.find(".axis_" + ($.inArray(x, shownInDragDrop))));
1557
- }
1558
- if (opts.aggregatorName != null) {
1559
- this.find(".pvtAggregator").val(opts.aggregatorName);
1560
- }
1561
- if (opts.rendererName != null) {
1562
- this.find(".pvtRenderer").val(opts.rendererName);
1563
- }
1564
- if (!opts.showUI) {
1565
- this.find(".pvtUiCell").hide();
1566
- }
1567
- initialRender = true;
1568
- refreshDelayed = (function(_this) {
1569
- return function() {
1570
- var exclusions, inclusions, len4, newDropdown, numInputsToProcess, pivotUIOptions, pvtVals, ref4, ref5, subopts, t, u, unusedAttrsContainer, vals;
1571
- subopts = {
1572
- derivedAttributes: opts.derivedAttributes,
1573
- localeStrings: opts.localeStrings,
1574
- rendererOptions: opts.rendererOptions,
1575
- sorters: opts.sorters,
1576
- cols: [],
1577
- rows: [],
1578
- dataClass: opts.dataClass
1579
- };
1580
- numInputsToProcess = (ref4 = opts.aggregators[aggregator.val()]([])().numInputs) != null ? ref4 : 0;
1581
- vals = [];
1582
- _this.find(".pvtRows li span.pvtAttr").each(function() {
1583
- return subopts.rows.push($(this).data("attrName"));
1584
- });
1585
- _this.find(".pvtCols li span.pvtAttr").each(function() {
1586
- return subopts.cols.push($(this).data("attrName"));
1587
- });
1588
- _this.find(".pvtVals select.pvtAttrDropdown").each(function() {
1589
- if (numInputsToProcess === 0) {
1590
- return $(this).remove();
1591
- } else {
1592
- numInputsToProcess--;
1593
- if ($(this).val() !== "") {
1594
- return vals.push($(this).val());
1595
- }
1596
- }
1597
- });
1598
- if (numInputsToProcess !== 0) {
1599
- pvtVals = _this.find(".pvtVals");
1600
- for (x = t = 0, ref5 = numInputsToProcess; 0 <= ref5 ? t < ref5 : t > ref5; x = 0 <= ref5 ? ++t : --t) {
1601
- newDropdown = $("<select>").addClass('pvtAttrDropdown').append($("<option>")).bind("change", function() {
1602
- return refresh();
1603
- });
1604
- for (u = 0, len4 = shownInAggregators.length; u < len4; u++) {
1605
- attr = shownInAggregators[u];
1606
- newDropdown.append($("<option>").val(attr).text(attr));
1607
- }
1608
- pvtVals.append(newDropdown);
1609
- }
1610
- }
1611
- if (initialRender) {
1612
- vals = opts.vals;
1613
- i = 0;
1614
- _this.find(".pvtVals select.pvtAttrDropdown").each(function() {
1615
- $(this).val(vals[i]);
1616
- return i++;
1617
- });
1618
- initialRender = false;
1619
- }
1620
- subopts.aggregatorName = aggregator.val();
1621
- subopts.vals = vals;
1622
- subopts.aggregator = opts.aggregators[aggregator.val()](vals);
1623
- subopts.renderer = opts.renderers[renderer.val()];
1624
- subopts.rowOrder = rowOrderArrow.data("order");
1625
- subopts.colOrder = colOrderArrow.data("order");
1626
- exclusions = {};
1627
- _this.find('input.pvtFilter').not(':checked').each(function() {
1628
- var filter;
1629
- filter = $(this).data("filter");
1630
- if (exclusions[filter[0]] != null) {
1631
- return exclusions[filter[0]].push(filter[1]);
1632
- } else {
1633
- return exclusions[filter[0]] = [filter[1]];
1634
- }
1635
- });
1636
- inclusions = {};
1637
- _this.find('input.pvtFilter:checked').each(function() {
1638
- var filter;
1639
- filter = $(this).data("filter");
1640
- if (exclusions[filter[0]] != null) {
1641
- if (inclusions[filter[0]] != null) {
1642
- return inclusions[filter[0]].push(filter[1]);
1643
- } else {
1644
- return inclusions[filter[0]] = [filter[1]];
1645
- }
1646
- }
1647
- });
1648
- subopts.filter = function(record) {
1649
- var excludedItems, k, ref6, ref7;
1650
- if (!opts.filter(record)) {
1651
- return false;
1652
- }
1653
- for (k in exclusions) {
1654
- excludedItems = exclusions[k];
1655
- if (ref6 = "" + ((ref7 = record[k]) != null ? ref7 : 'null'), indexOf.call(excludedItems, ref6) >= 0) {
1656
- return false;
1657
- }
1658
- }
1659
- return true;
1660
- };
1661
- pivotTable.pivot(materializedInput, subopts);
1662
- pivotUIOptions = $.extend({}, opts, {
1663
- cols: subopts.cols,
1664
- rows: subopts.rows,
1665
- colOrder: subopts.colOrder,
1666
- rowOrder: subopts.rowOrder,
1667
- vals: vals,
1668
- exclusions: exclusions,
1669
- inclusions: inclusions,
1670
- inclusionsInfo: inclusions,
1671
- aggregatorName: aggregator.val(),
1672
- rendererName: renderer.val()
1673
- });
1674
- _this.data("pivotUIOptions", pivotUIOptions);
1675
- if (opts.autoSortUnusedAttrs) {
1676
- unusedAttrsContainer = _this.find("td.pvtUnused.pvtAxisContainer");
1677
- $(unusedAttrsContainer).children("li").sort(function(a, b) {
1678
- return naturalSort($(a).text(), $(b).text());
1679
- }).appendTo(unusedAttrsContainer);
1680
- }
1681
- pivotTable.css("opacity", 1);
1682
- if (opts.onRefresh != null) {
1683
- return opts.onRefresh(pivotUIOptions);
1684
- }
1685
- };
1686
- })(this);
1687
- refresh = (function(_this) {
1688
- return function() {
1689
- pivotTable.css("opacity", 0.5);
1690
- return setTimeout(refreshDelayed, 10);
1691
- };
1692
- })(this);
1693
- refresh();
1694
- this.find(".pvtAxisContainer").sortable({
1695
- update: function(e, ui) {
1696
- if (ui.sender == null) {
1697
- return refresh();
1698
- }
1699
- },
1700
- connectWith: this.find(".pvtAxisContainer"),
1701
- items: 'li',
1702
- placeholder: 'pvtPlaceholder'
1703
- });
1704
- } catch (error) {
1705
- e = error;
1706
- if (typeof console !== "undefined" && console !== null) {
1707
- console.error(e.stack);
1708
- }
1709
- // This function is not used internally or in webclient_angular/export_widget_service
1710
- // TODO if it not removed in DR-39041, upgrade the error propagation
1711
- this.html("An error occurred rendering the PivotTable UI.");
1712
- }
1713
- return this;
1714
- }
1715
- };
1716
-
1717
1216
  /*
1718
1217
  Heatmap post-processing
1719
1218
  */
@@ -1,144 +1,69 @@
1
- const lodash = require('lodash');
1
+ const _ = require('lodash');
2
+ const { DELIMER } = require('./dr-renderer-helpers');
2
3
 
3
4
  const DR_SCENARIO = {
4
5
  SQ_Actuals: 'SQ_Actuals',
5
6
  Forecast: 'Forecast',
6
7
  };
7
8
 
8
- function createSingleDataSeriesForForecast(chart_series, chartOptions, pivotData, isChartCombiLine) {
9
- if (!chartOptions || !chartOptions.chart) return null;
10
-
11
- const { actuals, forecast, smart_query } = chartOptions.chart;
12
- const input = pivotData.input;
13
-
14
- const hasSQActuals = lodash.some(input, item => lodash.includes(item.Scenario, DR_SCENARIO.SQ_Actuals));
15
- chartOptions.isSmartQueriesEnabled = hasSQActuals;
16
- if (!smart_query || !hasSQActuals) return null;
17
-
18
- const midMonthOffset = 0.5
19
- return chart_series.length === 1
20
- ? buildChartSeriesFromPivotInputOnly(input, actuals, forecast, midMonthOffset, chart_series[0].name)
21
- : (isChartCombiLine ?
22
- buildChartSeriesForMultipleSeriesCombinedLine(chart_series, input, actuals, forecast, midMonthOffset) :
23
- buildChartSeriesFromSeries(chart_series, actuals, forecast, midMonthOffset));
24
- }
25
-
26
- function buildChartSeriesFromPivotInputOnly(input, actuals, forecast, midMonthOffset, name) {
27
- const filtered = input.filter(item =>
28
- (item.Scenario === DR_SCENARIO.SQ_Actuals || item.Scenario === DR_SCENARIO.Forecast) && !!item['Reporting Month']
29
- );
30
-
31
- const data = lodash.map(filtered, item => ({
32
- y: item.Amount,
33
- name: item['Reporting Month'],
34
- initialName: item['Reporting Month'],
35
- type: item.Scenario,
36
- })).sort((a, b) => sortRowValuesByName(a, b));
37
-
38
- const sqCount = lodash.filter(input, item => item.Scenario === DR_SCENARIO.SQ_Actuals).length;
39
-
40
- return {
41
- name,
42
- data,
43
- zoneAxis: "x",
44
- zones: [
45
- { value: sqCount - midMonthOffset, dashStyle: actuals },
46
- { dashStyle: forecast },
47
- ],
48
- };
49
- }
50
-
51
- function buildChartSeriesForMultipleSeriesCombinedLine(chart_series, input, actuals, forecast, midMonthOffset) {
52
- const resultingSeries = [];
53
- for (let i = 0; i < chart_series.length; i++) {
54
- const series = chart_series[i];
55
- if (!series || !series.data || !series.data.length) continue;
9
+ /**
10
+ * @param tree {DRPivotData['tree']}
11
+ * @param rowKey {string[]} ['6+6', 'Forecast 6+6 Mid'] OR ['6+6', 'SQ_Actuals']
12
+ * @param flatColKey {string} 'Jan-25'
13
+ * @returns {object|null} A aggregator object of SQ_Actuals or null if not found
14
+ */
15
+ function getSqAggregator(tree, rowKey, flatColKey) {
16
+ const uniqueRowKeys = _.uniq(rowKey);
17
+
18
+ // if we have only scenarioCycle (uniqueRowKeys[1] is undefined) default aggregator should handle fine
19
+ // SQ_Actuals should be used only for Forecast items, if current item is SQ_Actuals we just ignore it
20
+ if(!uniqueRowKeys[1] || uniqueRowKeys[1] === DR_SCENARIO.SQ_Actuals) {
21
+ return null;
22
+ }
56
23
 
57
- const data = lodash.chain(input)
58
- .filter(item => item['Scenario Cycle'] === series.name &&
59
- (item['Scenario'] === DR_SCENARIO.SQ_Actuals || item['Scenario'] === DR_SCENARIO.Forecast) && !!item['Reporting Month'])
60
- .map(item => ({
61
- y: item.Amount,
62
- name: item['Reporting Month'],
63
- initialName: item['Reporting Month'],
64
- type: item.Scenario,
65
- }))
66
- .value().sort((a, b) => {
67
- return sortRowValuesByName(a, b);
68
- });
69
- if (!data.length) {
70
- resultingSeries.push(series);
71
- continue;
72
- }
24
+ // at this point rowKey should be something like ['6+6', 'Forecast 6+6 Mid', ...]
25
+ // SQ_Actuals always contains scenarioCycle at 0 position ('6+6') and repeats 'SQ_Actuals' for rest of the rows
26
+ const sqFlatRowKey = _.map(rowKey, (key, index) => index === 0 ? key : DR_SCENARIO.SQ_Actuals).join(DELIMER)
73
27
 
74
- const sqCount = lodash.filter(data, item => item.type === DR_SCENARIO.SQ_Actuals).length;
75
- resultingSeries.push(
76
- {
77
- name: series.name,
78
- data,
79
- zoneAxis: "x",
80
- zones: [
81
- { value: sqCount - midMonthOffset, dashStyle: actuals },
82
- { dashStyle: forecast },
83
- ],
84
- }
85
- )
86
- }
87
- return resultingSeries;
28
+ return tree[sqFlatRowKey] ? tree[sqFlatRowKey][flatColKey] : null;
88
29
  }
89
30
 
90
- function sortRowValuesByName(rowValueA, rowValueB) {
91
- const aDate = new Date(rowValueA.name);
92
- const bDate = new Date(rowValueB.name);
93
- return !isNaN(aDate.getTime()) && !isNaN(bDate.getTime()) ? aDate - bDate : rowValueA.name.localeCompare(rowValueB.name);
31
+ function handleForecastSeries(chart_series, chartOptions, pivotData) {
32
+ const midMonthOffset = 0.5;
33
+ const sqInput = _.filter(pivotData.input, item => item['Scenario'] === DR_SCENARIO.SQ_Actuals);
34
+ const noSqSeries = _.filter(chart_series, (s) => !_.includes(s.name, DR_SCENARIO.SQ_Actuals)); // SQ_Actuals are just base for forecast
35
+
36
+ return _.map(noSqSeries, series => {
37
+ const itemScenario = getSqScenarioCycle(series.name);
38
+ const sqCount = _.filter(sqInput, item => _.startsWith(pivotData.getFlatKey(item, pivotData.rowAttrs), itemScenario)).length;
39
+
40
+ if(!sqCount) return series;
41
+
42
+ return {
43
+ name: series.name,
44
+ data: series.data,
45
+ zoneAxis: "x",
46
+ zones: [
47
+ { value: sqCount - midMonthOffset, dashStyle: chartOptions.chart.actuals },
48
+ { dashStyle: chartOptions.chart.forecast },
49
+ ],
50
+ }
51
+ })
94
52
  }
95
53
 
96
- function buildChartSeriesFromSeries(chart_series, actuals, forecast, midMonthOffset) {
97
- const seriesA = lodash.find(chart_series, s => s.name && lodash.includes(s.name, DR_SCENARIO.SQ_Actuals));
98
- const seriesB = lodash.find(chart_series, s => s.name && lodash.includes(s.name, DR_SCENARIO.Forecast));
99
-
100
- if (!seriesA || !seriesB) return null;
101
-
102
- const indexOfForecastFirstZero = lodash.findIndex(seriesB.data, function(value) {
103
- return value.y === 0;
104
- });
105
- const indexOfActualsFirstZero = lodash.findIndex(seriesA.data, function(value) {
106
- return value.y === 0;
107
- });
108
- const cutoffIndex = Math.max(indexOfForecastFirstZero, indexOfActualsFirstZero);
109
-
110
-
111
- const minLength = Math.min(seriesA.data.length, seriesB.data.length);
112
- const data = [];
113
-
114
- for (let i = 0; i < minLength; i++) {
115
- const pointA = seriesA.data[i];
116
- const pointB = seriesB.data[i];
117
-
118
- const yA = (pointA && pointA.y !== null && typeof pointA.y !== undefined) ? pointA.y : pointA;
119
- const yB = (pointB && pointB.y !== null && typeof pointB.y !== undefined) ? pointB.y : pointB;
120
-
121
- data.push({
122
- x: i,
123
- y: yA + yB,
124
- name: pointA && pointA.name ? pointA.name : null,
125
- initialName: (pointA && pointA.name) ? pointA.name : 'Point ' + (i + 1),
126
- type: yA ? DR_SCENARIO.SQ_Actuals : DR_SCENARIO.Forecast,
127
- });
128
- }
129
-
130
- return {
131
- name: "Forecast Smart Query",
132
- data,
133
- zoneAxis: "x",
134
- zones: [
135
- { value: cutoffIndex - midMonthOffset, dashStyle: actuals },
136
- { dashStyle: forecast },
137
- ],
138
- };
54
+ /**
55
+ * @example
56
+ * getSqScenarioCycle("6+6 , Forecast 6+6 Mid"); // "6+6"
57
+ * getSqScenarioCycle("6+6 , SQ_Actuals"); // "6+6"
58
+ *
59
+ * @returns {string|undefined}
60
+ */
61
+ function getSqScenarioCycle(name) {
62
+ return _.first(_.split(name, DELIMER));
139
63
  }
140
64
 
141
65
  module.exports = {
142
- createSingleDataSeriesForForecast,
66
+ getSqAggregator,
67
+ handleForecastSeries,
143
68
  DR_SCENARIO
144
69
  };