@genesislcap/pbc-reporting-ui 14.396.4 → 14.397.1

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 (70) hide show
  1. package/dist/dts/new/main/edit-config/datasource-config/datasource-config-item.d.ts +6 -2
  2. package/dist/dts/new/main/edit-config/datasource-config/datasource-config-item.d.ts.map +1 -1
  3. package/dist/dts/new/main/edit-config/datasource-config/datasource-config-item.styles.d.ts.map +1 -1
  4. package/dist/dts/new/main/edit-config/datasource-config/datasource-config-item.template.d.ts.map +1 -1
  5. package/dist/dts/new/main/edit-config/datasource-config/datasources-config-container.helpers.d.ts.map +1 -1
  6. package/dist/dts/new/main/edit-config/datasource-config/datasources-config-container.template.d.ts.map +1 -1
  7. package/dist/dts/new/main/edit-config/shared/datasource-data-base-component.helpers.ts.d.ts.map +1 -1
  8. package/dist/dts/new/store/slices/datasources-config.d.ts +19 -6
  9. package/dist/dts/new/store/slices/datasources-config.d.ts.map +1 -1
  10. package/dist/dts/new/store/slices/types.d.ts +19 -2
  11. package/dist/dts/new/store/slices/types.d.ts.map +1 -1
  12. package/dist/dts/new/store/store.d.ts +126 -35
  13. package/dist/dts/new/store/store.d.ts.map +1 -1
  14. package/dist/dts/new/types/misc.d.ts +4 -2
  15. package/dist/dts/new/types/misc.d.ts.map +1 -1
  16. package/dist/dts/new/utils/alias-generator.d.ts +8 -0
  17. package/dist/dts/new/utils/alias-generator.d.ts.map +1 -0
  18. package/dist/dts/new/utils/alias-generator.test.d.ts +2 -0
  19. package/dist/dts/new/utils/alias-generator.test.d.ts.map +1 -0
  20. package/dist/dts/new/utils/index.d.ts +1 -0
  21. package/dist/dts/new/utils/index.d.ts.map +1 -1
  22. package/dist/dts/new/utils/tooltip.d.ts +3 -0
  23. package/dist/dts/new/utils/tooltip.d.ts.map +1 -1
  24. package/dist/dts/new/utils/transformers.d.ts +1 -1
  25. package/dist/dts/new/utils/transformers.d.ts.map +1 -1
  26. package/dist/esm/new/main/edit-config/col-filters/col-filters-grid.helpers.test.js +39 -7
  27. package/dist/esm/new/main/edit-config/col-rename-alias/col-rename-alias-grid.helpers.test.js +32 -4
  28. package/dist/esm/new/main/edit-config/data-transforms-derived-fields/data-transforms.helpers.test.js +10 -2
  29. package/dist/esm/new/main/edit-config/datasource-config/datasource-config-item.js +100 -10
  30. package/dist/esm/new/main/edit-config/datasource-config/datasource-config-item.styles.js +6 -0
  31. package/dist/esm/new/main/edit-config/datasource-config/datasource-config-item.template.js +38 -3
  32. package/dist/esm/new/main/edit-config/datasource-config/datasources-config-container.helpers.js +11 -7
  33. package/dist/esm/new/main/edit-config/datasource-config/datasources-config-container.helpers.test.js +29 -22
  34. package/dist/esm/new/main/edit-config/datasource-config/datasources-config-container.template.js +3 -0
  35. package/dist/esm/new/main/edit-config/shared/datasource-data-base-component.helpers.ts.js +16 -8
  36. package/dist/esm/new/main/edit-config/shared/datasource-data-base-component.test.js +13 -2
  37. package/dist/esm/new/main/edit-config/tabbed-datasource-container/tabbed-datasource-container.template.js +1 -1
  38. package/dist/esm/new/store/slices/datasources-config.js +41 -5
  39. package/dist/esm/new/store/slices/types.js +1 -0
  40. package/dist/esm/new/utils/alias-generator.js +16 -0
  41. package/dist/esm/new/utils/alias-generator.test.js +36 -0
  42. package/dist/esm/new/utils/index.js +1 -0
  43. package/dist/esm/new/utils/tooltip.js +16 -0
  44. package/dist/esm/new/utils/transformers.js +20 -6
  45. package/dist/esm/new/utils/transformers.test.js +61 -11
  46. package/dist/esm/new/utils/validators.test.js +35 -21
  47. package/dist/tsconfig.tsbuildinfo +1 -1
  48. package/package.json +22 -22
  49. package/src/new/main/edit-config/col-filters/col-filters-grid.helpers.test.ts +39 -7
  50. package/src/new/main/edit-config/col-rename-alias/col-rename-alias-grid.helpers.test.ts +32 -4
  51. package/src/new/main/edit-config/data-transforms-derived-fields/data-transforms.helpers.test.ts +10 -2
  52. package/src/new/main/edit-config/datasource-config/datasource-config-item.styles.ts +6 -0
  53. package/src/new/main/edit-config/datasource-config/datasource-config-item.template.ts +62 -3
  54. package/src/new/main/edit-config/datasource-config/datasource-config-item.ts +107 -8
  55. package/src/new/main/edit-config/datasource-config/datasources-config-container.helpers.test.ts +32 -23
  56. package/src/new/main/edit-config/datasource-config/datasources-config-container.helpers.ts +18 -10
  57. package/src/new/main/edit-config/datasource-config/datasources-config-container.template.ts +6 -0
  58. package/src/new/main/edit-config/shared/datasource-data-base-component.helpers.ts.ts +21 -11
  59. package/src/new/main/edit-config/shared/datasource-data-base-component.test.ts +14 -2
  60. package/src/new/main/edit-config/tabbed-datasource-container/tabbed-datasource-container.template.ts +1 -1
  61. package/src/new/store/slices/datasources-config.ts +58 -7
  62. package/src/new/store/slices/types.ts +22 -4
  63. package/src/new/types/misc.ts +9 -2
  64. package/src/new/utils/alias-generator.test.ts +44 -0
  65. package/src/new/utils/alias-generator.ts +18 -0
  66. package/src/new/utils/index.ts +1 -0
  67. package/src/new/utils/tooltip.ts +19 -0
  68. package/src/new/utils/transformers.test.ts +73 -11
  69. package/src/new/utils/transformers.ts +30 -6
  70. package/src/new/utils/validators.test.ts +35 -21
