@adminforth/dashboard 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +43 -52
  2. package/custom/composables/useElementSize.ts +17 -2
  3. package/custom/model/dashboard.types.ts +385 -98
  4. package/custom/runtime/DashboardRuntime.vue +2 -1
  5. package/custom/runtime/WidgetRenderer.vue +2 -1
  6. package/custom/skills/adminforth-dashboard/SKILL.md +8 -4
  7. package/custom/widgets/chart/ChartWidget.vue +36 -35
  8. package/custom/widgets/chart/bar/BarChart.vue +20 -12
  9. package/custom/widgets/chart/chart.types.ts +42 -8
  10. package/custom/widgets/chart/chart.utils.ts +11 -0
  11. package/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
  12. package/custom/widgets/chart/line/LineChart.vue +23 -15
  13. package/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
  14. package/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -43
  15. package/custom/widgets/kpi-card/KpiCardWidget.vue +6 -10
  16. package/custom/widgets/pivot-table/PivotTableWidget.vue +10 -11
  17. package/custom/widgets/table/TableWidget.vue +9 -4
  18. package/dist/custom/composables/useElementSize.js +14 -2
  19. package/dist/custom/composables/useElementSize.ts +17 -2
  20. package/dist/custom/model/dashboard.types.d.ts +179 -38
  21. package/dist/custom/model/dashboard.types.js +108 -42
  22. package/dist/custom/model/dashboard.types.ts +385 -98
  23. package/dist/custom/queries/useDashboardConfig.d.ts +832 -68
  24. package/dist/custom/queries/useWidgetData.d.ts +828 -64
  25. package/dist/custom/runtime/DashboardRuntime.vue +2 -1
  26. package/dist/custom/runtime/WidgetRenderer.vue +2 -1
  27. package/dist/custom/skills/adminforth-dashboard/SKILL.md +8 -4
  28. package/dist/custom/widgets/chart/ChartWidget.vue +36 -35
  29. package/dist/custom/widgets/chart/bar/BarChart.vue +20 -12
  30. package/dist/custom/widgets/chart/chart.types.d.ts +14 -8
  31. package/dist/custom/widgets/chart/chart.types.js +23 -0
  32. package/dist/custom/widgets/chart/chart.types.ts +42 -8
  33. package/dist/custom/widgets/chart/chart.utils.d.ts +1 -0
  34. package/dist/custom/widgets/chart/chart.utils.js +7 -0
  35. package/dist/custom/widgets/chart/chart.utils.ts +11 -0
  36. package/dist/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
  37. package/dist/custom/widgets/chart/line/LineChart.vue +23 -15
  38. package/dist/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
  39. package/dist/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -43
  40. package/dist/custom/widgets/kpi-card/KpiCardWidget.vue +6 -10
  41. package/dist/custom/widgets/pivot-table/PivotTableWidget.vue +10 -11
  42. package/dist/custom/widgets/table/TableWidget.vue +9 -4
  43. package/dist/endpoint/widgets.js +23 -3
  44. package/dist/schema/api.d.ts +2637 -933
  45. package/dist/schema/widget.d.ts +1562 -582
  46. package/dist/schema/widget.js +207 -127
  47. package/dist/services/widgetConfigValidator.js +16 -80
  48. package/dist/services/widgetDataService.d.ts +0 -9
  49. package/dist/services/widgetDataService.js +356 -97
  50. package/endpoint/dashboard.ts +1 -1
  51. package/endpoint/widgets.ts +29 -3
  52. package/package.json +1 -1
  53. package/schema/widget.ts +221 -121
  54. package/services/widgetConfigValidator.ts +29 -100
  55. package/services/widgetDataService.ts +478 -129
@@ -113,10 +113,11 @@
113
113
  <script setup lang="ts">
114
114
  import { computed, ref, watch } from 'vue'
115
115
  import { useWidgetData } from '../../queries/useWidgetData.js'
116
- import type { DashboardWidgetConfig, DashboardWidgetTableData } from '../../model/dashboard.types.js'
116
+ import { getFieldRefField } from '../../model/dashboard.types.js'
117
+ import type { DashboardWidgetConfig, DashboardWidgetTableData, FieldRef } from '../../model/dashboard.types.js'
117
118
 
