@adminforth/dashboard 1.2.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.
- package/README.md +47 -39
- package/custom/composables/useElementSize.ts +17 -2
- package/custom/model/dashboard.types.ts +327 -234
- package/custom/skills/adminforth-dashboard/SKILL.md +6 -2
- package/custom/widgets/chart/ChartWidget.vue +23 -55
- 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/composables/useElementSize.js +14 -2
- package/dist/custom/composables/useElementSize.ts +17 -2
- package/dist/custom/model/dashboard.types.d.ts +178 -61
- package/dist/custom/model/dashboard.types.js +67 -92
- package/dist/custom/model/dashboard.types.ts +327 -234
- package/dist/custom/queries/useDashboardConfig.d.ts +832 -66
- package/dist/custom/queries/useWidgetData.d.ts +828 -62
- package/dist/custom/skills/adminforth-dashboard/SKILL.md +6 -2
- package/dist/custom/widgets/chart/ChartWidget.vue +23 -55
- 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/widgets.js +5 -2
- package/dist/schema/api.d.ts +2680 -736
- package/dist/schema/widget.d.ts +1588 -476
- package/dist/schema/widget.js +205 -139
- package/dist/services/widgetConfigValidator.js +16 -40
- package/dist/services/widgetDataService.js +359 -82
- package/endpoint/dashboard.ts +1 -1
- package/endpoint/widgets.ts +5 -2
- package/package.json +1 -1
- package/schema/widget.ts +222 -139
- package/services/widgetConfigValidator.ts +29 -53
- package/services/widgetDataService.ts +484 -100
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { computed, watch } from 'vue'
|
|
3
3
|
import { useWidgetData } from '../../queries/useWidgetData.js'
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
getFieldRefField,
|
|
6
6
|
} from '../../model/dashboard.types.js'
|
|
7
7
|
import type { DashboardWidgetConfig, DashboardWidgetData } from '../../model/dashboard.types.js'
|
|
8
8
|
import { formatChartLabel, formatChartValue, toFiniteNumber } from '../chart/chart.utils.js'
|
|
@@ -29,16 +29,17 @@ watch(
|
|
|
29
29
|
{ deep: true },
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
-
const pivotConfig = computed(() =>
|
|
32
|
+
const pivotConfig = computed(() => props.widget.target === 'pivot_table' ? props.widget.pivot : undefined)
|
|
33
33
|
const widgetData = computed(() => data.value?.data as DashboardWidgetData | null)
|
|
34
34
|
const rows = computed(() => widgetData.value?.rows ?? [])
|
|
35
35
|
const columns = computed(() => widgetData.value?.columns ?? [])
|
|
36
36
|
const isAggregateData = computed(() => widgetData.value?.kind === 'aggregate')
|
|
37
|
-
const shouldRenderAggregateMatrix = computed(() => isAggregateData.value && !pivotConfig.value?.
|
|
38
|
-
const rowField = computed(() => pivotConfig.value?.
|
|
39
|
-
const columnField = computed(() => pivotConfig.value?.
|
|
40
|
-
const
|
|
41
|
-
const
|
|
37
|
+
const shouldRenderAggregateMatrix = computed(() => isAggregateData.value && !pivotConfig.value?.columns?.length)
|
|
38
|
+
const rowField = computed(() => getFieldRefField(pivotConfig.value?.rows[0]) || columns.value[0])
|
|
39
|
+
const columnField = computed(() => getFieldRefField(pivotConfig.value?.columns?.[0]) || columns.value[1])
|
|
40
|
+
const valueConfig = computed(() => pivotConfig.value?.values[0])
|
|
41
|
+
const valueField = computed(() => valueConfig.value?.field || columns.value[2] || columns.value[1])
|
|
42
|
+
const aggregation = computed(() => valueConfig.value?.aggregation || (valueField.value ? 'sum' : 'count'))
|
|
42
43
|
const pivotColumnLabels = computed(() => {
|
|
43
44
|
if (shouldRenderAggregateMatrix.value) {
|
|
44
45
|
return columns.value.filter((column) => column !== rowField.value)
|
|
@@ -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
|
|
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?:
|
|
120
|
+
columns?: FieldRef[]
|
|
120
121
|
pagination?: boolean
|
|
121
122
|
pageSize?: number
|
|
122
123
|
}
|
|
@@ -168,7 +169,11 @@ const tableData = computed(() => {
|
|
|
168
169
|
|
|
169
170
|
const columns = computed(() => {
|
|
170
171
|
const configuredColumns = tableConfig.value?.columns
|
|
171
|
-
|
|
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
24
|
-
|
|
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
|
|
26
|
+
export type WidgetBaseConfig = {
|
|
53
27
|
id: string;
|
|
54
28
|
group_id: string;
|
|
55
29
|
label?: string;
|
|
@@ -59,14 +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
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;
|
|
70
203
|
export type DashboardWidgetTableData = {
|
|
71
204
|
kind?: 'table';
|
|
72
205
|
columns: string[];
|
|
@@ -83,32 +216,16 @@ export type DashboardWidgetAggregateData = {
|
|
|
83
216
|
columns: string[];
|
|
84
217
|
rows: Record<string, unknown>[];
|
|
85
218
|
values?: Record<string, unknown>;
|
|
219
|
+
pagination?: {
|
|
220
|
+
page: number;
|
|
221
|
+
pageSize: number;
|
|
222
|
+
total: number;
|
|
223
|
+
totalPages: number;
|
|
224
|
+
};
|
|
86
225
|
};
|
|
87
226
|
export type DashboardWidgetData = DashboardWidgetTableData | DashboardWidgetAggregateData;
|
|
88
|
-
export type NormalizedKpiCardWidgetConfig = {
|
|
89
|
-
valueField?: string;
|
|
90
|
-
labelField?: string;
|
|
91
|
-
prefix?: string;
|
|
92
|
-
suffix?: string;
|
|
93
|
-
};
|
|
94
|
-
export type NormalizedGaugeCardWidgetConfig = {
|
|
95
|
-
valueField?: string;
|
|
96
|
-
min?: number | string;
|
|
97
|
-
max?: number | string;
|
|
98
|
-
minField?: string;
|
|
99
|
-
maxField?: string;
|
|
100
|
-
suffix?: string;
|
|
101
|
-
color?: string;
|
|
102
|
-
};
|
|
103
|
-
export type NormalizedPivotTableWidgetConfig = {
|
|
104
|
-
rowField?: string;
|
|
105
|
-
columnField?: string;
|
|
106
|
-
valueField?: string;
|
|
107
|
-
aggregation?: 'count' | 'sum';
|
|
108
|
-
};
|
|
109
227
|
export declare function normalizeDashboardConfig(config: unknown): DashboardConfig;
|
|
110
228
|
export declare function normalizeDashboardWidgetConfig(config: unknown): unknown;
|
|
111
229
|
export declare function serializeDashboardWidgetConfigForEditor(widget: DashboardWidgetConfig): Record<string, unknown>;
|
|
112
|
-
export declare function
|
|
113
|
-
export declare function
|
|
114
|
-
export declare function normalizePivotTableWidgetConfig(value: unknown): NormalizedPivotTableWidgetConfig | undefined;
|
|
230
|
+
export declare function getFieldRefField(value: FieldRef | undefined): string | undefined;
|
|
231
|
+
export declare function getFieldRefLabel(value: FieldRef | undefined): string | undefined;
|
|
@@ -3,9 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.normalizeDashboardConfig = normalizeDashboardConfig;
|
|
4
4
|
exports.normalizeDashboardWidgetConfig = normalizeDashboardWidgetConfig;
|
|
5
5
|
exports.serializeDashboardWidgetConfigForEditor = serializeDashboardWidgetConfigForEditor;
|
|
6
|
-
exports.
|
|
7
|
-
exports.
|
|
8
|
-
exports.normalizePivotTableWidgetConfig = normalizePivotTableWidgetConfig;
|
|
6
|
+
exports.getFieldRefField = getFieldRefField;
|
|
7
|
+
exports.getFieldRefLabel = getFieldRefLabel;
|
|
9
8
|
function normalizeDashboardConfig(config) {
|
|
10
9
|
const value = isRecord(config) ? config : {};
|
|
11
10
|
return {
|
|
@@ -22,11 +21,17 @@ function normalizeDashboardWidgetConfig(config) {
|
|
|
22
21
|
}
|
|
23
22
|
const normalized = Object.assign({}, config);
|
|
24
23
|
normalizeWidgetLayoutConfig(normalized);
|
|
24
|
+
if (normalized.query !== undefined) {
|
|
25
|
+
normalized.query = normalizeQueryConfig(normalized.query);
|
|
26
|
+
}
|
|
25
27
|
if (normalized.table !== undefined) {
|
|
26
28
|
normalized.table = normalizeTableConfig(normalized.table);
|
|
27
29
|
}
|
|
28
|
-
if (normalized.
|
|
29
|
-
normalized.
|
|
30
|
+
if (normalized.card !== undefined) {
|
|
31
|
+
normalized.card = normalizeCardConfig(normalized.card);
|
|
32
|
+
}
|
|
33
|
+
if (normalized.pivot !== undefined) {
|
|
34
|
+
normalized.pivot = normalizePivotConfig(normalized.pivot);
|
|
30
35
|
}
|
|
31
36
|
const target = normalizeDashboardWidgetTarget(normalized.target);
|
|
32
37
|
if (target !== undefined) {
|
|
@@ -44,50 +49,25 @@ function serializeDashboardWidgetConfigForEditor(widget) {
|
|
|
44
49
|
serialized.max_width = widget.maxWidth;
|
|
45
50
|
delete serialized.maxWidth;
|
|
46
51
|
}
|
|
47
|
-
if (
|
|
52
|
+
if ('query' in widget) {
|
|
53
|
+
serialized.query = serializeQueryConfigForEditor(widget.query);
|
|
54
|
+
}
|
|
55
|
+
if ('table' in widget && widget.table !== undefined) {
|
|
48
56
|
serialized.table = serializeTableConfigForEditor(widget.table);
|
|
49
57
|
}
|
|
50
|
-
if (widget.
|
|
51
|
-
serialized.
|
|
52
|
-
|
|
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);
|
|
53
63
|
}
|
|
54
64
|
return serialized;
|
|
55
65
|
}
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const valueField = getStringField(config, 'value_field');
|
|
62
|
-
const labelField = getStringField(config, 'label_field');
|
|
63
|
-
const prefix = getStringField(config, 'prefix');
|
|
64
|
-
const suffix = getStringField(config, 'suffix');
|
|
65
|
-
return Object.assign(Object.assign(Object.assign(Object.assign({}, (valueField !== undefined ? { valueField } : {})), (labelField !== undefined ? { labelField } : {})), (prefix !== undefined ? { prefix } : {})), (suffix !== undefined ? { suffix } : {}));
|
|
66
|
-
}
|
|
67
|
-
function normalizeGaugeCardWidgetConfig(value) {
|
|
68
|
-
const config = asWidgetConfigRecord(value);
|
|
69
|
-
if (!config) {
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
const valueField = getStringField(config, 'value_field');
|
|
73
|
-
const minField = getStringField(config, 'min_field');
|
|
74
|
-
const maxField = getStringField(config, 'max_field');
|
|
75
|
-
const suffix = getStringField(config, 'suffix');
|
|
76
|
-
const color = getStringField(config, 'color');
|
|
77
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (valueField !== undefined ? { valueField } : {})), (config.min !== undefined ? { min: config.min } : {})), (config.max !== undefined ? { max: config.max } : {})), (minField !== undefined ? { minField } : {})), (maxField !== undefined ? { maxField } : {})), (suffix !== undefined ? { suffix } : {})), (color !== undefined ? { color } : {}));
|
|
78
|
-
}
|
|
79
|
-
function normalizePivotTableWidgetConfig(value) {
|
|
80
|
-
const config = asWidgetConfigRecord(value);
|
|
81
|
-
if (!config) {
|
|
82
|
-
return undefined;
|
|
83
|
-
}
|
|
84
|
-
const rowField = getStringField(config, 'row_field');
|
|
85
|
-
const columnField = getStringField(config, 'column_field');
|
|
86
|
-
const valueField = getStringField(config, 'value_field');
|
|
87
|
-
const aggregation = config.aggregation === 'count' || config.aggregation === 'sum'
|
|
88
|
-
? config.aggregation
|
|
89
|
-
: undefined;
|
|
90
|
-
return Object.assign(Object.assign(Object.assign(Object.assign({}, (rowField !== undefined ? { rowField } : {})), (columnField !== undefined ? { columnField } : {})), (valueField !== undefined ? { valueField } : {})), (aggregation !== undefined ? { aggregation } : {}));
|
|
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;
|
|
91
71
|
}
|
|
92
72
|
function normalizeDashboardWidgetTarget(value) {
|
|
93
73
|
switch (value) {
|
|
@@ -110,76 +90,71 @@ function normalizeWidgetLayoutConfig(value) {
|
|
|
110
90
|
value.maxWidth = value.max_width;
|
|
111
91
|
}
|
|
112
92
|
}
|
|
113
|
-
function
|
|
93
|
+
function normalizeQueryConfig(value) {
|
|
114
94
|
if (!isRecord(value)) {
|
|
115
95
|
return value;
|
|
116
96
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
97
|
+
if (Array.isArray(value.steps)) {
|
|
98
|
+
return {
|
|
99
|
+
steps: value.steps.map((step) => normalizeFunnelQueryStep(step)),
|
|
100
|
+
};
|
|
120
101
|
}
|
|
121
|
-
return
|
|
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 } : {}));
|
|
122
103
|
}
|
|
123
|
-
function
|
|
124
|
-
if (!isRecord(value)
|
|
104
|
+
function normalizeFunnelQueryStep(value) {
|
|
105
|
+
if (!isRecord(value)) {
|
|
125
106
|
return value;
|
|
126
107
|
}
|
|
127
|
-
|
|
128
|
-
? value.resource_id
|
|
129
|
-
: undefined;
|
|
130
|
-
if (value.type === 'resource') {
|
|
131
|
-
return Object.assign(Object.assign(Object.assign(Object.assign({ type: 'resource' }, (resourceId !== undefined ? { resourceId } : {})), (value.columns !== undefined ? { columns: value.columns } : {})), (value.filters !== undefined ? { filters: value.filters } : {})), (value.sort !== undefined ? { sort: value.sort } : {}));
|
|
132
|
-
}
|
|
133
|
-
if (value.type === 'aggregate') {
|
|
134
|
-
const groupBy = normalizeGroupByRule(value.group_by);
|
|
135
|
-
return Object.assign(Object.assign(Object.assign(Object.assign({ type: 'aggregate' }, (resourceId !== undefined ? { resourceId } : {})), (value.aggregations !== undefined ? { aggregations: value.aggregations } : {})), (groupBy !== undefined ? { groupBy } : {})), (value.filters !== undefined ? { filters: value.filters } : {}));
|
|
136
|
-
}
|
|
137
|
-
return value;
|
|
108
|
+
return Object.assign(Object.assign({}, value), (typeof value.resource_id === 'string' ? { resource: value.resource_id } : {}));
|
|
138
109
|
}
|
|
139
|
-
function
|
|
140
|
-
if (!isRecord(value)
|
|
110
|
+
function normalizeTableConfig(value) {
|
|
111
|
+
if (!isRecord(value)) {
|
|
141
112
|
return value;
|
|
142
113
|
}
|
|
143
|
-
|
|
144
|
-
return Object.assign({ type: 'field' }, (value.field !== undefined ? { field: value.field } : {}));
|
|
145
|
-
}
|
|
146
|
-
if (value.type === 'date_trunc') {
|
|
147
|
-
return Object.assign(Object.assign(Object.assign({ type: 'date_trunc' }, (value.field !== undefined ? { field: value.field } : {})), (value.truncation !== undefined ? { truncation: value.truncation } : {})), (value.timezone !== undefined ? { timezone: value.timezone } : {}));
|
|
148
|
-
}
|
|
149
|
-
return value;
|
|
114
|
+
return Object.assign(Object.assign({}, value), (value.page_size !== undefined ? { pageSize: value.page_size } : {}));
|
|
150
115
|
}
|
|
151
|
-
function
|
|
116
|
+
function normalizeCardConfig(value) {
|
|
152
117
|
if (!isRecord(value)) {
|
|
153
118
|
return value;
|
|
154
119
|
}
|
|
155
|
-
const
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
delete serialized.pageSize;
|
|
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 } : {}));
|
|
159
123
|
}
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
function serializeWidgetDataSourceForEditor(value) {
|
|
163
|
-
if (value.type === 'resource') {
|
|
164
|
-
return Object.assign(Object.assign(Object.assign({ type: 'resource', resource_id: value.resourceId }, (value.columns !== undefined ? { columns: value.columns } : {})), (value.filters !== undefined ? { filters: value.filters } : {})), (value.sort !== undefined ? { sort: value.sort } : {}));
|
|
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 } : {}));
|
|
165
126
|
}
|
|
166
|
-
return
|
|
127
|
+
return normalized;
|
|
167
128
|
}
|
|
168
|
-
function
|
|
169
|
-
|
|
129
|
+
function normalizePivotConfig(value) {
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
132
|
+
function serializeQueryConfigForEditor(value) {
|
|
133
|
+
if ('steps' in value) {
|
|
170
134
|
return {
|
|
171
|
-
|
|
172
|
-
field: value.field,
|
|
135
|
+
steps: value.steps.map((step) => (Object.assign(Object.assign({}, step), { resource_id: step.resource, resource: undefined }))).map((step) => removeUndefinedFields(step)),
|
|
173
136
|
};
|
|
174
137
|
}
|
|
175
|
-
return Object.assign({
|
|
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 }));
|
|
147
|
+
}
|
|
148
|
+
if (isRecord(serialized.comparison)) {
|
|
149
|
+
serialized.comparison = removeUndefinedFields(Object.assign(Object.assign({}, serialized.comparison), { positive_is_good: serialized.comparison.positiveIsGood, positiveIsGood: undefined }));
|
|
150
|
+
}
|
|
151
|
+
return removeUndefinedFields(serialized);
|
|
176
152
|
}
|
|
177
|
-
function
|
|
178
|
-
return
|
|
153
|
+
function serializePivotConfigForEditor(value) {
|
|
154
|
+
return value;
|
|
179
155
|
}
|
|
180
|
-
function
|
|
181
|
-
|
|
182
|
-
return typeof value === 'string' ? value : undefined;
|
|
156
|
+
function removeUndefinedFields(value) {
|
|
157
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
183
158
|
}
|
|
184
159
|
function isRecord(value) {
|
|
185
160
|
return typeof value === 'object' && value !== null;
|