@@ -154,14 +154,16 @@ CreateNewDatasourceConfig.before.each(() => {
154
154
  sinon.restore();
155
155
  });
156
156
  CreateNewDatasourceConfig('should exit when no valid datasources are available', () => __awaiter(void 0, void 0, void 0, function* () {
157
- const mockChoices = [{ name: 'test', inputType: 'REQ_REP' }];
157
+ const mockChoices = [{ name: 'testSource', inputType: 'REQ_REP' }];
158
158
  const getAllConfigSetStub = sinon.stub(selectors.datasourceConfig, 'getAllConfigSet').returns({
159
- REQ_REP_test: {
160
- KEY: 'REQ_REP_test',
161
- NAME: 'Test Datasource',
159
+ REQ_REP_testSource_testSource: {
160
+ KEY: 'testSource',
161
+ NAME: 'testSource',
162
162
  INPUT_TYPE: 'REQ_REP',
163
163
  OUTPUT_TYPE: 'TABLE',
164
164
  TRANSFORMER_CONFIGURATION: { INCLUDE_COLUMNS: [] },
165
+ GROUPING_STRATEGY: 'NONE',
166
+ GROUP_KEY: null,
165
167
  },
166
168
  });
167
169
  const loggerStub = sinon.stub(logger, 'error');
@@ -172,14 +174,16 @@ CreateNewDatasourceConfig('should exit when no valid datasources are available',
172
174
  assert.ok(!getSchemaStub.called);
173
175
  }));
174
176
  CreateNewDatasourceConfig('should exit when trying to add multiple datasources with CSV format', () => __awaiter(void 0, void 0, void 0, function* () {
175
- const mockChoices = [{ name: 'test', inputType: 'REQ_REP' }];
177
+ const mockChoices = [{ name: 'testSource', inputType: 'REQ_REP' }];
176
178
  const getAllConfigSetStub = sinon.stub(selectors.datasourceConfig, 'getAllConfigSet').returns({
177
- REQ_REP_existing: {
178
- KEY: 'REQ_REP_existing',
179
- NAME: 'Existing Datasource',
179
+ REQ_REP_existingSource_existingAlias: {
180
+ KEY: 'existingAlias',
181
+ NAME: 'existingSource',
180
182
  INPUT_TYPE: 'REQ_REP',
181
183
  OUTPUT_TYPE: 'TABLE',
182
184
  TRANSFORMER_CONFIGURATION: { INCLUDE_COLUMNS: [] },
185
+ GROUPING_STRATEGY: 'NONE',
186
+ GROUP_KEY: null,
183
187
  },
184
188
  });
185
189
  const getConfigStub = sinon.stub(selectors.baseConfig, 'getConfig').returns({
@@ -190,7 +194,7 @@ CreateNewDatasourceConfig('should exit when trying to add multiple datasources w
190
194
  const loggerStub = sinon.stub(logger, 'error');
191
195
  const getSchemaStub = sinon.stub().resolves({});
192
196
  yield createNewDatasourceConfig(getSchemaStub)(mockChoices);
193
- assert.equal(getAllConfigSetStub.callCount, 2, 'getAllConfigSetStub should be called twice');
197
+ assert.equal(getAllConfigSetStub.callCount, 1, 'getAllConfigSetStub should be called once');
194
198
  assert.equal(getConfigStub.callCount, 1, 'getConfigStub should be called once');
195
199
  // assert.ok(loggerStub.calledWith('Cannot add multiple datasources when using csv file without a template'));
196
200
  if (loggerStub.args.length > 0) {
@@ -202,14 +206,16 @@ CreateNewDatasourceConfig('should exit when trying to add multiple datasources w
202
206
  assert.equal(getSchemaStub.callCount, 0, 'getSchemaStub should not be called');
203
207
  }));
204
208
  CreateNewDatasourceConfig('should allow adding multiple datasources with CSV format IF template is selected', () => __awaiter(void 0, void 0, void 0, function* () {
205
- const mockChoices = [{ name: 'test', inputType: 'REQ_REP' }];
209
+ const mockChoices = [{ name: 'testSource', inputType: 'REQ_REP' }];
206
210
  const getAllConfigSetStub = sinon.stub(selectors.datasourceConfig, 'getAllConfigSet').returns({
207
- REQ_REP_existing: {
208
- KEY: 'REQ_REP_existing',
209
- NAME: 'Existing Datasource',
211
+ REQ_REP_existingSource_existingAlias: {
212
+ KEY: 'existingAlias',
213
+ NAME: 'existingSource',
210
214
  INPUT_TYPE: 'REQ_REP',
211
215
  OUTPUT_TYPE: 'TABLE',
212
216
  TRANSFORMER_CONFIGURATION: { INCLUDE_COLUMNS: [] },
217
+ GROUPING_STRATEGY: 'NONE',
218
+ GROUP_KEY: null,
213
219
  },
214
220
  });
215
221
  sinon.stub(selectors.baseConfig, 'getConfig').returns({
@@ -227,12 +233,12 @@ CreateNewDatasourceConfig('should allow adding multiple datasources with CSV for
227
233
  const getSchemaStub = sinon.stub().resolves(mockSchema);
228
234
  const initConfigStub = sinon.stub(actions.datasourceConfig, 'initDatasourceConfiguration');
229
235
  yield createNewDatasourceConfig(getSchemaStub)(mockChoices);
230
- assert.ok(getAllConfigSetStub.calledTwice);
236
+ assert.ok(getAllConfigSetStub.calledOnce);
231
237
  assert.ok(getSchemaStub.calledOnce);
232
238
  assert.ok(initConfigStub.called);
233
239
  }));
234
240
  CreateNewDatasourceConfig('should successfully create new datasource configuration', () => __awaiter(void 0, void 0, void 0, function* () {
235
- const mockChoices = [{ name: 'test', inputType: 'REQ_REP' }];
241
+ const mockChoices = [{ name: 'testSource', inputType: 'REQ_REP' }];
236
242
  const getAllConfigSetStub = sinon.stub(selectors.datasourceConfig, 'getAllConfigSet').returns({});
237
243
  sinon.stub(selectors.baseConfig, 'getConfig').returns({
238
244
  DESTINATION_IDS: [],
@@ -248,14 +254,15 @@ CreateNewDatasourceConfig('should successfully create new datasource configurati
248
254
  const getSchemaStub = sinon.stub().resolves(mockSchema);
249
255
  const initConfigStub = sinon.stub(actions.datasourceConfig, 'initDatasourceConfiguration');
250
256
  yield createNewDatasourceConfig(getSchemaStub)(mockChoices);
251
- assert.ok(getAllConfigSetStub.calledTwice);
257
+ assert.ok(getAllConfigSetStub.calledOnce);
252
258
  assert.ok(getSchemaStub.calledOnce);
253
- assert.ok(initConfigStub.calledWith({
254
- base: {
255
- KEY: 'test',
259
+ assert.ok(initConfigStub.calledWith(sinon.match({
260
+ base: sinon.match({
261
+ KEY: 'testSource',
262
+ NAME: 'testSource',
256
263
  INPUT_TYPE: 'REQ_REP',
257
- },
258
- fields: ['field1', 'field2'],
259
- }));
264
+ }),
265
+ fields: sinon.match.array.deepEquals(['field1', 'field2']),
266
+ })));
260
267
  }));
261
268
  CreateNewDatasourceConfig.run();
@@ -27,6 +27,9 @@ const container = html `
27
27
  </p>
28
28
  <div>
29
29
  ${repeat((_) => Object.keys(selectors.datasourceConfig.getAllConfigSet()), html `
30
+ ${when((_, ctx) => !ctx.isFirst, html `
31
+ <rapid-divider></rapid-divider>
32
+ `)}
30
33
  <datasource-config-item
31
34
  :datasourceName=${(x) => x}
32
35
  :datasourceChoices=${(_, c) => c.parent.datasourceChoices}
@@ -77,9 +77,17 @@ export function datasourceNameFromDisplay(input) {
77
77
  .replace(/[)]/g, '')
78
78
  .split('(')
79
79
  .map((x) => x.trim());
80
- return (datasourceInputFromDisplay(parts[1]) +
81
- '_' +
82
- parts[0]);
80
+ const type = datasourceInputFromDisplay(parts[1]);
81
+ const name = parts[0];
82
+ const match = Object.entries(selectors.datasourceConfig.getAllConfigSet()).find(([_, ds]) => ds.KEY === name && ds.INPUT_TYPE === type);
83
+ if (!match) {
84
+ /**
85
+ * This can occur when the datasource is first being initialized and the name
86
+ * hasn't yet been persisted to the store.
87
+ */
88
+ return `${type}_${name}_${name}`;
89
+ }
90
+ return match[0];
83
91
  }
84
92
  /**
85
93
  * Formats datasource name for display
@@ -137,12 +145,12 @@ export function fetchDatasourceSpecs(datasourceName, getSchema, onError) {
137
145
  return [];
138
146
  }
139
147
  try {
140
- return yield Promise.all(Object.values(selectors.datasourceConfig.getAllConfigSet())
141
- .filter(({ NAME, INPUT_TYPE }) => INPUT_TYPE === 'REQ_REP' && `${INPUT_TYPE}_${NAME}` === datasourceName)
142
- .map((_a) => __awaiter(this, [_a], void 0, function* ({ NAME }) {
148
+ return yield Promise.all(Object.entries(selectors.datasourceConfig.getAllConfigSet())
149
+ .filter(([key, ds]) => ds.INPUT_TYPE === 'REQ_REP' && key === datasourceName)
150
+ .map((_a) => __awaiter(this, [_a], void 0, function* ([_, { KEY, NAME }]) {
143
151
  return ({
144
- spec: yield getSchema(NAME),
145
- name: datasourceNameForDisplay(NAME, 'REQ_REP'),
152
+ spec: yield getSchema(NAME), // Fetch schema by Resource Name
153
+ name: datasourceNameForDisplay(KEY, 'REQ_REP'), // Display Alias
146
154
  });
147
155
  })));
148
156
  }
@@ -17,14 +17,17 @@ function createTestRowData(overrides = {}) {
17
17
  const FIRST_PARAM = 0;
18
18
  // DatasourceNameFromDisplay tests
19
19
  const DatasourceNameFromDisplayTests = suite('datasourceNameFromDisplay()');
20
+ DatasourceNameFromDisplayTests.before.each(() => {
21
+ sinon.restore();
22
+ });
20
23
  DatasourceNameFromDisplayTests('Correctly builds datasource key from Snapshot (REQ_REP) input', () => {
21
24
  const input = 'myService (Snapshot)';
22
- const expected = 'REQ_REP_myService';
25
+ const expected = 'REQ_REP_myService_myService';
23
26
  assert.equal(datasourceNameFromDisplay(input), expected);
24
27
  });
25
28
  DatasourceNameFromDisplayTests('Correctly builds datasource key from Data Pipeline (DATA_PIPELINE) input', () => {
26
29
  const input = 'dataFlow (Data Pipeline)';
27
- const expected = 'DATA_PIPELINE_dataFlow';
30
+ const expected = 'DATA_PIPELINE_dataFlow_dataFlow';
28
31
  assert.equal(datasourceNameFromDisplay(input), expected);
29
32
  });
30
33
  DatasourceNameFromDisplayTests.run();
@@ -60,6 +63,8 @@ LookupColumnIsIncluded('returns true when column is in included', () => {
60
63
  NAME: 'Test Datasource',
61
64
  INPUT_TYPE: 'REQ_REP',
62
65
  OUTPUT_TYPE: 'TABLE',
66
+ GROUPING_STRATEGY: 'NONE',
67
+ GROUP_KEY: null,
63
68
  TRANSFORMER_CONFIGURATION: { INCLUDE_COLUMNS: ['testColumn', 'otherColumn'] },
64
69
  };
65
70
  sinon.stub(selectors.datasourceConfig, 'getDatasource').returns(mockDatasource);
@@ -78,6 +83,8 @@ LookupColumnIsIncluded('returns false when column is not in filters', () => {
78
83
  NAME: 'Test Datasource',
79
84
  INPUT_TYPE: 'REQ_REP',
80
85
  OUTPUT_TYPE: 'TABLE',
86
+ GROUPING_STRATEGY: 'NONE',
87
+ GROUP_KEY: null,
81
88
  TRANSFORMER_CONFIGURATION: { INCLUDE_COLUMNS: ['testColumn', 'otherColumn'] },
82
89
  };
83
90
  sinon.stub(selectors.datasourceConfig, 'getDatasource').returns(mockDatasource);
@@ -96,6 +103,8 @@ LookupColumnIsIncluded('returns false when INCLUDE_COLUMNS is undefined', () =>
96
103
  NAME: 'Test Datasource',
97
104
  INPUT_TYPE: 'REQ_REP',
98
105
  OUTPUT_TYPE: 'TABLE',
106
+ GROUPING_STRATEGY: 'NONE',
107
+ GROUP_KEY: null,
99
108
  TRANSFORMER_CONFIGURATION: { INCLUDE_COLUMNS: undefined },
100
109
  };
101
110
  sinon.stub(selectors.datasourceConfig, 'getDatasource').returns(mockDatasource);
@@ -114,6 +123,8 @@ LookupColumnIsIncluded('returns false when INCLUDE_COLUMNS is empty array', () =
114
123
  NAME: 'Test Datasource',
115
124
  INPUT_TYPE: 'REQ_REP',
116
125
  OUTPUT_TYPE: 'TABLE',
126
+ GROUPING_STRATEGY: 'NONE',
127
+ GROUP_KEY: null,
117
128
  TRANSFORMER_CONFIGURATION: { INCLUDE_COLUMNS: [] },
118
129
  };
119
130
  sinon.stub(selectors.datasourceConfig, 'getDatasource').returns(mockDatasource);
@@ -7,7 +7,7 @@ export const template = html `
7
7
  <rapid-tabs ${ref('tabs')}>
8
8
  ${repeat((_) => Object.entries(selectors.datasourceConfig.getAllConfigSet()), html `
9
9
  <rapid-tab @click=${(x, c) => c.parent.handleDatasourceChanged(x[0])}>
10
- ${(x) => x[1].NAME}
10
+ ${(x) => x[1].KEY}
11
11
  </rapid-tab>
12
12
  `)}
13
13
  <!-- rapid-tab-panel unused for content, only used to make the rapid-tabs work correctly -->
@@ -10,14 +10,16 @@ export const datasourceSlice = createSlice({
10
10
  initialState,
11
11
  reducers: {
12
12
  initDatasourceConfiguration(state, action) {
13
- const { KEY, INPUT_TYPE } = action.payload.base;
14
- const key = buildDatasourceName(KEY, INPUT_TYPE);
13
+ const { KEY, NAME, INPUT_TYPE } = action.payload.base;
14
+ const key = buildDatasourceName(KEY, NAME, INPUT_TYPE);
15
15
  state[key] = {
16
16
  KEY: KEY,
17
17
  INPUT_TYPE: INPUT_TYPE,
18
- NAME: KEY,
18
+ NAME: NAME,
19
19
  OUTPUT_TYPE: 'TABLE',
20
20
  TRANSFORMER_CONFIGURATION: {},
21
+ GROUPING_STRATEGY: 'NONE',
22
+ GROUP_KEY: null,
21
23
  };
22
24
  action.payload.fields.forEach((field) => {
23
25
  datasourceSlice.caseReducers.setColumnRename(state, Object.assign(Object.assign({}, action), { payload: {
@@ -33,8 +35,32 @@ export const datasourceSlice = createSlice({
33
35
  } }));
34
36
  });
35
37
  },
36
- updateDatasourceKey(state, action) {
37
- state[action.payload.key].KEY = action.payload.newKey;
38
+ reorderDatasource(state, action) {
39
+ const { key, newIndex } = action.payload;
40
+ const entries = Object.entries(state);
41
+ const currentIndex = entries.findIndex(([k]) => k === key);
42
+ if (currentIndex === -1)
43
+ return state;
44
+ const [item] = entries.splice(currentIndex, 1);
45
+ entries.splice(newIndex, 0, item);
46
+ return Object.fromEntries(entries);
47
+ },
48
+ renameDatasource(state, action) {
49
+ const { key: oldKey, newName } = action.payload;
50
+ const datasource = state[oldKey];
51
+ if (!datasource) {
52
+ return;
53
+ }
54
+ const newKey = buildDatasourceName(newName, datasource.NAME, datasource.INPUT_TYPE);
55
+ if (state[newKey] && newKey !== oldKey) {
56
+ return;
57
+ }
58
+ return Object.fromEntries(Object.entries(state).map(([k, v]) => {
59
+ if (k === oldKey) {
60
+ return [newKey, Object.assign(Object.assign({}, v), { KEY: newName })];
61
+ }
62
+ return [k, v];
63
+ }));
38
64
  },
39
65
  updateDatasourceOutputType(state, action) {
40
66
  state[action.payload.key].OUTPUT_TYPE = action.payload.newType;
@@ -122,6 +148,16 @@ export const datasourceSlice = createSlice({
122
148
  const _c = (_b = (_a = state[key].TRANSFORMER_CONFIGURATION) === null || _a === void 0 ? void 0 : _a.COLUMN_FORMATS) !== null && _b !== void 0 ? _b : {}, _d = column, _ = _c[_d], rest = __rest(_c, [typeof _d === "symbol" ? _d : _d + ""]);
123
149
  state[key].TRANSFORMER_CONFIGURATION.COLUMN_FORMATS = rest;
124
150
  },
151
+ setGrouping(state, action) {
152
+ const { key, grouping } = action.payload;
153
+ state[key].GROUPING_STRATEGY = grouping.GROUPING_STRATEGY;
154
+ state[key].GROUP_KEY = grouping.GROUP_KEY;
155
+ },
156
+ deleteGrouping(state, action) {
157
+ const { key } = action.payload;
158
+ state[key].GROUPING_STRATEGY = 'NONE';
159
+ state[key].GROUP_KEY = null;
160
+ },
125
161
  },
126
162
  selectors: {
127
163
  getAllConfigSet(state) {
@@ -8,5 +8,6 @@ export const datasourceOutputs = [
8
8
  // 'RECORD_STREAM',
9
9
  'TABLE',
10
10
  ];
11
+ export const datasourceGroupingStrategies = ['NONE', 'MULTI_SHEET', 'LOOKUP_TABLE'];
11
12
  // BASE-CONFIG
12
13
  export const reportOutputFormats = ['CSV', 'PDF', 'XLSX'];
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generates a unique alias by appending a counter if the base alias already exists in the set.
3
+ * @param baseAlias The desired alias name (usually the resource name).
4
+ * @param existingAliases A Set of currently used aliases to check against.
5
+ * @returns A unique alias string.
6
+ */
7
+ export function generateUniqueAlias(baseAlias, existingAliases) {
8
+ const existingAliasesLower = new Set(Array.from(existingAliases).map((alias) => alias.toLowerCase()));
9
+ let uniqueAlias = baseAlias;
10
+ let counter = 1;
11
+ while (existingAliasesLower.has(uniqueAlias.toLowerCase())) {
12
+ uniqueAlias = `${baseAlias}_${counter}`;
13
+ counter += 1;
14
+ }
15
+ return uniqueAlias;
16
+ }
@@ -0,0 +1,36 @@
1
+ import { assert, suite } from '@genesislcap/foundation-testing';
2
+ import { generateUniqueAlias } from './alias-generator';
3
+ const GenerateUniqueAlias = suite('generateUniqueAlias');
4
+ GenerateUniqueAlias('returns the base alias if it does not exist', () => {
5
+ const existingAliases = new Set(['other']);
6
+ const alias = generateUniqueAlias('test', existingAliases);
7
+ assert.equal(alias, 'test');
8
+ });
9
+ GenerateUniqueAlias('increments the alias if it already exists', () => {
10
+ const existingAliases = new Set(['test']);
11
+ const alias = generateUniqueAlias('test', existingAliases);
12
+ assert.equal(alias, 'test_1');
13
+ });
14
+ GenerateUniqueAlias('increments the alias until it is unique', () => {
15
+ const existingAliases = new Set(['test', 'test_1']);
16
+ const alias = generateUniqueAlias('test', existingAliases);
17
+ assert.equal(alias, 'test_2');
18
+ });
19
+ GenerateUniqueAlias('handles case-insensitivity when checking for existing aliases', () => {
20
+ const existingAliases = new Set(['Test']);
21
+ const alias = generateUniqueAlias('test', existingAliases);
22
+ assert.equal(alias, 'test_1');
23
+ });
24
+ GenerateUniqueAlias('handles case-insensitivity for new alias generation', () => {
25
+ const existingAliases = new Set(['test']);
26
+ const alias = generateUniqueAlias('Test', existingAliases);
27
+ // Since input baseAlias is 'Test', it tries 'Test'. 'Test' matches 'test' case-insensitively.
28
+ // Next attempt 'Test_1'.
29
+ assert.equal(alias, 'Test_1');
30
+ });
31
+ GenerateUniqueAlias('handles mixed case existing aliases', () => {
32
+ const existingAliases = new Set(['TeSt', 'tEsT_1']);
33
+ const alias = generateUniqueAlias('test', existingAliases);
34
+ assert.equal(alias, 'test_2');
35
+ });
36
+ GenerateUniqueAlias.run();
@@ -1,3 +1,4 @@
1
+ export * from './alias-generator';
1
2
  export * from './endpoint';
2
3
  export * from './formatters';
3
4
  export * from './notifications';
@@ -44,6 +44,10 @@ export var TOOLTIP;
44
44
  <li>Where File type is set to <strong>PDF</strong> you must select a <code>.html</code> or <code>.xhtml</code> template that you've uploaded to the document manager PBC</li>
45
45
  </ul>
46
46
  `;
47
+ TOOLTIP.DATASOURCES_DATASOURCE = `
48
+ <h3>Datasource</h3>
49
+ <p>This is the name of the server resource that data will be pulled from to generate the report.</p>
50
+ `;
47
51
  TOOLTIP.DATASOURCES_NAME = `
48
52
  <h3>Datasource name</h3>
49
53
  <p>Allows you to set a name for the datasource which must correspond with your template data references where the report is configured to use a template file.</p>
@@ -52,6 +56,18 @@ export var TOOLTIP;
52
56
  TOOLTIP.DATASOURCES_TYPE = `
53
57
  <h3>Datasource type</h3>
54
58
  <p>Configures the method by which the server constructs the report configuration. Currently only TABLE is supported, which means the entire datasource is loaded into memory when generating the report using this report configuration.</p>
59
+ `;
60
+ TOOLTIP.DATASOURCES_GROUPING_STRATEGY = `
61
+ <h3>Grouping Strategy</h3>
62
+ <p>Select "None" to disable grouping strategies, or select the strategy you'd like to use.</p>
63
+ <ul>
64
+ <li><strong>Multi-sheet</strong>: Group data for <code>JXLS</code> template Multi-sheet functionality, to split different groups across multiple excel worksheets.</li>
65
+ <li><strong>Lookup-table</strong>: Create a lookup table of key value pairs in the template data, where the group key field is the map key.</li>
66
+ </ul>
67
+ `;
68
+ TOOLTIP.DATASOURCES_GROUPING_KEY = `
69
+ <h3>Grouping Key</h3>
70
+ <p>Select the field for this datasource you want to operate the grouping strategy on.</p>
55
71
  `;
56
72
  TOOLTIP.DELIVERY_TIMEZONE = `
57
73
  <h3>Timezone</h3>
@@ -10,7 +10,14 @@ export function transformToServerPayload(state) {
10
10
  // TODO: server workaround - currently need to explicitly set to null if unset
11
11
  DOCUMENT_TEMPLATE_ID: restBaseConfig.DOCUMENT_TEMPLATE_ID
12
12
  ? restBaseConfig.DOCUMENT_TEMPLATE_ID
13
- : null, DATA_SOURCES: Object.values(datasourceConfig) });
13
+ : null, DATA_SOURCES: Object.values(datasourceConfig).map((ds) => {
14
+ // For NONE case we just don't send it to the server to be backwards compatible
15
+ if (ds.GROUPING_STRATEGY === 'NONE') {
16
+ const { GROUPING_STRATEGY, GROUP_KEY } = ds, rest = __rest(ds, ["GROUPING_STRATEGY", "GROUP_KEY"]);
17
+ return rest;
18
+ }
19
+ return ds;
20
+ }) });
14
21
  }
15
22
  /**
16
23
  * Cleans up orphaned field references from transformer configuration
@@ -46,10 +53,12 @@ export function transformFromServerPayload(payload, getSchema) {
46
53
  DESTINATION_IDS,
47
54
  OUTPUT_DIRECTORY,
48
55
  DOCUMENT_TEMPLATE_ID }, (SCHEDULES.length > 0 && { SCHEDULE: SCHEDULES[0] }));
49
- const cleanedDatasources = yield Promise.all(DATA_SOURCES.map((_a) => __awaiter(this, [_a], void 0, function* ({ KEY, INPUT_TYPE, NAME: DS_NAME, OUTPUT_TYPE, TRANSFORMER_CONFIGURATION }) {
56
+ const cleanedDatasources = yield Promise.all(DATA_SOURCES.map((_a) => __awaiter(this, void 0, void 0, function* () {
57
+ var { KEY, INPUT_TYPE, NAME: DS_NAME, OUTPUT_TYPE, TRANSFORMER_CONFIGURATION } = _a, rest = __rest(_a, ["KEY", "INPUT_TYPE", "NAME", "OUTPUT_TYPE", "TRANSFORMER_CONFIGURATION"]);
50
58
  try {
51
- const schema = yield getSchema(KEY);
59
+ const schema = yield getSchema(DS_NAME);
52
60
  const validFields = new Set(Object.keys(schema.properties || {}));
61
+ const { GROUPING_STRATEGY, GROUP_KEY } = rest;
53
62
  const cleanedConfig = cleanupTransformerConfig(TRANSFORMER_CONFIGURATION || {}, validFields);
54
63
  return {
55
64
  KEY,
@@ -57,23 +66,28 @@ export function transformFromServerPayload(payload, getSchema) {
57
66
  NAME: DS_NAME,
58
67
  OUTPUT_TYPE,
59
68
  TRANSFORMER_CONFIGURATION: cleanedConfig,
69
+ GROUPING_STRATEGY: GROUPING_STRATEGY || 'NONE',
70
+ GROUP_KEY: GROUP_KEY || null,
60
71
  };
61
72
  }
62
73
  catch (error) {
63
74
  // If schema fetch fails, log warning but keep original config
64
75
  console.warn(`Failed to fetch schema for ${KEY}, skipping cleanup:`, error);
76
+ const { GROUPING_STRATEGY, GROUP_KEY } = rest;
65
77
  return {
66
78
  KEY,
67
79
  INPUT_TYPE,
68
80
  NAME: DS_NAME,
69
81
  OUTPUT_TYPE,
70
82
  TRANSFORMER_CONFIGURATION: TRANSFORMER_CONFIGURATION || {},
83
+ GROUPING_STRATEGY: GROUPING_STRATEGY || 'NONE',
84
+ GROUP_KEY: GROUP_KEY || null,
71
85
  };
72
86
  }
73
87
  })));
74
88
  return {
75
89
  baseConfig,
76
- datasourceConfig: cleanedDatasources.reduce((acum, ds) => (Object.assign(Object.assign({}, acum), { [buildDatasourceName(ds.NAME, ds.INPUT_TYPE)]: ds })), {}),
90
+ datasourceConfig: cleanedDatasources.reduce((acum, ds) => (Object.assign(Object.assign({}, acum), { [buildDatasourceName(ds.KEY, ds.NAME, ds.INPUT_TYPE)]: ds })), {}),
77
91
  };
78
92
  });
79
93
  }
@@ -93,6 +107,6 @@ export function datasourceInputFromDisplay(display) {
93
107
  else
94
108
  throw new Error(`datasourceInputFromDisplay - Uncaught case ${display}`);
95
109
  }
96
- export function buildDatasourceName(key, type) {
97
- return `${type}_${key}`;
110
+ export function buildDatasourceName(alias, resourceName, type) {
111
+ return `${type}_${resourceName}_${alias}`;
98
112
  }
@@ -1,6 +1,6 @@
1
1
  import { __awaiter } from "tslib";
2
2
  import { assert, sinon, suite } from '@genesislcap/foundation-testing';
3
- import { buildDatasourceName, transformFromServerPayload } from './transformers';
3
+ import { buildDatasourceName, transformFromServerPayload, transformToServerPayload, } from './transformers';
4
4
  const TransformFromServerPayload = suite('transformFromServerPayload');
5
5
  TransformFromServerPayload.before.each(() => {
6
6
  sinon.restore();
@@ -34,7 +34,7 @@ TransformFromServerPayload('cleans up orphaned fields from INCLUDE_COLUMNS', ()
34
34
  OUTPUT_DIRECTORY: '/reports',
35
35
  };
36
36
  const result = yield transformFromServerPayload(payload, mockGetSchema);
37
- const datasourceKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
37
+ const datasourceKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
38
38
  const cleanedConfig = result.datasourceConfig[datasourceKey].TRANSFORMER_CONFIGURATION;
39
39
  assert.equal((_a = cleanedConfig.INCLUDE_COLUMNS) === null || _a === void 0 ? void 0 : _a.length, 2);
40
40
  assert.ok((_b = cleanedConfig.INCLUDE_COLUMNS) === null || _b === void 0 ? void 0 : _b.includes('COUNTERPARTY_NAME'));
@@ -74,7 +74,7 @@ TransformFromServerPayload('cleans up orphaned fields from COLUMN_RENAMES', () =
74
74
  OUTPUT_DIRECTORY: '/reports',
75
75
  };
76
76
  const result = yield transformFromServerPayload(payload, mockGetSchema);
77
- const datasourceKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
77
+ const datasourceKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
78
78
  const cleanedConfig = result.datasourceConfig[datasourceKey].TRANSFORMER_CONFIGURATION;
79
79
  assert.equal(Object.keys(cleanedConfig.COLUMN_RENAMES || {}).length, 2);
80
80
  assert.equal((_a = cleanedConfig.COLUMN_RENAMES) === null || _a === void 0 ? void 0 : _a['COUNTERPARTY_NAME'], 'Counterparty Name');
@@ -114,7 +114,7 @@ TransformFromServerPayload('cleans up orphaned fields from COLUMN_FORMATS', () =
114
114
  OUTPUT_DIRECTORY: '/reports',
115
115
  };
116
116
  const result = yield transformFromServerPayload(payload, mockGetSchema);
117
- const datasourceKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
117
+ const datasourceKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
118
118
  const cleanedConfig = result.datasourceConfig[datasourceKey].TRANSFORMER_CONFIGURATION;
119
119
  assert.equal(Object.keys(cleanedConfig.COLUMN_FORMATS || {}).length, 2);
120
120
  assert.equal((_a = cleanedConfig.COLUMN_FORMATS) === null || _a === void 0 ? void 0 : _a['COUNTERPARTY_NAME'], 'text');
@@ -154,7 +154,7 @@ TransformFromServerPayload('cleans up orphaned fields from COLUMN_TRANSFORMS', (
154
154
  OUTPUT_DIRECTORY: '/reports',
155
155
  };
156
156
  const result = yield transformFromServerPayload(payload, mockGetSchema);
157
- const datasourceKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
157
+ const datasourceKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
158
158
  const cleanedConfig = result.datasourceConfig[datasourceKey].TRANSFORMER_CONFIGURATION;
159
159
  assert.equal(Object.keys(cleanedConfig.COLUMN_TRANSFORMS || {}).length, 2);
160
160
  assert.ok((_a = cleanedConfig.COLUMN_TRANSFORMS) === null || _a === void 0 ? void 0 : _a['COUNTERPARTY_NAME']);
@@ -186,7 +186,7 @@ TransformFromServerPayload('handles schema fetch failure gracefully', () => __aw
186
186
  OUTPUT_DIRECTORY: '/reports',
187
187
  };
188
188
  const result = yield transformFromServerPayload(payload, mockGetSchema);
189
- const datasourceKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
189
+ const datasourceKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
190
190
  const cleanedConfig = result.datasourceConfig[datasourceKey].TRANSFORMER_CONFIGURATION;
191
191
  // Should keep original config when schema fetch fails
192
192
  assert.equal(JSON.stringify(cleanedConfig), JSON.stringify(originalConfig));
@@ -238,8 +238,8 @@ TransformFromServerPayload('handles multiple datasources independently', () => _
238
238
  OUTPUT_DIRECTORY: '/reports',
239
239
  };
240
240
  const result = yield transformFromServerPayload(payload, mockGetSchema);
241
- const counterpartyKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
242
- const tradeKey = buildDatasourceName('TRADE', 'REQ_REP');
241
+ const counterpartyKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
242
+ const tradeKey = buildDatasourceName('TRADE', 'TRADE', 'REQ_REP');
243
243
  assert.equal((_a = result.datasourceConfig[counterpartyKey].TRANSFORMER_CONFIGURATION.INCLUDE_COLUMNS) === null || _a === void 0 ? void 0 : _a.length, 1);
244
244
  assert.ok((_b = result.datasourceConfig[counterpartyKey].TRANSFORMER_CONFIGURATION.INCLUDE_COLUMNS) === null || _b === void 0 ? void 0 : _b.includes('COUNTERPARTY_NAME'));
245
245
  assert.equal((_c = result.datasourceConfig[tradeKey].TRANSFORMER_CONFIGURATION.INCLUDE_COLUMNS) === null || _c === void 0 ? void 0 : _c.length, 1);
@@ -270,7 +270,7 @@ TransformFromServerPayload('handles empty transformer configuration', () => __aw
270
270
  OUTPUT_DIRECTORY: '/reports',
271
271
  };
272
272
  const result = yield transformFromServerPayload(payload, mockGetSchema);
273
- const datasourceKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
273
+ const datasourceKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
274
274
  const cleanedConfig = result.datasourceConfig[datasourceKey].TRANSFORMER_CONFIGURATION;
275
275
  assert.equal(JSON.stringify(cleanedConfig), JSON.stringify({}));
276
276
  }));
@@ -298,7 +298,7 @@ TransformFromServerPayload('handles missing schema properties', () => __awaiter(
298
298
  OUTPUT_DIRECTORY: '/reports',
299
299
  };
300
300
  const result = yield transformFromServerPayload(payload, mockGetSchema);
301
- const datasourceKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
301
+ const datasourceKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
302
302
  const cleanedConfig = result.datasourceConfig[datasourceKey].TRANSFORMER_CONFIGURATION;
303
303
  // All fields should be removed when schema has no properties
304
304
  assert.equal((_a = cleanedConfig.INCLUDE_COLUMNS) === null || _a === void 0 ? void 0 : _a.length, 0);
@@ -398,7 +398,7 @@ TransformFromServerPayload('handles all transformer config types together', () =
398
398
  OUTPUT_DIRECTORY: '/reports',
399
399
  };
400
400
  const result = yield transformFromServerPayload(payload, mockGetSchema);
401
- const datasourceKey = buildDatasourceName('COUNTERPARTY', 'REQ_REP');
401
+ const datasourceKey = buildDatasourceName('COUNTERPARTY', 'COUNTERPARTY', 'REQ_REP');
402
402
  const cleanedConfig = result.datasourceConfig[datasourceKey].TRANSFORMER_CONFIGURATION;
403
403
  // INCLUDE_COLUMNS should only have valid fields
404
404
  assert.equal((_a = cleanedConfig.INCLUDE_COLUMNS) === null || _a === void 0 ? void 0 : _a.length, 2);
@@ -417,3 +417,53 @@ TransformFromServerPayload('handles all transformer config types together', () =
417
417
  assert.ok(cleanedConfig.ROW_FILTERS);
418
418
  }));
419
419
  TransformFromServerPayload.run();
420
+ const TransformToServerPayload = suite('transformToServerPayload');
421
+ TransformToServerPayload('omits grouping fields when strategy is NONE', () => {
422
+ const state = {
423
+ baseConfig: {
424
+ DESTINATION_IDS: [],
425
+ OUTPUT_DIRECTORY: '/reports',
426
+ },
427
+ datasourceConfig: {
428
+ REQ_REP_COUNTERPARTY_COUNTERPARTY: {
429
+ KEY: 'COUNTERPARTY',
430
+ INPUT_TYPE: 'REQ_REP',
431
+ NAME: 'COUNTERPARTY',
432
+ OUTPUT_TYPE: 'TABLE',
433
+ TRANSFORMER_CONFIGURATION: {},
434
+ GROUPING_STRATEGY: 'NONE',
435
+ GROUP_KEY: null,
436
+ },
437
+ },
438
+ };
439
+ const result = transformToServerPayload(state);
440
+ const ds = result.DATA_SOURCES[0];
441
+ assert.equal(ds.KEY, 'COUNTERPARTY');
442
+ assert.ok(!('GROUPING_STRATEGY' in ds));
443
+ assert.ok(!('GROUP_KEY' in ds));
444
+ });
445
+ TransformToServerPayload('includes grouping fields when strategy is not NONE', () => {
446
+ const state = {
447
+ baseConfig: {
448
+ DESTINATION_IDS: [],
449
+ OUTPUT_DIRECTORY: '/reports',
450
+ },
451
+ datasourceConfig: {
452
+ REQ_REP_COUNTERPARTY_COUNTERPARTY: {
453
+ KEY: 'COUNTERPARTY',
454
+ INPUT_TYPE: 'REQ_REP',
455
+ NAME: 'COUNTERPARTY',
456
+ OUTPUT_TYPE: 'TABLE',
457
+ TRANSFORMER_CONFIGURATION: {},
458
+ GROUPING_STRATEGY: 'MULTI_SHEET',
459
+ GROUP_KEY: 'some_key',
460
+ },
461
+ },
462
+ };
463
+ const result = transformToServerPayload(state);
464
+ const ds = result.DATA_SOURCES[0];
465
+ assert.equal(ds.KEY, 'COUNTERPARTY');
466
+ assert.equal(ds.GROUPING_STRATEGY, 'MULTI_SHEET');
467
+ assert.equal(ds.GROUP_KEY, 'some_key');
468
+ });
469
+ TransformToServerPayload.run();