@gooddata/sdk-code-convertors 11.30.0-alpha.2 → 11.30.0-alpha.4

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.
@@ -3,7 +3,7 @@ import { Document, Pair, YAMLMap, YAMLSeq } from "yaml";
3
3
  import { dashboardFilterReferenceObjRef, isAttributeElementsByRef, isAttributeElementsByValue, isAttributeHierarchyReference, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardDateFilter, isDashboardMatchAttributeFilter, isDrillToAttributeUrl, isDrillToCustomUrl, isDrillToDashboard, isDrillToInsight, isNoopAllTimeDashboardDateFilter, isRelativeDashboardDateFilter, } from "@gooddata/sdk-model";
4
4
  import { VisualisationsTypes } from "../conts.js";
5
5
  import { serializeUrlTarget } from "../utils/customUrl.js";
6
- import { CoreErrorCode, newError } from "../utils/errors.js";
6
+ import { CoreErrorCode, newError, updateErrorContext } from "../utils/errors.js";
7
7
  import { matchConditionToYaml } from "../utils/filterUtils.js";
8
8
  import { parseGranularity } from "../utils/granularityUtils.js";
9
9
  import { fromDeclarativePermissions } from "../utils/permissionUtils.js";
@@ -11,7 +11,12 @@ import { collectFieldLevelFilters } from "../utils/sharedUtils.js";
11
11
  import { DASHBOARD_COMMENT } from "../utils/texts.js";
12
12
  import { createFilterContextItemKeyName, entryWithSpace, fillOptionalMetaFields, getIdentifier, } from "../utils/yamlUtils.js";
13
13
  /** @public */