118
119
  type TableWidgetConfig = {
119
- columns?: string[]
120
+ columns?: FieldRef[]
120
121
  pagination?: boolean
121
122
  pageSize?: number
122
123
  }
@@ -132,7 +133,7 @@ const currentPage = ref(1)
132
133
  const currentPageInput = ref(1)
133
134
  const tableConfig = computed(() => props.widget.table as TableWidgetConfig | undefined)
134
135
  const isPaginationEnabled = computed(() => tableConfig.value?.pagination !== false)
135
- const pageSize = computed(() => tableConfig.value?.pageSize ?? props.widget.query?.limit ?? DEFAULT_PAGE_SIZE)
136
+ const pageSize = computed(() => tableConfig.value?.pageSize ?? DEFAULT_PAGE_SIZE)
136
137
  const dashboardSlugRef = computed(() => props.dashboardSlug)
137
138
  const widgetIdRef = computed(() => props.widget.id)
138
139
  const widgetDataRequest = computed(() => (
@@ -168,7 +169,11 @@ const tableData = computed(() => {
168
169
 
169
170
  const columns = computed(() => {
170
171
  const configuredColumns = tableConfig.value?.columns
171
- return configuredColumns ?? tableData.value?.columns ?? []
172
+ if (configuredColumns) {
173
+ return configuredColumns.map((column) => getFieldRefField(column)).filter(Boolean) as string[]
174
+ }
175
+
176
+ return tableData.value?.columns ?? []
172
177
  })
173
178
 
174
179
  const pagination = computed(() => tableData.value?.pagination)
@@ -7,19 +7,31 @@ function useElementSize() {
7
7
  const width = (0, vue_1.ref)(0);
8
8
  const height = (0, vue_1.ref)(0);
9
9
  let observer;
10
+ let frameId;
10
11
  (0, vue_1.onMounted)(() => {
11
12
  observer = new ResizeObserver(([entry]) => {
12
13
  if (!entry) {
13
14
  return;
14
15
  }
15
- width.value = Math.floor(entry.contentRect.width);
16
- height.value = Math.floor(entry.contentRect.height);
16
+ const nextWidth = Math.floor(entry.contentRect.width);
17
+ const nextHeight = Math.floor(entry.contentRect.height);
18
+ if (frameId !== undefined) {
19
+ cancelAnimationFrame(frameId);
20
+ }
21
+ frameId = requestAnimationFrame(() => {
22
+ frameId = undefined;
23
+ width.value = nextWidth;
24
+ height.value = nextHeight;
25
+ });
17
26
  });
18
27
  if (el.value) {
19
28
  observer.observe(el.value);
20
29
  }
21
30
  });
22
31
  (0, vue_1.onBeforeUnmount)(() => {
32
+ if (frameId !== undefined) {
33
+ cancelAnimationFrame(frameId);
34
+ }
23
35
  observer === null || observer === void 0 ? void 0 : observer.disconnect();
24
36
  });
25
37
  return {
@@ -13,6 +13,7 @@ export function useElementSize<T extends HTMLElement>(): ElementSizeState<T> {
13
13
  const height = ref(0)
14
14
 
15
15
  let observer: ResizeObserver | undefined
16
+ let frameId: number | undefined
16
17
 
17
18
  onMounted(() => {
18
19
  observer = new ResizeObserver(([entry]) => {
@@ -20,8 +21,18 @@ export function useElementSize<T extends HTMLElement>(): ElementSizeState<T> {
20
21
  return
21
22
  }
22
23
 
23
- width.value = Math.floor(entry.contentRect.width)
24
- height.value = Math.floor(entry.contentRect.height)
24
+ const nextWidth = Math.floor(entry.contentRect.width)
25
+ const nextHeight = Math.floor(entry.contentRect.height)
26
+
27
+ if (frameId !== undefined) {
28
+ cancelAnimationFrame(frameId)
29
+ }
30
+
31
+ frameId = requestAnimationFrame(() => {
32
+ frameId = undefined
33
+ width.value = nextWidth
34
+ height.value = nextHeight
35
+ })
25
36
  })
26
37
 
27
38
  if (el.value) {
@@ -30,6 +41,10 @@ export function useElementSize<T extends HTMLElement>(): ElementSizeState<T> {
30
41
  })
31
42
 
32
43
  onBeforeUnmount(() => {
44
+ if (frameId !== undefined) {
45
+ cancelAnimationFrame(frameId)
46
+ }
47
+
33
48
  observer?.disconnect()
34
49
  })
35
50
 
@@ -1,33 +1,4 @@
1
1
  import type { ChartWidgetConfig } from '../widgets/chart/chart.types.js';
2
- export type AggregationOperation = 'sum' | 'count' | 'avg' | 'min' | 'max' | 'median';
3
- export type AggregationRule = {
4
- operation: AggregationOperation;
5
- field?: string;
6
- };
7
- export type GroupByRule = {
8
- type: 'field';
9
- field: string;
10
- } | {
11
- type: 'date_trunc';
12
- field: string;
13
- truncation: 'day' | 'week' | 'month' | 'year';
14
- timezone?: string;
15
- };
16
- export type ResourceWidgetDataSource = {
17
- type: 'resource';
18
- resourceId: string;
19
- columns?: string[];
20
- sort?: unknown;
21
- filters?: unknown;
22
- };
23
- export type AggregateWidgetDataSource = {
24
- type: 'aggregate';
25
- resourceId: string;
26
- aggregations: Record<string, AggregationRule>;
27
- groupBy?: GroupByRule;
28
- filters?: unknown;
29
- };
30
- export type WidgetDataSource = ResourceWidgetDataSource | AggregateWidgetDataSource;
31
2
  export type DashboardConfig = {
32
3
  version: number;
33
4
  groups: DashboardGroupConfig[];
@@ -42,6 +13,9 @@ export type DashboardGroupMoveDirection = 'up' | 'down';
42
13
  export type DashboardWidgetMoveDirection = 'up' | 'down';
43
14
  export type DashboardWidgetTarget = 'empty' | 'table' | 'chart' | 'kpi_card' | 'pivot_table' | 'gauge_card';
44
15
  export type DashboardWidgetSize = 'small' | 'medium' | 'large' | 'wide' | 'full';
16
+ export type QueryAggregateOperation = 'sum' | 'count' | 'count_distinct' | 'avg' | 'min' | 'max' | 'median';
17
+ export type TimeGrain = 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';
18
+ export type ValueFormat = 'number' | 'compact_number' | 'currency' | 'percent' | 'percent_delta' | 'number_delta' | 'currency_delta';
45
19
  export type WidgetLayout = {
46
20
  size?: DashboardWidgetSize;
47
21
  width?: number;
@@ -49,7 +23,7 @@ export type WidgetLayout = {
49
23
  maxWidth?: number | null;
50
24
  height?: number;
51
25
  };
52
- export type DashboardWidgetConfig = {
26
+ export type WidgetBaseConfig = {
53
27
  id: string;
54
28
  group_id: string;
55
29
  label?: string;
@@ -59,15 +33,173 @@ export type DashboardWidgetConfig = {
59
33
  minWidth?: number;
60
34
  maxWidth?: number | null;
61
35
  order: number;
62
- target: DashboardWidgetTarget;
63
- dataSource?: WidgetDataSource;
64
- chart?: ChartWidgetConfig;
65
- table?: unknown;
66
- kpi_card?: unknown;
67
- pivot_table?: unknown;
68
- gauge_card?: unknown;
69
- query?: unknown;
70
36
  };
37
+ export type FilterExpression = {
38
+ and: FilterExpression[];
39
+ } | {
40
+ or: FilterExpression[];
41
+ } | Array<FilterExpression> | {
42
+ field: string;
43
+ eq?: unknown;
44
+ neq?: unknown;
45
+ gt?: unknown;
46
+ gte?: unknown;
47
+ lt?: unknown;
48
+ lte?: unknown;
49
+ in?: unknown[];
50
+ not_in?: unknown[];
51
+ like?: unknown;
52
+ ilike?: unknown;
53
+ };
54
+ export type QueryFieldSelectItem = {
55
+ field: string;
56
+ as?: string;
57
+ grain?: TimeGrain;
58
+ };
59
+ export type QueryAggregateSelectItem = {
60
+ agg: QueryAggregateOperation;
61
+ field?: string;
62
+ as: string;
63
+ filters?: FilterExpression;
64
+ };
65
+ export type QueryCalcSelectItem = {
66
+ calc: string;
67
+ as: string;
68
+ };
69
+ export type QuerySelectItem = QueryFieldSelectItem | QueryAggregateSelectItem | QueryCalcSelectItem;
70
+ export type QueryGroupByItem = string | {
71
+ field: string;
72
+ as?: string;
73
+ grain?: TimeGrain;
74
+ timezone?: string;
75
+ };
76
+ export type QueryOrderByItem = {
77
+ field: string;
78
+ direction?: 'asc' | 'desc';
79
+ };
80
+ export type QueryConfig = {
81
+ resource: string;
82
+ select?: QuerySelectItem[];
83
+ filters?: FilterExpression;
84
+ groupBy?: QueryGroupByItem[];
85
+ orderBy?: QueryOrderByItem[];
86
+ limit?: number;
87
+ offset?: number;
88
+ timeSeries?: {
89
+ field: string;
90
+ grain: TimeGrain;
91
+ timezone?: string;
92
+ };
93
+ period?: {
94
+ field: string;
95
+ gte?: unknown;
96
+ lt?: unknown;
97
+ };
98
+ bucket?: {
99
+ field: string;
100
+ buckets: Array<{
101
+ label: string;
102
+ min?: number;
103
+ max?: number;
104
+ }>;
105
+ };
106
+ calcs?: QueryCalcSelectItem[];
107
+ formatting?: Record<string, unknown>;
108
+ };
109
+ export type FunnelQueryConfig = {
110
+ steps: FunnelQueryStep[];
111
+ };
112
+ export type FunnelQueryStep = {
113
+ name: string;
114
+ resource: string;
115
+ metric: QueryAggregateSelectItem;
116
+ filters?: FilterExpression;
117
+ };
118
+ export type FieldRef = string | {
119
+ field: string;
120
+ label?: string;
121
+ format?: ValueFormat;
122
+ };
123
+ export type TableViewConfig = {
124
+ columns?: FieldRef[];
125
+ pagination?: boolean;
126
+ pageSize?: number;
127
+ };
128
+ export type KpiCardViewConfig = {
129
+ title?: string;
130
+ value: {
131
+ field: string;
132
+ format?: ValueFormat;
133
+ prefix?: string;
134
+ suffix?: string;
135
+ };
136
+ subtitle?: {
137
+ text?: string;
138
+ field?: string;
139
+ };
140
+ comparison?: unknown;
141
+ sparkline?: unknown;
142
+ };
143
+ export type GaugeCardViewConfig = {
144
+ title?: string;
145
+ value: {
146
+ field: string;
147
+ format?: ValueFormat;
148
+ prefix?: string;
149
+ suffix?: string;
150
+ };
151
+ target?: {
152
+ value?: number;
153
+ field?: string;
154
+ label?: string;
155
+ };
156
+ progress?: {
157
+ valueField: string;
158
+ targetValue?: number;
159
+ targetField?: string;
160
+ format?: ValueFormat;
161
+ };
162
+ color?: string;
163
+ };
164
+ export type PivotTableViewConfig = {
165
+ rows: FieldRef[];
166
+ columns?: FieldRef[];
167
+ values: Array<{
168
+ field: string;
169
+ label?: string;
170
+ format?: ValueFormat;
171
+ aggregation?: 'sum' | 'count' | 'avg' | 'min' | 'max';
172
+ }>;
173
+ };
174
+ export type EmptyWidgetConfig = WidgetBaseConfig & {
175
+ target: 'empty';
176
+ };
177
+ export type TableWidgetConfig = WidgetBaseConfig & {
178
+ target: 'table';
179
+ table?: TableViewConfig;
180
+ query: QueryConfig;
181
+ };
182
+ export type ChartDashboardWidgetConfig = WidgetBaseConfig & {
183
+ target: 'chart';
184
+ chart: ChartWidgetConfig;
185
+ query: QueryConfig | FunnelQueryConfig;
186
+ };
187
+ export type KpiCardWidgetConfig = WidgetBaseConfig & {
188
+ target: 'kpi_card';
189
+ card: KpiCardViewConfig;
190
+ query: QueryConfig;
191
+ };
192
+ export type GaugeCardWidgetConfig = WidgetBaseConfig & {
193
+ target: 'gauge_card';
194
+ card: GaugeCardViewConfig;
195
+ query: QueryConfig;
196
+ };
197
+ export type PivotTableWidgetConfig = WidgetBaseConfig & {
198
+ target: 'pivot_table';
199
+ pivot: PivotTableViewConfig;
200
+ query: QueryConfig;
201
+ };
202
+ export type DashboardWidgetConfig = EmptyWidgetConfig | TableWidgetConfig | ChartDashboardWidgetConfig | KpiCardWidgetConfig | GaugeCardWidgetConfig | PivotTableWidgetConfig;
71
203
  export type DashboardWidgetTableData = {
72
204
  kind?: 'table';
73
205
  columns: string[];
@@ -84,7 +216,16 @@ export type DashboardWidgetAggregateData = {
84
216
  columns: string[];
85
217
  rows: Record<string, unknown>[];
86
218
  values?: Record<string, unknown>;
219
+ pagination?: {
220
+ page: number;
221
+ pageSize: number;
222
+ total: number;
223
+ totalPages: number;
224
+ };
87
225
  };
88
226
  export type DashboardWidgetData = DashboardWidgetTableData | DashboardWidgetAggregateData;
89
227
  export declare function normalizeDashboardConfig(config: unknown): DashboardConfig;
90
228
  export declare function normalizeDashboardWidgetConfig(config: unknown): unknown;
229
+ export declare function serializeDashboardWidgetConfigForEditor(widget: DashboardWidgetConfig): Record<string, unknown>;
230
+ export declare function getFieldRefField(value: FieldRef | undefined): string | undefined;
231
+ export declare function getFieldRefLabel(value: FieldRef | undefined): string | undefined;
@@ -2,6 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizeDashboardConfig = normalizeDashboardConfig;
4
4
  exports.normalizeDashboardWidgetConfig = normalizeDashboardWidgetConfig;
5
+ exports.serializeDashboardWidgetConfigForEditor = serializeDashboardWidgetConfigForEditor;
6
+ exports.getFieldRefField = getFieldRefField;
7
+ exports.getFieldRefLabel = getFieldRefLabel;
5
8
  function normalizeDashboardConfig(config) {
6
9
  const value = isRecord(config) ? config : {};
7
10
  return {
@@ -13,29 +16,59 @@ function normalizeDashboardConfig(config) {
13
16
  };
14
17
  }
15
18
  function normalizeDashboardWidgetConfig(config) {
16
- var _a;
17
19
  if (!isRecord(config)) {
18
20
  return config;
19
21
  }
20
22
  const normalized = Object.assign({}, config);
21
- const target = normalizeDashboardWidgetTarget((_a = normalized.target) !== null && _a !== void 0 ? _a : normalized.type);
22
- if (target && normalized.target === undefined) {
23
- normalized.target = target;
23
+ normalizeWidgetLayoutConfig(normalized);
24
+ if (normalized.query !== undefined) {
25
+ normalized.query = normalizeQueryConfig(normalized.query);
26
+ }
27
+ if (normalized.table !== undefined) {
28
+ normalized.table = normalizeTableConfig(normalized.table);
29
+ }
30
+ if (normalized.card !== undefined) {
31
+ normalized.card = normalizeCardConfig(normalized.card);
24
32
  }
25
- if (target === 'kpi_card') {
26
- const kpiCardConfig = normalizeKpiCardConfig(normalized);
27
- if (kpiCardConfig !== undefined) {
28
- normalized.kpi_card = kpiCardConfig;
29
- }
33
+ if (normalized.pivot !== undefined) {
34
+ normalized.pivot = normalizePivotConfig(normalized.pivot);
30
35
  }
31
- if (target === 'gauge_card') {
32
- const gaugeCardConfig = normalizeGaugeCardConfig(normalized);
33
- if (gaugeCardConfig !== undefined) {
34
- normalized.gauge_card = gaugeCardConfig;
35
- }
36
+ const target = normalizeDashboardWidgetTarget(normalized.target);
37
+ if (target !== undefined) {
38
+ normalized.target = target;
36
39
  }
37
40
  return normalized;
38
41
  }
42
+ function serializeDashboardWidgetConfigForEditor(widget) {
43
+ const serialized = Object.assign({}, widget);
44
+ if (Object.prototype.hasOwnProperty.call(serialized, 'minWidth')) {
45
+ serialized.min_width = widget.minWidth;
46
+ delete serialized.minWidth;
47
+ }
48
+ if (Object.prototype.hasOwnProperty.call(serialized, 'maxWidth')) {
49
+ serialized.max_width = widget.maxWidth;
50
+ delete serialized.maxWidth;
51
+ }
52
+ if ('query' in widget) {
53
+ serialized.query = serializeQueryConfigForEditor(widget.query);
54
+ }
55
+ if ('table' in widget && widget.table !== undefined) {
56
+ serialized.table = serializeTableConfigForEditor(widget.table);
57
+ }
58
+ if ('card' in widget && widget.card !== undefined) {
59
+ serialized.card = serializeCardConfigForEditor(widget.card);
60
+ }
61
+ if ('pivot' in widget && widget.pivot !== undefined) {
62
+ serialized.pivot = serializePivotConfigForEditor(widget.pivot);
63
+ }
64
+ return serialized;
65
+ }
66
+ function getFieldRefField(value) {
67
+ return typeof value === 'string' ? value : value === null || value === void 0 ? void 0 : value.field;
68
+ }
69
+ function getFieldRefLabel(value) {
70
+ return typeof value === 'string' ? value : value === null || value === void 0 ? void 0 : value.label;
71
+ }
39
72
  function normalizeDashboardWidgetTarget(value) {
40
73
  switch (value) {
41
74
  case 'empty':
@@ -49,46 +82,79 @@ function normalizeDashboardWidgetTarget(value) {
49
82
  return undefined;
50
83
  }
51
84
  }
52
- function normalizeKpiCardConfig(value) {
53
- const config = isRecord(value.kpi_card) ? Object.assign({}, value.kpi_card) : {};
54
- if (typeof value.valueField === 'string' && config.value_field === undefined) {
55
- config.value_field = value.valueField;
85
+ function normalizeWidgetLayoutConfig(value) {
86
+ if (value.min_width !== undefined) {
87
+ value.minWidth = value.min_width;
88
+ }
89
+ if (value.max_width !== undefined) {
90
+ value.maxWidth = value.max_width;
56
91
  }
57
- if (typeof value.labelField === 'string' && config.label_field === undefined) {
58
- config.label_field = value.labelField;
92
+ }
93
+ function normalizeQueryConfig(value) {
94
+ if (!isRecord(value)) {
95
+ return value;
59
96
  }
60
- if (typeof value.prefix === 'string' && config.prefix === undefined) {
61
- config.prefix = value.prefix;
97
+ if (Array.isArray(value.steps)) {
98
+ return {
99
+ steps: value.steps.map((step) => normalizeFunnelQueryStep(step)),
100
+ };
62
101
  }
63
- if (typeof value.suffix === 'string' && config.suffix === undefined) {
64
- config.suffix = value.suffix;
102
+ return Object.assign(Object.assign(Object.assign(Object.assign({}, value), (Array.isArray(value.group_by) ? { groupBy: value.group_by } : {})), (Array.isArray(value.order_by) ? { orderBy: value.order_by } : {})), (value.time_series !== undefined ? { timeSeries: value.time_series } : {}));
103
+ }
104
+ function normalizeFunnelQueryStep(value) {
105
+ if (!isRecord(value)) {
106
+ return value;
65
107
  }
66
- return Object.keys(config).length ? config : value.kpi_card;
108
+ return Object.assign(Object.assign({}, value), (typeof value.resource_id === 'string' ? { resource: value.resource_id } : {}));
67
109
  }
68
- function normalizeGaugeCardConfig(value) {
69
- const config = isRecord(value.gauge_card) ? Object.assign({}, value.gauge_card) : {};
70
- if (typeof value.valueField === 'string' && config.value_field === undefined) {
71
- config.value_field = value.valueField;
110
+ function normalizeTableConfig(value) {
111
+ if (!isRecord(value)) {
112
+ return value;
72
113
  }
73
- if (value.min !== undefined && config.min === undefined) {
74
- config.min = value.min;
114
+ return Object.assign(Object.assign({}, value), (value.page_size !== undefined ? { pageSize: value.page_size } : {}));
115
+ }
116
+ function normalizeCardConfig(value) {
117
+ if (!isRecord(value)) {
118
+ return value;
75
119
  }
76
- if (value.max !== undefined && config.max === undefined) {
77
- config.max = value.max;
120
+ const normalized = Object.assign({}, value);
121
+ if (isRecord(normalized.progress)) {
122
+ normalized.progress = Object.assign(Object.assign(Object.assign(Object.assign({}, normalized.progress), (normalized.progress.value_field !== undefined ? { valueField: normalized.progress.value_field } : {})), (normalized.progress.target_value !== undefined ? { targetValue: normalized.progress.target_value } : {})), (normalized.progress.target_field !== undefined ? { targetField: normalized.progress.target_field } : {}));
78
123
  }
79
- if (typeof value.minField === 'string' && config.min_field === undefined) {
80
- config.min_field = value.minField;
124
+ if (isRecord(normalized.comparison)) {
125
+ normalized.comparison = Object.assign(Object.assign({}, normalized.comparison), (normalized.comparison.positive_is_good !== undefined ? { positiveIsGood: normalized.comparison.positive_is_good } : {}));
81
126
  }
82
- if (typeof value.maxField === 'string' && config.max_field === undefined) {
83
- config.max_field = value.maxField;
127
+ return normalized;
128
+ }
129
+ function normalizePivotConfig(value) {
130
+ return value;
131
+ }
132
+ function serializeQueryConfigForEditor(value) {
133
+ if ('steps' in value) {
134
+ return {
135
+ steps: value.steps.map((step) => (Object.assign(Object.assign({}, step), { resource_id: step.resource, resource: undefined }))).map((step) => removeUndefinedFields(step)),
136
+ };
84
137
  }
85
- if (typeof value.suffix === 'string' && config.suffix === undefined) {
86
- config.suffix = value.suffix;
138
+ return removeUndefinedFields(Object.assign(Object.assign({}, value), { group_by: value.groupBy, groupBy: undefined, order_by: value.orderBy, orderBy: undefined, time_series: value.timeSeries, timeSeries: undefined }));
139
+ }
140
+ function serializeTableConfigForEditor(value) {
141
+ return removeUndefinedFields(Object.assign(Object.assign({}, value), { page_size: value.pageSize, pageSize: undefined }));
142
+ }
143
+ function serializeCardConfigForEditor(value) {
144
+ const serialized = Object.assign({}, value);
145
+ if (isRecord(serialized.progress)) {
146
+ serialized.progress = removeUndefinedFields(Object.assign(Object.assign({}, serialized.progress), { value_field: serialized.progress.valueField, valueField: undefined, target_value: serialized.progress.targetValue, targetValue: undefined, target_field: serialized.progress.targetField, targetField: undefined }));
87
147
  }
88
- if (typeof value.color === 'string' && config.color === undefined) {
89
- config.color = value.color;
148
+ if (isRecord(serialized.comparison)) {
149
+ serialized.comparison = removeUndefinedFields(Object.assign(Object.assign({}, serialized.comparison), { positive_is_good: serialized.comparison.positiveIsGood, positiveIsGood: undefined }));
90
150
  }
91
- return Object.keys(config).length ? config : value.gauge_card;
151
+ return removeUndefinedFields(serialized);
152
+ }
153
+ function serializePivotConfigForEditor(value) {
154
+ return value;
155
+ }
156
+ function removeUndefinedFields(value) {
157
+ return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
92
158
  }
93
159
  function isRecord(value) {
94
160
  return typeof value === 'object' && value !== null;