@adminforth/dashboard 1.2.0 → 1.4.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.
- package/README.md +116 -39
- package/custom/api/dashboardApi.ts +4 -0
- package/custom/composables/useElementSize.ts +17 -2
- package/custom/model/dashboard.types.ts +337 -236
- package/custom/skills/adminforth-dashboard/SKILL.md +113 -2
- package/custom/widgets/chart/ChartWidget.vue +38 -53
- package/custom/widgets/chart/bar/BarChart.vue +20 -12
- package/custom/widgets/chart/chart.types.ts +17 -66
- package/custom/widgets/chart/chart.utils.ts +11 -0
- package/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
- package/custom/widgets/chart/line/LineChart.vue +23 -15
- package/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
- package/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -12
- package/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
- package/custom/widgets/pivot-table/PivotTableWidget.vue +8 -7
- package/custom/widgets/table/TableWidget.vue +8 -3
- package/dist/custom/api/dashboardApi.d.ts +1 -0
- package/dist/custom/api/dashboardApi.js +5 -0
- package/dist/custom/api/dashboardApi.ts +4 -0
- package/dist/custom/composables/useElementSize.js +14 -2
- package/dist/custom/composables/useElementSize.ts +17 -2
- package/dist/custom/model/dashboard.types.d.ts +181 -61
- package/dist/custom/model/dashboard.types.js +82 -93
- package/dist/custom/model/dashboard.types.ts +337 -236
- package/dist/custom/queries/useDashboardConfig.d.ts +852 -66
- package/dist/custom/queries/useWidgetData.d.ts +848 -62
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +113 -2
- package/dist/custom/widgets/chart/ChartWidget.vue +38 -53
- package/dist/custom/widgets/chart/bar/BarChart.vue +20 -12
- package/dist/custom/widgets/chart/chart.types.d.ts +13 -22
- package/dist/custom/widgets/chart/chart.types.js +2 -25
- package/dist/custom/widgets/chart/chart.types.ts +17 -66
- package/dist/custom/widgets/chart/chart.utils.d.ts +1 -0
- package/dist/custom/widgets/chart/chart.utils.js +7 -0
- package/dist/custom/widgets/chart/chart.utils.ts +11 -0
- package/dist/custom/widgets/chart/funnel/FunnelChart.vue +6 -4
- package/dist/custom/widgets/chart/line/LineChart.vue +23 -15
- package/dist/custom/widgets/chart/stacked-bar/StackedBarChart.vue +28 -43
- package/dist/custom/widgets/gauge-card/GaugeCardWidget.vue +7 -12
- package/dist/custom/widgets/kpi-card/KpiCardWidget.vue +6 -8
- package/dist/custom/widgets/pivot-table/PivotTableWidget.vue +8 -7
- package/dist/custom/widgets/table/TableWidget.vue +8 -3
- package/dist/endpoint/dashboard.d.ts +7 -2
- package/dist/endpoint/dashboard.js +45 -1
- package/dist/endpoint/widgets.d.ts +2 -1
- package/dist/endpoint/widgets.js +6 -2
- package/dist/schema/api.d.ts +2773 -736
- package/dist/schema/api.js +5 -0
- package/dist/schema/widget.d.ts +1648 -476
- package/dist/schema/widget.js +208 -139
- package/dist/services/widgetConfigValidator.js +16 -40
- package/dist/services/widgetDataService.d.ts +2 -1
- package/dist/services/widgetDataService.js +389 -82
- package/endpoint/dashboard.ts +77 -4
- package/endpoint/widgets.ts +11 -4
- package/package.json +1 -1
- package/schema/api.ts +6 -0
- package/schema/widget.ts +225 -139
- package/services/widgetConfigValidator.ts +29 -53
- package/services/widgetDataService.ts +522 -100
|
@@ -1,48 +1,13 @@
|
|
|
1
1
|
import type { ChartWidgetConfig } from '../widgets/chart/chart.types.js'
|
|
2
2
|
|
|
3
|
-
export type AggregationOperation = 'sum' | 'count' | 'avg' | 'min' | 'max' | 'median'
|
|
4
|
-
|
|
5
|
-
export type AggregationRule = {
|
|
6
|
-
operation: AggregationOperation
|
|
7
|
-
field?: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export type GroupByRule =
|
|
11
|
-
| {
|
|
12
|
-
type: 'field'
|
|
13
|
-
field: string
|
|
14
|
-
}
|
|
15
|
-
| {
|
|
16
|
-
type: 'date_trunc'
|
|
17
|
-
field: string
|
|
18
|
-
truncation: 'day' | 'week' | 'month' | 'year'
|
|
19
|
-
timezone?: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type ResourceWidgetDataSource = {
|
|
23
|
-
type: 'resource'
|
|
24
|
-
resourceId: string
|
|
25
|
-
columns?: string[]
|
|
26
|
-
sort?: unknown
|
|
27
|
-
filters?: unknown
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export type AggregateWidgetDataSource = {
|
|
31
|
-
type: 'aggregate'
|
|
32
|
-
resourceId: string
|
|
33
|
-
aggregations: Record<string, AggregationRule>
|
|
34
|
-
groupBy?: GroupByRule
|
|
35
|
-
filters?: unknown
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export type WidgetDataSource = ResourceWidgetDataSource | AggregateWidgetDataSource
|
|
39
|
-
|
|
40
3
|
export type DashboardConfig = {
|
|
41
4
|
version: number
|
|
42
5
|
groups: DashboardGroupConfig[]
|
|
43
6
|
widgets: DashboardWidgetConfig[]
|
|
44
7
|
}
|
|
45
8
|
|
|
9
|
+
export type DashboardVariables = Record<string, unknown>
|
|
10
|
+
|
|
46
11
|
export type DashboardGroupConfig = {
|
|
47
12
|
id: string
|
|
48
13
|
label: string
|
|
@@ -50,18 +15,19 @@ export type DashboardGroupConfig = {
|
|
|
50
15
|
}
|
|
51
16
|
|
|
52
17
|
export type DashboardGroupMoveDirection = 'up' | 'down'
|
|
53
|
-
|
|
54
18
|
export type DashboardWidgetMoveDirection = 'up' | 'down'
|
|
55
|
-
|
|
56
|
-
export type DashboardWidgetTarget =
|
|
57
|
-
| 'empty'
|
|
58
|
-
| 'table'
|
|
59
|
-
| 'chart'
|
|
60
|
-
| 'kpi_card'
|
|
61
|
-
| 'pivot_table'
|
|
62
|
-
| 'gauge_card'
|
|
63
|
-
|
|
19
|
+
export type DashboardWidgetTarget = 'empty' | 'table' | 'chart' | 'kpi_card' | 'pivot_table' | 'gauge_card'
|
|
64
20
|
export type DashboardWidgetSize = 'small' | 'medium' | 'large' | 'wide' | 'full'
|
|
21
|
+
export type QueryAggregateOperation = 'sum' | 'count' | 'count_distinct' | 'avg' | 'min' | 'max' | 'median'
|
|
22
|
+
export type TimeGrain = 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year'
|
|
23
|
+
export type ValueFormat =
|
|
24
|
+
| 'number'
|
|
25
|
+
| 'compact_number'
|
|
26
|
+
| 'currency'
|
|
27
|
+
| 'percent'
|
|
28
|
+
| 'percent_delta'
|
|
29
|
+
| 'number_delta'
|
|
30
|
+
| 'currency_delta'
|
|
65
31
|
|
|
66
32
|
export type WidgetLayout = {
|
|
67
33
|
size?: DashboardWidgetSize
|
|
@@ -71,25 +37,212 @@ export type WidgetLayout = {
|
|
|
71
37
|
height?: number
|
|
72
38
|
}
|
|
73
39
|
|
|
74
|
-
export type
|
|
40
|
+
export type WidgetBaseConfig = {
|
|
75
41
|
id: string
|
|
76
42
|
group_id: string
|
|
77
43
|
label?: string
|
|
44
|
+
variables?: DashboardVariables
|
|
78
45
|
size?: DashboardWidgetSize
|
|
79
46
|
width?: number
|
|
80
47
|
height?: number
|
|
81
48
|
minWidth?: number
|
|
82
49
|
maxWidth?: number | null
|
|
83
50
|
order: number
|
|
84
|
-
target: DashboardWidgetTarget
|
|
85
|
-
dataSource?: WidgetDataSource
|
|
86
|
-
chart?: ChartWidgetConfig
|
|
87
|
-
table?: unknown
|
|
88
|
-
kpi_card?: unknown
|
|
89
|
-
pivot_table?: unknown
|
|
90
|
-
gauge_card?: unknown
|
|
91
51
|
}
|
|
92
52
|
|
|
53
|
+
export type FilterExpression =
|
|
54
|
+
| { and: FilterExpression[] }
|
|
55
|
+
| { or: FilterExpression[] }
|
|
56
|
+
| Array<FilterExpression>
|
|
57
|
+
| {
|
|
58
|
+
field: string
|
|
59
|
+
eq?: unknown
|
|
60
|
+
neq?: unknown
|
|
61
|
+
gt?: unknown
|
|
62
|
+
gte?: unknown
|
|
63
|
+
lt?: unknown
|
|
64
|
+
lte?: unknown
|
|
65
|
+
in?: unknown[]
|
|
66
|
+
not_in?: unknown[]
|
|
67
|
+
like?: unknown
|
|
68
|
+
ilike?: unknown
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type QueryFieldSelectItem = {
|
|
72
|
+
field: string
|
|
73
|
+
as?: string
|
|
74
|
+
grain?: TimeGrain
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type QueryAggregateSelectItem = {
|
|
78
|
+
agg: QueryAggregateOperation
|
|
79
|
+
field?: string
|
|
80
|
+
as: string
|
|
81
|
+
filters?: FilterExpression
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type QueryCalcSelectItem = {
|
|
85
|
+
calc: string
|
|
86
|
+
as: string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type QuerySelectItem = QueryFieldSelectItem | QueryAggregateSelectItem | QueryCalcSelectItem
|
|
90
|
+
|
|
91
|
+
export type QueryGroupByItem =
|
|
92
|
+
| string
|
|
93
|
+
| {
|
|
94
|
+
field: string
|
|
95
|
+
as?: string
|
|
96
|
+
grain?: TimeGrain
|
|
97
|
+
timezone?: string
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type QueryOrderByItem = {
|
|
101
|
+
field: string
|
|
102
|
+
direction?: 'asc' | 'desc'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type QueryConfig = {
|
|
106
|
+
resource: string
|
|
107
|
+
select?: QuerySelectItem[]
|
|
108
|
+
filters?: FilterExpression
|
|
109
|
+
groupBy?: QueryGroupByItem[]
|
|
110
|
+
orderBy?: QueryOrderByItem[]
|
|
111
|
+
limit?: number
|
|
112
|
+
offset?: number
|
|
113
|
+
timeSeries?: {
|
|
114
|
+
field: string
|
|
115
|
+
grain: TimeGrain
|
|
116
|
+
timezone?: string
|
|
117
|
+
}
|
|
118
|
+
period?: {
|
|
119
|
+
field: string
|
|
120
|
+
gte?: unknown
|
|
121
|
+
lt?: unknown
|
|
122
|
+
}
|
|
123
|
+
bucket?: {
|
|
124
|
+
field: string
|
|
125
|
+
buckets: Array<{ label: string, min?: number, max?: number }>
|
|
126
|
+
}
|
|
127
|
+
calcs?: QueryCalcSelectItem[]
|
|
128
|
+
formatting?: Record<string, unknown>
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export type FunnelQueryConfig = {
|
|
132
|
+
steps: FunnelQueryStep[]
|
|
133
|
+
calcs?: QueryCalcSelectItem[]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export type FunnelQueryStep = {
|
|
137
|
+
name: string
|
|
138
|
+
resource: string
|
|
139
|
+
metric: QueryAggregateSelectItem
|
|
140
|
+
filters?: FilterExpression
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export type FieldRef = string | {
|
|
144
|
+
field: string
|
|
145
|
+
label?: string
|
|
146
|
+
format?: ValueFormat
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export type TableViewConfig = {
|
|
150
|
+
columns?: FieldRef[]
|
|
151
|
+
pagination?: boolean
|
|
152
|
+
pageSize?: number
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export type KpiCardViewConfig = {
|
|
156
|
+
title?: string
|
|
157
|
+
value: {
|
|
158
|
+
field: string
|
|
159
|
+
format?: ValueFormat
|
|
160
|
+
prefix?: string
|
|
161
|
+
suffix?: string
|
|
162
|
+
}
|
|
163
|
+
subtitle?: {
|
|
164
|
+
text?: string
|
|
165
|
+
field?: string
|
|
166
|
+
}
|
|
167
|
+
comparison?: unknown
|
|
168
|
+
sparkline?: unknown
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export type GaugeCardViewConfig = {
|
|
172
|
+
title?: string
|
|
173
|
+
value: {
|
|
174
|
+
field: string
|
|
175
|
+
format?: ValueFormat
|
|
176
|
+
prefix?: string
|
|
177
|
+
suffix?: string
|
|
178
|
+
}
|
|
179
|
+
target?: {
|
|
180
|
+
value?: number
|
|
181
|
+
field?: string
|
|
182
|
+
label?: string
|
|
183
|
+
}
|
|
184
|
+
progress?: {
|
|
185
|
+
valueField: string
|
|
186
|
+
targetValue?: number
|
|
187
|
+
targetField?: string
|
|
188
|
+
format?: ValueFormat
|
|
189
|
+
}
|
|
190
|
+
color?: string
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export type PivotTableViewConfig = {
|
|
194
|
+
rows: FieldRef[]
|
|
195
|
+
columns?: FieldRef[]
|
|
196
|
+
values: Array<{
|
|
197
|
+
field: string
|
|
198
|
+
label?: string
|
|
199
|
+
format?: ValueFormat
|
|
200
|
+
aggregation?: 'sum' | 'count' | 'avg' | 'min' | 'max'
|
|
201
|
+
}>
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export type EmptyWidgetConfig = WidgetBaseConfig & {
|
|
205
|
+
target: 'empty'
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export type TableWidgetConfig = WidgetBaseConfig & {
|
|
209
|
+
target: 'table'
|
|
210
|
+
table?: TableViewConfig
|
|
211
|
+
query: QueryConfig
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export type ChartDashboardWidgetConfig = WidgetBaseConfig & {
|
|
215
|
+
target: 'chart'
|
|
216
|
+
chart: ChartWidgetConfig
|
|
217
|
+
query: QueryConfig | FunnelQueryConfig
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export type KpiCardWidgetConfig = WidgetBaseConfig & {
|
|
221
|
+
target: 'kpi_card'
|
|
222
|
+
card: KpiCardViewConfig
|
|
223
|
+
query: QueryConfig
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export type GaugeCardWidgetConfig = WidgetBaseConfig & {
|
|
227
|
+
target: 'gauge_card'
|
|
228
|
+
card: GaugeCardViewConfig
|
|
229
|
+
query: QueryConfig
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export type PivotTableWidgetConfig = WidgetBaseConfig & {
|
|
233
|
+
target: 'pivot_table'
|
|
234
|
+
pivot: PivotTableViewConfig
|
|
235
|
+
query: QueryConfig
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export type DashboardWidgetConfig =
|
|
239
|
+
| EmptyWidgetConfig
|
|
240
|
+
| TableWidgetConfig
|
|
241
|
+
| ChartDashboardWidgetConfig
|
|
242
|
+
| KpiCardWidgetConfig
|
|
243
|
+
| GaugeCardWidgetConfig
|
|
244
|
+
| PivotTableWidgetConfig
|
|
245
|
+
|
|
93
246
|
export type DashboardWidgetTableData = {
|
|
94
247
|
kind?: 'table'
|
|
95
248
|
columns: string[]
|
|
@@ -107,34 +260,16 @@ export type DashboardWidgetAggregateData = {
|
|
|
107
260
|
columns: string[]
|
|
108
261
|
rows: Record<string, unknown>[]
|
|
109
262
|
values?: Record<string, unknown>
|
|
263
|
+
pagination?: {
|
|
264
|
+
page: number
|
|
265
|
+
pageSize: number
|
|
266
|
+
total: number
|
|
267
|
+
totalPages: number
|
|
268
|
+
}
|
|
110
269
|
}
|
|
111
270
|
|
|
112
271
|
export type DashboardWidgetData = DashboardWidgetTableData | DashboardWidgetAggregateData
|
|
113
272
|
|
|
114
|
-
export type NormalizedKpiCardWidgetConfig = {
|
|
115
|
-
valueField?: string
|
|
116
|
-
labelField?: string
|
|
117
|
-
prefix?: string
|
|
118
|
-
suffix?: string
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export type NormalizedGaugeCardWidgetConfig = {
|
|
122
|
-
valueField?: string
|
|
123
|
-
min?: number | string
|
|
124
|
-
max?: number | string
|
|
125
|
-
minField?: string
|
|
126
|
-
maxField?: string
|
|
127
|
-
suffix?: string
|
|
128
|
-
color?: string
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export type NormalizedPivotTableWidgetConfig = {
|
|
132
|
-
rowField?: string
|
|
133
|
-
columnField?: string
|
|
134
|
-
valueField?: string
|
|
135
|
-
aggregation?: 'count' | 'sum'
|
|
136
|
-
}
|
|
137
|
-
|
|
138
273
|
export function normalizeDashboardConfig(config: unknown): DashboardConfig {
|
|
139
274
|
const value = isRecord(config) ? config : {}
|
|
140
275
|
|
|
@@ -155,12 +290,20 @@ export function normalizeDashboardWidgetConfig(config: unknown) {
|
|
|
155
290
|
const normalized: Record<string, unknown> = { ...config }
|
|
156
291
|
normalizeWidgetLayoutConfig(normalized)
|
|
157
292
|
|
|
293
|
+
if (normalized.query !== undefined) {
|
|
294
|
+
normalized.query = normalizeQueryConfig(normalized.query)
|
|
295
|
+
}
|
|
296
|
+
|
|
158
297
|
if (normalized.table !== undefined) {
|
|
159
298
|
normalized.table = normalizeTableConfig(normalized.table)
|
|
160
299
|
}
|
|
161
300
|
|
|
162
|
-
if (normalized.
|
|
163
|
-
normalized.
|
|
301
|
+
if (normalized.card !== undefined) {
|
|
302
|
+
normalized.card = normalizeCardConfig(normalized.card)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (normalized.pivot !== undefined) {
|
|
306
|
+
normalized.pivot = normalizePivotConfig(normalized.pivot)
|
|
164
307
|
}
|
|
165
308
|
|
|
166
309
|
const target = normalizeDashboardWidgetTarget(normalized.target)
|
|
@@ -185,82 +328,31 @@ export function serializeDashboardWidgetConfigForEditor(widget: DashboardWidgetC
|
|
|
185
328
|
delete serialized.maxWidth
|
|
186
329
|
}
|
|
187
330
|
|
|
188
|
-
if (
|
|
189
|
-
serialized.
|
|
331
|
+
if ('query' in widget) {
|
|
332
|
+
serialized.query = serializeQueryConfigForEditor(widget.query)
|
|
190
333
|
}
|
|
191
334
|
|
|
192
|
-
if (widget.
|
|
193
|
-
serialized.
|
|
194
|
-
delete serialized.dataSource
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return serialized
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export function normalizeKpiCardWidgetConfig(value: unknown): NormalizedKpiCardWidgetConfig | undefined {
|
|
201
|
-
const config = asWidgetConfigRecord(value)
|
|
202
|
-
|
|
203
|
-
if (!config) {
|
|
204
|
-
return undefined
|
|
335
|
+
if ('table' in widget && widget.table !== undefined) {
|
|
336
|
+
serialized.table = serializeTableConfigForEditor(widget.table)
|
|
205
337
|
}
|
|
206
338
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const prefix = getStringField(config, 'prefix')
|
|
210
|
-
const suffix = getStringField(config, 'suffix')
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
...(valueField !== undefined ? { valueField } : {}),
|
|
214
|
-
...(labelField !== undefined ? { labelField } : {}),
|
|
215
|
-
...(prefix !== undefined ? { prefix } : {}),
|
|
216
|
-
...(suffix !== undefined ? { suffix } : {}),
|
|
339
|
+
if ('card' in widget && widget.card !== undefined) {
|
|
340
|
+
serialized.card = serializeCardConfigForEditor(widget.card)
|
|
217
341
|
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export function normalizeGaugeCardWidgetConfig(value: unknown): NormalizedGaugeCardWidgetConfig | undefined {
|
|
221
|
-
const config = asWidgetConfigRecord(value)
|
|
222
342
|
|
|
223
|
-
if (
|
|
224
|
-
|
|
343
|
+
if ('pivot' in widget && widget.pivot !== undefined) {
|
|
344
|
+
serialized.pivot = serializePivotConfigForEditor(widget.pivot)
|
|
225
345
|
}
|
|
226
346
|
|
|
227
|
-
|
|
228
|
-
const minField = getStringField(config, 'min_field')
|
|
229
|
-
const maxField = getStringField(config, 'max_field')
|
|
230
|
-
const suffix = getStringField(config, 'suffix')
|
|
231
|
-
const color = getStringField(config, 'color')
|
|
232
|
-
|
|
233
|
-
return {
|
|
234
|
-
...(valueField !== undefined ? { valueField } : {}),
|
|
235
|
-
...(config.min !== undefined ? { min: config.min as number | string } : {}),
|
|
236
|
-
...(config.max !== undefined ? { max: config.max as number | string } : {}),
|
|
237
|
-
...(minField !== undefined ? { minField } : {}),
|
|
238
|
-
...(maxField !== undefined ? { maxField } : {}),
|
|
239
|
-
...(suffix !== undefined ? { suffix } : {}),
|
|
240
|
-
...(color !== undefined ? { color } : {}),
|
|
241
|
-
}
|
|
347
|
+
return serialized
|
|
242
348
|
}
|
|
243
349
|
|
|
244
|
-
export function
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (!config) {
|
|
248
|
-
return undefined
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const rowField = getStringField(config, 'row_field')
|
|
252
|
-
const columnField = getStringField(config, 'column_field')
|
|
253
|
-
const valueField = getStringField(config, 'value_field')
|
|
254
|
-
const aggregation = config.aggregation === 'count' || config.aggregation === 'sum'
|
|
255
|
-
? config.aggregation
|
|
256
|
-
: undefined
|
|
350
|
+
export function getFieldRefField(value: FieldRef | undefined) {
|
|
351
|
+
return typeof value === 'string' ? value : value?.field
|
|
352
|
+
}
|
|
257
353
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
...(columnField !== undefined ? { columnField } : {}),
|
|
261
|
-
...(valueField !== undefined ? { valueField } : {}),
|
|
262
|
-
...(aggregation !== undefined ? { aggregation } : {}),
|
|
263
|
-
}
|
|
354
|
+
export function getFieldRefLabel(value: FieldRef | undefined) {
|
|
355
|
+
return typeof value === 'string' ? value : value?.label
|
|
264
356
|
}
|
|
265
357
|
|
|
266
358
|
function normalizeDashboardWidgetTarget(value: unknown): DashboardWidgetTarget | undefined {
|
|
@@ -287,138 +379,147 @@ function normalizeWidgetLayoutConfig(value: Record<string, unknown>) {
|
|
|
287
379
|
}
|
|
288
380
|
}
|
|
289
381
|
|
|
290
|
-
function
|
|
382
|
+
function normalizeQueryConfig(value: unknown): unknown {
|
|
291
383
|
if (!isRecord(value)) {
|
|
292
384
|
return value
|
|
293
385
|
}
|
|
294
386
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
387
|
+
if (Array.isArray(value.steps)) {
|
|
388
|
+
return removeUndefinedFields({
|
|
389
|
+
steps: value.steps.map((step) => normalizeFunnelQueryStep(step)),
|
|
390
|
+
calcs: Array.isArray(value.calcs) ? value.calcs as QueryCalcSelectItem[] : undefined,
|
|
391
|
+
})
|
|
299
392
|
}
|
|
300
393
|
|
|
301
|
-
return
|
|
394
|
+
return {
|
|
395
|
+
...value,
|
|
396
|
+
...(Array.isArray(value.group_by) ? { groupBy: value.group_by } : {}),
|
|
397
|
+
...(Array.isArray(value.order_by) ? { orderBy: value.order_by } : {}),
|
|
398
|
+
...(value.time_series !== undefined ? { timeSeries: value.time_series } : {}),
|
|
399
|
+
}
|
|
302
400
|
}
|
|
303
401
|
|
|
304
|
-
function
|
|
305
|
-
if (!isRecord(value)
|
|
402
|
+
function normalizeFunnelQueryStep(value: unknown) {
|
|
403
|
+
if (!isRecord(value)) {
|
|
306
404
|
return value
|
|
307
405
|
}
|
|
308
406
|
|
|
309
|
-
const
|
|
310
|
-
? value.resource_id
|
|
311
|
-
: undefined
|
|
407
|
+
const { resource_id, ...rest } = value
|
|
312
408
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
...(value.filters !== undefined ? { filters: value.filters } : {}),
|
|
319
|
-
...(value.sort !== undefined ? { sort: value.sort } : {}),
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
if (value.type === 'aggregate') {
|
|
324
|
-
const groupBy = normalizeGroupByRule(value.group_by)
|
|
409
|
+
return removeUndefinedFields({
|
|
410
|
+
...rest,
|
|
411
|
+
resource: typeof resource_id === 'string' ? resource_id : rest.resource,
|
|
412
|
+
})
|
|
413
|
+
}
|
|
325
414
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
...(value.aggregations !== undefined ? { aggregations: value.aggregations } : {}),
|
|
330
|
-
...(groupBy !== undefined ? { groupBy } : {}),
|
|
331
|
-
...(value.filters !== undefined ? { filters: value.filters } : {}),
|
|
332
|
-
}
|
|
415
|
+
function normalizeTableConfig(value: unknown) {
|
|
416
|
+
if (!isRecord(value)) {
|
|
417
|
+
return value
|
|
333
418
|
}
|
|
334
419
|
|
|
335
|
-
return
|
|
420
|
+
return {
|
|
421
|
+
...value,
|
|
422
|
+
...(value.page_size !== undefined ? { pageSize: value.page_size } : {}),
|
|
423
|
+
}
|
|
336
424
|
}
|
|
337
425
|
|
|
338
|
-
function
|
|
339
|
-
if (!isRecord(value)
|
|
426
|
+
function normalizeCardConfig(value: unknown): unknown {
|
|
427
|
+
if (!isRecord(value)) {
|
|
340
428
|
return value
|
|
341
429
|
}
|
|
342
430
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
431
|
+
const normalized = { ...value }
|
|
432
|
+
|
|
433
|
+
if (isRecord(normalized.progress)) {
|
|
434
|
+
normalized.progress = {
|
|
435
|
+
...normalized.progress,
|
|
436
|
+
...(normalized.progress.value_field !== undefined ? { valueField: normalized.progress.value_field } : {}),
|
|
437
|
+
...(normalized.progress.target_value !== undefined ? { targetValue: normalized.progress.target_value } : {}),
|
|
438
|
+
...(normalized.progress.target_field !== undefined ? { targetField: normalized.progress.target_field } : {}),
|
|
347
439
|
}
|
|
348
440
|
}
|
|
349
441
|
|
|
350
|
-
if (
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
...(
|
|
354
|
-
...(value.truncation !== undefined ? { truncation: value.truncation } : {}),
|
|
355
|
-
...(value.timezone !== undefined ? { timezone: value.timezone } : {}),
|
|
442
|
+
if (isRecord(normalized.comparison)) {
|
|
443
|
+
normalized.comparison = {
|
|
444
|
+
...normalized.comparison,
|
|
445
|
+
...(normalized.comparison.positive_is_good !== undefined ? { positiveIsGood: normalized.comparison.positive_is_good } : {}),
|
|
356
446
|
}
|
|
357
447
|
}
|
|
358
448
|
|
|
359
|
-
return
|
|
449
|
+
return normalized
|
|
360
450
|
}
|
|
361
451
|
|
|
362
|
-
function
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const serialized = { ...value }
|
|
452
|
+
function normalizePivotConfig(value: unknown): unknown {
|
|
453
|
+
return value
|
|
454
|
+
}
|
|
368
455
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
456
|
+
function serializeQueryConfigForEditor(value: QueryConfig | FunnelQueryConfig) {
|
|
457
|
+
if ('steps' in value) {
|
|
458
|
+
return removeUndefinedFields({
|
|
459
|
+
steps: value.steps.map((step) => ({
|
|
460
|
+
...step,
|
|
461
|
+
resource_id: step.resource,
|
|
462
|
+
resource: undefined,
|
|
463
|
+
})).map((step) => removeUndefinedFields(step)),
|
|
464
|
+
calcs: value.calcs,
|
|
465
|
+
})
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return removeUndefinedFields({
|
|
469
|
+
...value,
|
|
470
|
+
group_by: value.groupBy,
|
|
471
|
+
groupBy: undefined,
|
|
472
|
+
order_by: value.orderBy,
|
|
473
|
+
orderBy: undefined,
|
|
474
|
+
time_series: value.timeSeries,
|
|
475
|
+
timeSeries: undefined,
|
|
476
|
+
})
|
|
477
|
+
}
|
|
373
478
|
|
|
374
|
-
|
|
479
|
+
function serializeTableConfigForEditor(value: TableViewConfig) {
|
|
480
|
+
return removeUndefinedFields({
|
|
481
|
+
...value,
|
|
482
|
+
page_size: value.pageSize,
|
|
483
|
+
pageSize: undefined,
|
|
484
|
+
})
|
|
375
485
|
}
|
|
376
486
|
|
|
377
|
-
function
|
|
378
|
-
|
|
379
|
-
return {
|
|
380
|
-
type: 'resource',
|
|
381
|
-
resource_id: value.resourceId,
|
|
382
|
-
...(value.columns !== undefined ? { columns: value.columns } : {}),
|
|
383
|
-
...(value.filters !== undefined ? { filters: value.filters } : {}),
|
|
384
|
-
...(value.sort !== undefined ? { sort: value.sort } : {}),
|
|
385
|
-
}
|
|
386
|
-
}
|
|
487
|
+
function serializeCardConfigForEditor(value: KpiCardViewConfig | GaugeCardViewConfig) {
|
|
488
|
+
const serialized: Record<string, unknown> = { ...value }
|
|
387
489
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
490
|
+
if (isRecord(serialized.progress)) {
|
|
491
|
+
serialized.progress = removeUndefinedFields({
|
|
492
|
+
...serialized.progress,
|
|
493
|
+
value_field: serialized.progress.valueField,
|
|
494
|
+
valueField: undefined,
|
|
495
|
+
target_value: serialized.progress.targetValue,
|
|
496
|
+
targetValue: undefined,
|
|
497
|
+
target_field: serialized.progress.targetField,
|
|
498
|
+
targetField: undefined,
|
|
499
|
+
})
|
|
394
500
|
}
|
|
395
|
-
}
|
|
396
501
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
}
|
|
502
|
+
if (isRecord(serialized.comparison)) {
|
|
503
|
+
serialized.comparison = removeUndefinedFields({
|
|
504
|
+
...serialized.comparison,
|
|
505
|
+
positive_is_good: serialized.comparison.positiveIsGood,
|
|
506
|
+
positiveIsGood: undefined,
|
|
507
|
+
})
|
|
403
508
|
}
|
|
404
509
|
|
|
405
|
-
return
|
|
406
|
-
type: 'date_trunc',
|
|
407
|
-
field: value.field,
|
|
408
|
-
truncation: value.truncation,
|
|
409
|
-
...(value.timezone !== undefined ? { timezone: value.timezone } : {}),
|
|
410
|
-
}
|
|
510
|
+
return removeUndefinedFields(serialized)
|
|
411
511
|
}
|
|
412
512
|
|
|
413
|
-
function
|
|
414
|
-
return
|
|
513
|
+
function serializePivotConfigForEditor(value: PivotTableViewConfig) {
|
|
514
|
+
return value
|
|
415
515
|
}
|
|
416
516
|
|
|
417
|
-
function
|
|
418
|
-
|
|
419
|
-
|
|
517
|
+
function removeUndefinedFields<T extends Record<string, unknown>>(value: T) {
|
|
518
|
+
return Object.fromEntries(
|
|
519
|
+
Object.entries(value).filter(([, item]) => item !== undefined),
|
|
520
|
+
)
|
|
420
521
|
}
|
|
421
522
|
|
|
422
|
-
function isRecord(value: unknown): value is Record<string,
|
|
523
|
+
function isRecord(value: unknown): value is Record<string, any> {
|
|
423
524
|
return typeof value === 'object' && value !== null
|
|
424
525
|
}
|