14
- export function declarativeDashboardToYaml(entities, dashboard, filterContexts) {
14
+ export function declarativeDashboardToYaml(entities, dashboard, filterContexts, context) {
15
+ const errorContext = updateErrorContext(context, {
16
+ type: "dashboard",
17
+ path: ["dashboard", dashboard.id],
18
+ data: {},
19
+ });
15
20
  const content = dashboard.content;
16
21
  // Create new doc and add mandatory fields right away
17
22
  const doc = new Document({
@@ -46,7 +51,7 @@ export function declarativeDashboardToYaml(entities, dashboard, filterContexts)
46
51
  const hasSingleTabWithTitle = content.tabs?.length === 1 && content.tabs[0].title;
47
52
  const shouldUseTabs = hasMultipleTabs || hasSingleTabWithTitle;
48
53
  if (content.tabs && shouldUseTabs) {
49
- const tabs = declarativeTabsToYaml(content.tabs, filterContexts, entities);
54
+ const tabs = declarativeTabsToYaml(content.tabs, filterContexts, entities, updateErrorContext(errorContext, { path: ["tabs"] }));
50
55
  if (tabs) {
51
56
  doc.add(entryWithSpace("tabs", tabs));
52
57
  }
@@ -55,13 +60,15 @@ export function declarativeDashboardToYaml(entities, dashboard, filterContexts)
55
60
  // Dashboard with implicit single tab - create root yaml structure like without tabs
56
61
  // but read all metadata from a single tab
57
62
  const tab = content.tabs[0];
58
- const section = declarativeSectionsToYaml(tab.layout, entities);
63
+ const section = declarativeSectionsToYaml(tab.layout, entities, updateErrorContext(errorContext, { path: ["tabs", "0"] }));
59
64
  if (section) {
60
65
  doc.add(entryWithSpace("sections", section));
61
66
  }
62
- const filterContextId = tab.filterContextRef ? getIdentifier(tab.filterContextRef, true) : undefined;
63
- const { filters, filtersMap } = declarativeFilterContextToYaml(tab.dateFilterConfig, filterContexts?.find((fc) => fc.id === filterContextId));
64
- declarativeFiltersConfigToYaml(filtersMap, tab.dateFilterConfig, tab.dateFilterConfigs, tab.attributeFilterConfigs);
67
+ const filterContextId = tab.filterContextRef
68
+ ? getIdentifier(tab.filterContextRef, true, updateErrorContext(errorContext, { path: ["filterContext"] }))
69
+ : undefined;
70
+ const { filters, filtersMap } = declarativeFilterContextToYaml(tab.dateFilterConfig, filterContexts?.find((fc) => fc.id === filterContextId), updateErrorContext(errorContext, { path: ["dateFilterConfig"] }));
71
+ declarativeFiltersConfigToYaml(filtersMap, tab.dateFilterConfig, tab.dateFilterConfigs, tab.attributeFilterConfigs, errorContext);
65
72
  const groupedFilters = declarativeFilterGroupsToYaml(filters, tab.filterGroupsConfig);
66
73
  if (groupedFilters.items.length > 0) {
67
74
  doc.add(entryWithSpace("filters", groupedFilters));
@@ -69,21 +76,21 @@ export function declarativeDashboardToYaml(entities, dashboard, filterContexts)
69
76
  }
70
77
  else {
71
78
  // Dashboard without tabs - add sections and filters
72
- const section = declarativeSectionsToYaml(content.layout, entities);
79
+ const section = declarativeSectionsToYaml(content.layout, entities, updateErrorContext(errorContext, { path: ["layout"] }));
73
80
  if (section) {
74
81
  doc.add(entryWithSpace("sections", section));
75
82
  }
76
83
  const filterContextId = content.filterContextRef
77
- ? getIdentifier(content.filterContextRef, true)
84
+ ? getIdentifier(content.filterContextRef, true, updateErrorContext(errorContext, { path: ["filterContext"] }))
78
85
  : undefined;
79
- const { filters, filtersMap } = declarativeFilterContextToYaml(content.dateFilterConfig, filterContexts?.find((fc) => fc.id === filterContextId));
80
- declarativeFiltersConfigToYaml(filtersMap, content.dateFilterConfig, content.dateFilterConfigs, content.attributeFilterConfigs);
86
+ const { filters, filtersMap } = declarativeFilterContextToYaml(content.dateFilterConfig, filterContexts?.find((fc) => fc.id === filterContextId), updateErrorContext(errorContext, { path: ["dateFilterConfig"] }));
87
+ declarativeFiltersConfigToYaml(filtersMap, content.dateFilterConfig, content.dateFilterConfigs, content.attributeFilterConfigs, errorContext);
81
88
  if (filters.items.length > 0) {
82
89
  doc.add(entryWithSpace("filters", filters));
83
90
  }
84
91
  }
85
92
  // Add KD plugins definitions
86
- const plugins = declarativePluginsToYaml(content);
93
+ const plugins = declarativePluginsToYaml(content, updateErrorContext(errorContext, { path: ["plugins"] }));
87
94
  if (plugins) {
88
95
  doc.add(entryWithSpace("plugins", plugins));
89
96
  }
@@ -99,26 +106,27 @@ export function declarativeDashboardToYaml(entities, dashboard, filterContexts)
99
106
  json: doc.toJSON(),
100
107
  };
101
108
  }
102
- export function declarativeTabsToYaml(tabs, filterContexts, entities) {
109
+ export function declarativeTabsToYaml(tabs, filterContexts, entities, errorContext) {
103
110
  // no tabs
104
111
  if (!tabs || tabs.length === 0) {
105
112
  return;
106
113
  }
107
114
  const yamlTabs = new YAMLSeq();
108
- tabs.forEach((tab) => {
115
+ tabs.forEach((tab, ti) => {
109
116
  const yamlTab = new YAMLMap();
117
+ const tabErrorContext = updateErrorContext(errorContext, { path: [ti.toString()] });
110
118
  // Add tab id and name
111
119
  yamlTab.add(new Pair("id", tab.localIdentifier));
112
120
  yamlTab.add(new Pair("title", tab.title));
113
121
  // Add tab filters
114
122
  let filterContext;
115
123
  if (tab.filterContextRef && filterContexts?.length) {
116
- const filterContextId = getIdentifier(tab.filterContextRef, true);
124
+ const filterContextId = getIdentifier(tab.filterContextRef, true, tabErrorContext);
117
125
  filterContext = filterContexts.find((fc) => fc.id === filterContextId);
118
126
  }
119
127
  if (filterContext) {
120
- const { filters, filtersMap } = declarativeFilterContextToYaml(tab.dateFilterConfig, filterContext);
121
- declarativeFiltersConfigToYaml(filtersMap, tab.dateFilterConfig, tab.dateFilterConfigs, tab.attributeFilterConfigs);
128
+ const { filters, filtersMap } = declarativeFilterContextToYaml(tab.dateFilterConfig, filterContext, updateErrorContext(tabErrorContext, { path: ["dateFilterConfig"] }));
129
+ declarativeFiltersConfigToYaml(filtersMap, tab.dateFilterConfig, tab.dateFilterConfigs, tab.attributeFilterConfigs, tabErrorContext);
122
130
  const groupedFilters = declarativeFilterGroupsToYaml(filters, tab.filterGroupsConfig);
123
131
  if (groupedFilters.items.length > 0) {
124
132
  yamlTab.add(new Pair("filters", groupedFilters));
@@ -129,7 +137,7 @@ export function declarativeTabsToYaml(tabs, filterContexts, entities) {
129
137
  const tempDashboard = {
130
138
  layout: tab.layout,
131
139
  };
132
- const sections = declarativeSectionsToYaml(tempDashboard.layout, entities);
140
+ const sections = declarativeSectionsToYaml(tempDashboard.layout, entities, updateErrorContext(tabErrorContext, { path: ["layout"] }));
133
141
  if (sections) {
134
142
  yamlTab.add(new Pair("sections", sections));
135
143
  }
@@ -138,14 +146,15 @@ export function declarativeTabsToYaml(tabs, filterContexts, entities) {
138
146
  });
139
147
  return yamlTabs;
140
148
  }
141
- export function declarativeSectionsToYaml(layout, entities) {
149
+ export function declarativeSectionsToYaml(layout, entities, errorContext) {
142
150
  //no sections at all
143
151
  if (!layout?.sections?.length) {
144
152
  return;
145
153
  }
146
154
  const sections = new YAMLSeq();
147
- layout.sections.forEach((section) => {
155
+ layout.sections.forEach((section, si) => {
148
156
  const yamlSection = new YAMLMap();
157
+ const sectionErrorContext = updateErrorContext(errorContext, { path: ["sections", si.toString()] });
149
158
  if (section.header?.title) {
150
159
  yamlSection.add(new Pair("title", section.header.title));
151
160
  }
@@ -154,8 +163,8 @@ export function declarativeSectionsToYaml(layout, entities) {
154
163
  }
155
164
  if (section.items?.length) {
156
165
  const items = new YAMLSeq();
157
- section.items.forEach((item) => {
158
- const widget = declarativeWidgetToYaml(item.widget, item.size, entities);
166
+ section.items.forEach((item, i) => {
167
+ const widget = declarativeWidgetToYaml(item.widget, item.size, entities, updateErrorContext(sectionErrorContext, { path: ["items", i.toString()] }));
159
168
  if (widget) {
160
169
  items.add(widget);
161
170
  }
@@ -166,31 +175,31 @@ export function declarativeSectionsToYaml(layout, entities) {
166
175
  });
167
176
  return sections;
168
177
  }
169
- export function declarativeWidgetToYaml(widget, size, entities) {
178
+ export function declarativeWidgetToYaml(widget, size, entities, errorContext) {
170
179
  if (!widget) {
171
180
  return;
172
181
  }
173
182
  switch (widget?.type) {
174
183
  case "insight":
175
- return declarativeInsightWidgetToYaml(widget, size, entities);
184
+ return declarativeInsightWidgetToYaml(widget, size, entities, updateErrorContext(errorContext, { path: ["insight"] }));
176
185
  case "richText":
177
186
  return declarativeRichTextWidgetToYaml(widget, size);
178
187
  case "visualizationSwitcher":
179
- return declarativeVisualizationSwitcherWidgetToYaml(widget, size, entities);
188
+ return declarativeVisualizationSwitcherWidgetToYaml(widget, size, entities, updateErrorContext(errorContext, { path: ["visualizationSwitcher"] }));
180
189
  case "IDashboardLayout":
181
- return declarativeContainerWidgetToYaml(widget, size, entities);
190
+ return declarativeContainerWidgetToYaml(widget, size, entities, updateErrorContext(errorContext, { path: ["layout"] }));
182
191
  default:
183
- throw newError(CoreErrorCode.ReferenceTypeNotSupported, [String(widget?.type)]);
192
+ throw newError(CoreErrorCode.ReferenceTypeNotSupported, [String(widget?.type)], errorContext);
184
193
  }
185
194
  }
186
- export function declarativeInsightWidgetToYaml(widget, size, entities) {
195
+ export function declarativeInsightWidgetToYaml(widget, size, entities, errorContext) {
187
196
  const yamlWidget = new YAMLMap();
188
197
  // Local id of widget
189
198
  if (widget.localIdentifier) {
190
199
  yamlWidget.add(new Pair("id", widget.localIdentifier));
191
200
  }
192
201
  // The visualization
193
- yamlWidget.add(new Pair("visualization", getIdentifier(widget.insight, true)));
202
+ yamlWidget.add(new Pair("visualization", getIdentifier(widget.insight, true, updateErrorContext(errorContext, { path: ["visualisation"] }))));
194
203
  // Title
195
204
  if (widget.configuration?.hideTitle) {
196
205
  yamlWidget.add(new Pair("title", false));
@@ -217,11 +226,11 @@ export function declarativeInsightWidgetToYaml(widget, size, entities) {
217
226
  }
218
227
  // Filtering
219
228
  if (widget.dateDataSet) {
220
- yamlWidget.add(new Pair("date", getIdentifier(widget.dateDataSet, true)));
229
+ yamlWidget.add(new Pair("date", getIdentifier(widget.dateDataSet, true, updateErrorContext(errorContext, { path: ["date"] }))));
221
230
  }
222
231
  if (widget.ignoreDashboardFilters?.length) {
223
- yamlWidget.add(new Pair("ignored_filters", widget.ignoreDashboardFilters.map((df) => {
224
- return getIdentifier(dashboardFilterReferenceObjRef(df));
232
+ yamlWidget.add(new Pair("ignored_filters", widget.ignoreDashboardFilters.map((df, i) => {
233
+ return getIdentifier(dashboardFilterReferenceObjRef(df), undefined, updateErrorContext(errorContext, { path: ["ignoreDashboardFilters", i.toString()] }));
225
234
  })));
226
235
  }
227
236
  // Interactions
@@ -230,19 +239,21 @@ export function declarativeInsightWidgetToYaml(widget, size, entities) {
230
239
  }
231
240
  if (widget.drills?.length) {
232
241
  const drills = new YAMLSeq();
233
- const sourceVisualizationId = getIdentifier(widget.insight, true);
234
- widget.drills.forEach((drill) => {
235
- drills.add(declarativeDrillToYaml(drill, entities, sourceVisualizationId));
242
+ const sourceVisualizationId = getIdentifier(widget.insight, true, updateErrorContext(errorContext, { path: ["insight"] }));
243
+ widget.drills.forEach((drill, id) => {
244
+ drills.add(declarativeDrillToYaml(drill, entities, sourceVisualizationId, updateErrorContext(errorContext, { path: ["drills", id.toString()] })));
236
245
  });
237
246
  yamlWidget.add(new Pair("interactions", drills));
238
247
  }
239
248
  if (widget.ignoredDrillDownHierarchies?.length) {
240
- const ignores = widget.ignoredDrillDownHierarchies.map((hierarchy) => declarativeIgnoreDrillDownHierarchyToYaml(hierarchy));
249
+ const ignores = widget.ignoredDrillDownHierarchies.map((hierarchy, hi) => declarativeIgnoreDrillDownHierarchyToYaml(hierarchy, updateErrorContext(errorContext, { path: ["ignoredDrillDownHierarchies", hi.toString()] })));
241
250
  yamlWidget.add(new Pair("ignored_drill_downs", ignores));
242
251
  }
243
252
  if (widget.drillDownIntersectionIgnoredAttributes?.length) {
244
253
  const ignores = widget.drillDownIntersectionIgnoredAttributes
245
- .map((hierarchy) => declarativeDrillDownIntersectionIgnoredAttributesToYaml(hierarchy))
254
+ .map((hierarchy, hi) => declarativeDrillDownIntersectionIgnoredAttributesToYaml(hierarchy, updateErrorContext(errorContext, {
255
+ path: ["drillDownIntersectionIgnoredAttributes", hi.toString()],
256
+ })))
246
257
  .filter(Boolean);
247
258
  yamlWidget.add(new Pair("ignored_drill_downs_intersections", ignores));
248
259
  }
@@ -252,25 +263,25 @@ export function declarativeInsightWidgetToYaml(widget, size, entities) {
252
263
  }
253
264
  return yamlWidget;
254
265
  }
255
- export function declarativeIgnoreDrillDownHierarchyToYaml(hierarchy) {
266
+ export function declarativeIgnoreDrillDownHierarchyToYaml(hierarchy, errorContext) {
256
267
  if (isAttributeHierarchyReference(hierarchy)) {
257
268
  return {
258
269
  hierarchy: hierarchy.attributeHierarchy,
259
- on: getIdentifier(hierarchy.attribute),
270
+ on: getIdentifier(hierarchy.attribute, undefined, updateErrorContext(errorContext, { path: ["attribute"] })),
260
271
  };
261
272
  }
262
273
  return {
263
274
  template: hierarchy.dateHierarchyTemplate,
264
- on: getIdentifier(hierarchy.dateDatasetAttribute),
275
+ on: getIdentifier(hierarchy.dateDatasetAttribute, undefined, updateErrorContext(errorContext, { path: ["dateDatasetAttribute"] })),
265
276
  };
266
277
  }
267
- export function declarativeDrillDownIntersectionIgnoredAttributesToYaml(hierarchy) {
278
+ export function declarativeDrillDownIntersectionIgnoredAttributesToYaml(hierarchy, errorContext) {
268
279
  if (hierarchy.ignoredAttributes.length === 0) {
269
280
  return null;
270
281
  }
271
282
  return {
272
283
  attributes: hierarchy.ignoredAttributes,
273
- hierarchy: declarativeIgnoreDrillDownHierarchyToYaml(hierarchy.drillDownReference),
284
+ hierarchy: declarativeIgnoreDrillDownHierarchyToYaml(hierarchy.drillDownReference, updateErrorContext(errorContext, { path: ["drillDownReference"] })),
274
285
  };
275
286
  }
276
287
  export function declarativeRichTextWidgetToYaml(widget, size) {
@@ -290,14 +301,14 @@ export function declarativeRichTextWidgetToYaml(widget, size) {
290
301
  }
291
302
  return yamlWidget;
292
303
  }
293
- export function declarativeVisualizationSwitcherWidgetToYaml(widget, size, entities) {
304
+ export function declarativeVisualizationSwitcherWidgetToYaml(widget, size, entities, errorContext) {
294
305
  const yamlWidget = new YAMLMap();
295
306
  // Local id of widget
296
307
  if (widget.localIdentifier) {
297
308
  yamlWidget.add(new Pair("id", widget.localIdentifier));
298
309
  }
299
310
  // The visualizations
300
- yamlWidget.add(new Pair("visualizations", widget.visualizations.map((vis) => declarativeInsightWidgetToYaml(vis, undefined, entities))));
311
+ yamlWidget.add(new Pair("visualizations", widget.visualizations.map((vis, vi) => declarativeInsightWidgetToYaml(vis, undefined, entities, updateErrorContext(errorContext, { path: ["visualizations", vi.toString()] })))));
301
312
  // Size
302
313
  if (size?.xl?.gridWidth) {
303
314
  yamlWidget.add(new Pair("columns", size.xl.gridWidth));
@@ -307,7 +318,7 @@ export function declarativeVisualizationSwitcherWidgetToYaml(widget, size, entit
307
318
  }
308
319
  return yamlWidget;
309
320
  }
310
- export function declarativeContainerWidgetToYaml(widget, size, entities) {
321
+ export function declarativeContainerWidgetToYaml(widget, size, entities, errorContext) {
311
322
  const yamlWidget = new YAMLMap();
312
323
  // Local id of widget
313
324
  if (widget.localIdentifier) {
@@ -331,7 +342,7 @@ export function declarativeContainerWidgetToYaml(widget, size, entities) {
331
342
  // Nested sections
332
343
  if (widget.sections?.length) {
333
344
  const nestedSections = new YAMLSeq();
334
- widget.sections.forEach((section) => {
345
+ widget.sections.forEach((section, si) => {
335
346
  const yamlSection = new YAMLMap();
336
347
  if (section.header?.title) {
337
348
  yamlSection.add(new Pair("title", section.header.title));
@@ -341,8 +352,10 @@ export function declarativeContainerWidgetToYaml(widget, size, entities) {
341
352
  }
342
353
  if (section.items?.length) {
343
354
  const widgets = new YAMLSeq();
344
- section.items.forEach((item) => {
345
- const yamlNestedWidget = declarativeWidgetToYaml(item.widget, item.size, entities);
355
+ section.items.forEach((item, ii) => {
356
+ const yamlNestedWidget = declarativeWidgetToYaml(item.widget, item.size, entities, updateErrorContext(errorContext, {
357
+ path: ["sections", si.toString(), "items", ii.toString()],
358
+ }));
346
359
  if (yamlNestedWidget) {
347
360
  widgets.add(yamlNestedWidget);
348
361
  }
@@ -355,13 +368,14 @@ export function declarativeContainerWidgetToYaml(widget, size, entities) {
355
368
  }
356
369
  return yamlWidget;
357
370
  }
358
- export function declarativeDrillToYaml(drill, entities, sourceVisualizationId) {
371
+ export function declarativeDrillToYaml(drill, entities, sourceVisualizationId, errorContext) {
359
372
  const drillYaml = new YAMLMap();
360
373
  const originIdentifier = drill.origin.type === "drillFromMeasure" ? drill.origin.measure : drill.origin.attribute;
361
- drillYaml.add(new Pair("click_on", getIdentifier(originIdentifier)));
374
+ const originPath = drill.origin.type === "drillFromMeasure" ? "measure" : "attribute";
375
+ drillYaml.add(new Pair("click_on", getIdentifier(originIdentifier, undefined, updateErrorContext(errorContext, { path: ["origin", originPath] }))));
362
376
  if (isDrillToInsight(drill)) {
363
- drillYaml.add(new Pair("open_visualization", getIdentifier(drill.target, true)));
364
- const filters = drillFiltersToYaml(drill, entities, sourceVisualizationId);
377
+ drillYaml.add(new Pair("open_visualization", getIdentifier(drill.target, true, updateErrorContext(errorContext, { path: ["target"] }))));
378
+ const filters = drillFiltersToYaml(drill, entities, sourceVisualizationId, errorContext);
365
379
  if (filters) {
366
380
  drillYaml.add(new Pair("filters", filters));
367
381
  }
@@ -369,11 +383,11 @@ export function declarativeDrillToYaml(drill, entities, sourceVisualizationId) {
369
383
  }
370
384
  if (isDrillToDashboard(drill) && drill.target) {
371
385
  const dashboardDrill = drill;
372
- drillYaml.add(new Pair("open_dashboard", getIdentifier(drill.target, true)));
386
+ drillYaml.add(new Pair("open_dashboard", getIdentifier(drill.target, true, updateErrorContext(errorContext, { path: ["target"] }))));
373
387
  if (drill.targetTabLocalIdentifier) {
374
388
  drillYaml.add(new Pair("open_dashboard_tab", drill.targetTabLocalIdentifier));
375
389
  }
376
- const filters = drillFiltersToYaml(dashboardDrill, entities, sourceVisualizationId);
390
+ const filters = drillFiltersToYaml(dashboardDrill, entities, sourceVisualizationId, errorContext);
377
391
  if (filters) {
378
392
  drillYaml.add(new Pair("filters", filters));
379
393
  }
@@ -395,14 +409,14 @@ export function declarativeDrillToYaml(drill, entities, sourceVisualizationId) {
395
409
  drillYaml.add(new Pair("ignored_intersection_attributes", attrs));
396
410
  }
397
411
  drillYaml.add(new Pair("open_url", {
398
- label: getIdentifier(drill.target.displayForm),
399
- href: getIdentifier(drill.target.hyperlinkDisplayForm),
412
+ label: getIdentifier(drill.target.displayForm, undefined, updateErrorContext(errorContext, { path: ["target", "displayForm"] })),
413
+ href: getIdentifier(drill.target.hyperlinkDisplayForm, undefined, updateErrorContext(errorContext, { path: ["target", "hyperlinkDisplayForm"] })),
400
414
  }));
401
415
  return drillYaml;
402
416
  }
403
417
  return drillYaml;
404
418
  }
405
- function drillFiltersToYaml(drill, entities, sourceVisualizationId) {
419
+ function drillFiltersToYaml(drill, entities, sourceVisualizationId, errorContext) {
406
420
  const filtersYaml = new YAMLMap();
407
421
  const excludeYaml = new YAMLMap();
408
422
  const includeYaml = new YAMLMap();
@@ -417,10 +431,10 @@ function drillFiltersToYaml(drill, entities, sourceVisualizationId) {
417
431
  excludeYaml.add(new Pair("dashboard_filters", filters));
418
432
  }
419
433
  if (drill.includedSourceInsightFiltersObjRefs?.length) {
420
- includeYaml.add(new Pair("visualization_filters", filterRefsToYaml(drill.includedSourceInsightFiltersObjRefs, entities, sourceVisualizationId)));
434
+ includeYaml.add(new Pair("visualization_filters", filterRefsToYaml(drill.includedSourceInsightFiltersObjRefs, entities, sourceVisualizationId, updateErrorContext(errorContext, { path: ["includedSourceInsightFiltersObjRefs"] }))));
421
435
  }
422
436
  if (drill.includedSourceMeasureFiltersObjRefs?.length) {
423
- includeYaml.add(new Pair("metric_filters", sourceMeasureFilterRefsToYaml(drill.includedSourceMeasureFiltersObjRefs, entities, sourceVisualizationId)));
437
+ includeYaml.add(new Pair("metric_filters", sourceMeasureFilterRefsToYaml(drill.includedSourceMeasureFiltersObjRefs, entities, sourceVisualizationId, updateErrorContext(errorContext, { path: ["includedSourceMeasureFiltersObjRefs"] }))));
424
438
  }
425
439
  if (excludeYaml.items.length) {
426
440
  filtersYaml.add(new Pair("exclude", excludeYaml));
@@ -430,51 +444,62 @@ function drillFiltersToYaml(drill, entities, sourceVisualizationId) {
430
444
  }
431
445
  return filtersYaml.items.length ? filtersYaml : null;
432
446
  }
433
- function filterRefsToYaml(refs, entities, sourceVisualizationId) {
447
+ function filterRefsToYaml(refs, entities, sourceVisualizationId, errorContext) {
434
448
  const visualisation = entities?.find((entity) => VisualisationsTypes.includes(entity.type) && entity.id === sourceVisualizationId)?.data;
435
449
  const filters = visualisation?.query?.filter_by;
436
450
  return refs
437
- .map((ref) => findSourceInsightFilterId(filters, ref) ?? sourceInsightFilterRefFallbackId(ref))
451
+ .map((ref) => findSourceInsightFilterId(filters, ref, errorContext) ??
452
+ sourceInsightFilterRefFallbackId(ref, errorContext))
438
453
  .filter(Boolean);
439
454
  }
440
- function findSourceInsightFilterId(filters, ref) {
455
+ function findSourceInsightFilterId(filters, ref, errorContext) {
441
456
  if (!filters) {
442
457
  return undefined;
443
458
  }
444
- return Object.entries(filters).find(([_, filter]) => matchesSourceInsightFilterRef(filter, ref))?.[0];
459
+ return Object.entries(filters).find(([_, filter]) => matchesSourceInsightFilterRef(filter, ref, errorContext))?.[0];
445
460
  }
446
- function matchesSourceInsightFilterRef(filter, ref) {
461
+ function matchesSourceInsightFilterRef(filter, ref, errorContext) {
447
462
  switch (ref.type) {
448
463
  case "attributeFilter":
449
- return filter.type === "attribute_filter" && filter.using === getIdentifier(ref["label"]);
464
+ return (filter.type === "attribute_filter" &&
465
+ filter.using ===
466
+ getIdentifier(ref["label"], undefined, updateErrorContext(errorContext, { path: ["attributeFilter"] })));
450
467
  case "dateFilter":
451
- return filter.type === "date_filter" && filter.using === getIdentifier(ref["dataSet"], true);
468
+ return (filter.type === "date_filter" &&
469
+ filter.using ===
470
+ getIdentifier(ref["dataSet"], true, updateErrorContext(errorContext, { path: ["dateFilter"] })));
452
471
  case "measureValueFilter":
453
- return filter.type === "metric_value_filter" && filter.using === getIdentifier(ref["measure"]);
472
+ return (filter.type === "metric_value_filter" &&
473
+ filter.using ===
474
+ getIdentifier(ref["measure"], undefined, updateErrorContext(errorContext, { path: ["measureValueFilter"] })));
454
475
  case "rankingFilter":
455
- return filter.type === "ranking_filter" && filter.using === getIdentifier(ref["measure"]);
476
+ return (filter.type === "ranking_filter" &&
477
+ filter.using ===
478
+ getIdentifier(ref["measure"], undefined, updateErrorContext(errorContext, { path: ["rankingFilter"] })));
456
479
  default:
457
480
  return false;
458
481
  }
459
482
  }
460
- function sourceInsightFilterRefFallbackId(ref) {
483
+ function sourceInsightFilterRefFallbackId(ref, errorContext) {
461
484
  switch (ref.type) {
462
485
  case "attributeFilter":
463
- return getIdentifier(ref["label"]);
486
+ return getIdentifier(ref["label"], undefined, updateErrorContext(errorContext, { path: ["attributeFilter"] }));
464
487
  case "dateFilter":
465
- return getIdentifier(ref["dataSet"], true);
488
+ return getIdentifier(ref["dataSet"], true, updateErrorContext(errorContext, { path: ["dateFilter"] }));
466
489
  case "measureValueFilter":
490
+ return getIdentifier(ref["measure"], undefined, updateErrorContext(errorContext, { path: ["measureValueFilter"] }));
467
491
  case "rankingFilter":
468
- return getIdentifier(ref["measure"]);
492
+ return getIdentifier(ref["measure"], undefined, updateErrorContext(errorContext, { path: ["rankingFilter"] }));
469
493
  default:
470
494
  return null;
471
495
  }
472
496
  }
473
- function sourceMeasureFilterRefsToYaml(refs, entities, sourceVisualizationId) {
497
+ function sourceMeasureFilterRefsToYaml(refs, entities, sourceVisualizationId, errorContext) {
474
498
  const visualisation = entities?.find((entity) => VisualisationsTypes.includes(entity.type) && entity.id === sourceVisualizationId)?.data;
475
499
  const fieldFilters = collectFieldLevelFilters(visualisation);
476
500
  return refs
477
- .map((ref) => findSourceInsightFilterId(fieldFilters, ref) ?? sourceInsightFilterRefFallbackId(ref))
501
+ .map((ref) => findSourceInsightFilterId(fieldFilters, ref, errorContext) ??
502
+ sourceInsightFilterRefFallbackId(ref, errorContext))
478
503
  .filter(Boolean);
479
504
  }
480
505
  function getDateFilterEmptyValueHandling(filter) {
@@ -484,7 +509,7 @@ function getDateFilterEmptyValueHandling(filter) {
484
509
  }
485
510
  return undefined;
486
511
  }
487
- export function declarativeFilterContextToYaml(dateFilterConfig, filterContext) {
512
+ export function declarativeFilterContextToYaml(dateFilterConfig, filterContext, errorContext) {
488
513
  const filters = [];
489
514
  const filtersMap = {};
490
515
  const content = filterContext ? filterContext.content : undefined;
@@ -493,9 +518,9 @@ export function declarativeFilterContextToYaml(dateFilterConfig, filterContext)
493
518
  if (isDashboardDateFilter(filter) && isNoopAllTimeDashboardDateFilter(filter)) {
494
519
  return;
495
520
  }
496
- const key = createFilterContextItemKeyName(filter);
521
+ const key = createFilterContextItemKeyName(filter, "date", updateErrorContext(errorContext, { path: ["date"] }));
497
522
  if (isDashboardDateFilter(filter)) {
498
- const def = declarativeDateFilterToYaml(filter);
523
+ const def = declarativeDateFilterToYaml(filter, errorContext);
499
524
  filters.push(new Pair(key, def));
500
525
  filtersMap[key] = {
501
526
  yaml: def,
@@ -503,7 +528,7 @@ export function declarativeFilterContextToYaml(dateFilterConfig, filterContext)
503
528
  };
504
529
  }
505
530
  if (isDashboardAttributeFilter(filter)) {
506
- const def = declarativeAttributeFilterToYaml(filter);
531
+ const def = declarativeAttributeFilterToYaml(filter, errorContext);
507
532
  filters.push(new Pair(key, def));
508
533
  filtersMap[key] = {
509
534
  yaml: def,
@@ -511,7 +536,7 @@ export function declarativeFilterContextToYaml(dateFilterConfig, filterContext)
511
536
  };
512
537
  }
513
538
  if (isDashboardArbitraryAttributeFilter(filter)) {
514
- const def = declarativeArbitraryTextFilterToYaml(filter);
539
+ const def = declarativeArbitraryTextFilterToYaml(filter, errorContext);
515
540
  filters.push(new Pair(key, def));
516
541
  filtersMap[key] = {
517
542
  yaml: def,
@@ -519,7 +544,7 @@ export function declarativeFilterContextToYaml(dateFilterConfig, filterContext)
519
544
  };
520
545
  }
521
546
  if (isDashboardMatchAttributeFilter(filter)) {
522
- const def = declarativeMatchTextFilterToYaml(filter);
547
+ const def = declarativeMatchTextFilterToYaml(filter, errorContext);
523
548
  filters.push(new Pair(key, def));
524
549
  filtersMap[key] = {
525
550
  yaml: def,
@@ -541,8 +566,8 @@ export function declarativeFilterContextToYaml(dateFilterConfig, filterContext)
541
566
  type: "absolute",
542
567
  },
543
568
  };
544
- const key = createFilterContextItemKeyName(filter, "common");
545
- const def = declarativeDateFilterToYaml(filter);
569
+ const key = createFilterContextItemKeyName(filter, "common", updateErrorContext(errorContext, { path: ["common"] }));
570
+ const def = declarativeDateFilterToYaml(filter, errorContext);
546
571
  filters.unshift(new Pair(key, def));
547
572
  filtersMap[key] = {
548
573
  yaml: def,
@@ -578,7 +603,7 @@ export function declarativeFilterContextToYaml(dateFilterConfig, filterContext)
578
603
  }
579
604
  //metric filters
580
605
  const metricsIds = filterBody.validateElementsBy
581
- ?.map((element) => getIdentifier(element))
606
+ ?.map((element, i) => getIdentifier(element, undefined, updateErrorContext(errorContext, { path: ["validateElementsBy", i.toString()] })))
582
607
  .filter(Boolean);
583
608
  if (metricsIds?.length) {
584
609
  yaml.add(new Pair("metric_filters", metricsIds));
@@ -593,7 +618,7 @@ export function declarativeFilterContextToYaml(dateFilterConfig, filterContext)
593
618
  filtersMap,
594
619
  };
595
620
  }
596
- function declarativeDateFilterToYaml(filter) {
621
+ function declarativeDateFilterToYaml(filter, errorContext) {
597
622
  const dateFilter = new YAMLMap();
598
623
  dateFilter.add(new Pair("type", "date_filter"));
599
624
  const gran = parseGranularity(filter.dateFilter.granularity);
@@ -601,7 +626,7 @@ function declarativeDateFilterToYaml(filter) {
601
626
  dateFilter.add(new Pair("granularity", gran));
602
627
  }
603
628
  if (filter.dateFilter.dataSet) {
604
- dateFilter.add(new Pair("date", getIdentifier(filter.dateFilter.dataSet, true)));
629
+ dateFilter.add(new Pair("date", getIdentifier(filter.dateFilter.dataSet, true, updateErrorContext(errorContext, { path: ["date"] }))));
605
630
  }
606
631
  if (isRelativeDashboardDateFilter(filter)) {
607
632
  // Relative filter
@@ -626,13 +651,13 @@ function declarativeDateFilterToYaml(filter) {
626
651
  }
627
652
  return dateFilter;
628
653
  }
629
- function declarativeAttributeFilterToYaml(filter) {
654
+ function declarativeAttributeFilterToYaml(filter, errorContext) {
630
655
  const attributeFilter = new YAMLMap();
631
656
  attributeFilter.add(new Pair("type", "attribute_filter"));
632
657
  if (filter.attributeFilter.title) {
633
658
  attributeFilter.add(new Pair("title", filter.attributeFilter.title));
634
659
  }
635
- const attributeId = getIdentifier(filter.attributeFilter.displayForm);
660
+ const attributeId = getIdentifier(filter.attributeFilter.displayForm, undefined, updateErrorContext(errorContext, { path: ["attributeFilter", "displayForm"] }));
636
661
  attributeFilter.add(new Pair("using", attributeId));
637
662
  if (filter.attributeFilter.selectionMode === "single") {
638
663
  attributeFilter.add(new Pair("multiselect", false));
@@ -656,24 +681,24 @@ function declarativeAttributeFilterToYaml(filter) {
656
681
  }
657
682
  return attributeFilter;
658
683
  }
659
- function declarativeArbitraryTextFilterToYaml(filter) {
684
+ function declarativeArbitraryTextFilterToYaml(filter, errorContext) {
660
685
  const textFilter = new YAMLMap();
661
686
  textFilter.add(new Pair("type", "text_filter"));
662
687
  if (filter.arbitraryAttributeFilter.title) {
663
688
  textFilter.add(new Pair("title", filter.arbitraryAttributeFilter.title));
664
689
  }
665
- textFilter.add(new Pair("using", getIdentifier(filter.arbitraryAttributeFilter.displayForm)));
690
+ textFilter.add(new Pair("using", getIdentifier(filter.arbitraryAttributeFilter.displayForm, undefined, updateErrorContext(errorContext, { path: ["arbitraryAttributeFilter", "displayForm"] }))));
666
691
  textFilter.add(new Pair("condition", filter.arbitraryAttributeFilter.negativeSelection ? "isNot" : "is"));
667
692
  textFilter.add(new Pair("values", filter.arbitraryAttributeFilter.values));
668
693
  return textFilter;
669
694
  }
670
- function declarativeMatchTextFilterToYaml(filter) {
695
+ function declarativeMatchTextFilterToYaml(filter, errorContext) {
671
696
  const textFilter = new YAMLMap();
672
697
  textFilter.add(new Pair("type", "text_filter"));
673
698
  if (filter.matchAttributeFilter.title) {
674
699
  textFilter.add(new Pair("title", filter.matchAttributeFilter.title));
675
700
  }
676
- textFilter.add(new Pair("using", getIdentifier(filter.matchAttributeFilter.displayForm)));
701
+ textFilter.add(new Pair("using", getIdentifier(filter.matchAttributeFilter.displayForm, undefined, updateErrorContext(errorContext, { path: ["matchAttributeFilter", "displayForm"] }))));
677
702
  textFilter.add(new Pair("condition", matchConditionToYaml(filter.matchAttributeFilter.operator, filter.matchAttributeFilter.negativeSelection)));
678
703
  textFilter.add(new Pair("value", filter.matchAttributeFilter.literal));
679
704
  if (filter.matchAttributeFilter.caseSensitive !== undefined) {
@@ -681,20 +706,25 @@ function declarativeMatchTextFilterToYaml(filter) {
681
706
  }
682
707
  return textFilter;
683
708
  }
684
- export function declarativeFiltersConfigToYaml(filtersMap, dateFilterConfig, dateFilterConfigs, attributeFilterConfigs) {
685
- attributeFilterConfigs?.forEach((filterSettings) => {
709
+ export function declarativeFiltersConfigToYaml(filtersMap, dateFilterConfig, dateFilterConfigs, attributeFilterConfigs, errorContext) {
710
+ attributeFilterConfigs?.forEach((filterSettings, i) => {
686
711
  const filter = filtersMap[filterSettings.localIdentifier];
687
712
  if (filter) {
688
713
  if (filterSettings.mode && filterSettings.mode !== "active") {
689
714
  filter.yaml.add(new Pair("mode", filterSettings.mode));
690
715
  }
691
716
  if (filterSettings.displayAsLabel) {
692
- filter.yaml.add(new Pair("display_as", getIdentifier(filterSettings.displayAsLabel)));
717
+ filter.yaml.add(new Pair("display_as", getIdentifier(filterSettings.displayAsLabel, undefined, updateErrorContext(errorContext, {
718
+ path: ["attributeFilterConfig", i.toString(), "displayAsLabel"],
719
+ }))));
693
720
  }
694
721
  }
695
722
  });
696
- dateFilterConfigs?.forEach((filterSettings) => {
697
- const filter = Object.values(filtersMap).find((filter) => filter.yaml.get("date") === getIdentifier(filterSettings.dateDataSet, true));
723
+ dateFilterConfigs?.forEach((filterSettings, i) => {
724
+ const filter = Object.values(filtersMap).find((filter) => filter.yaml.get("date") ===
725
+ getIdentifier(filterSettings.dateDataSet, true, updateErrorContext(errorContext, {
726
+ path: ["dateFilterConfig", i.toString(), "dateDataSet"],
727
+ })));
698
728
  fillDateFilterConfig(filterSettings.config, filter);
699
729
  });
700
730
  if (dateFilterConfig) {
@@ -787,13 +817,13 @@ function getFilterGroupIdBase({ title, localIdentifier }) {
787
817
  .replace(/[^a-zA-Z0-9]/g, "_")
788
818
  .toLowerCase();
789
819
  }
790
- export function declarativePluginsToYaml(dashboard) {
820
+ export function declarativePluginsToYaml(dashboard, errorContext) {
791
821
  if (!dashboard.plugins?.length) {
792
822
  return;
793
823
  }
794
824
  const plugins = new YAMLSeq();
795
- dashboard.plugins.forEach((plugin) => {
796
- const pluginId = getIdentifier(plugin.plugin, true);
825
+ dashboard.plugins.forEach((plugin, i) => {
826
+ const pluginId = getIdentifier(plugin.plugin, true, updateErrorContext(errorContext, { path: [i.toString(), "plugin"] }));
797
827
  if (plugin.parameters?.length) {
798
828
  plugins.add({
799
829
  id: pluginId,