@mixd-id/web-scaffold 0.1.230406347 → 0.1.230406349
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/package.json +1 -1
- package/src/components/GHeatMaps.vue +25 -7
- package/src/configs/dashboard/bar.js +2 -1
- package/src/utils/preset-selector.mjs +2 -2
- package/src/widgets/Dashboard/BarChart.vue +86 -20
- package/src/widgets/Dashboard/BarChartSetting.vue +6 -2
- package/src/widgets/Dashboard/DatasourcePreview.vue +4 -8
- package/src/widgets/Dashboard/Doughnut.vue +14 -1
- package/src/widgets/Dashboard/DoughnutSetting.vue +7 -4
- package/src/widgets/Dashboard/GHeatMapsSetting.vue +1 -1
- package/src/widgets/Dashboard/Pie.vue +13 -0
- package/src/widgets/Dashboard/PieSetting.vue +1 -1
- package/src/widgets/Dashboard/PolarArea.vue +13 -1
- package/src/widgets/Dashboard/PolarAreaSetting.vue +5 -3
- package/src/widgets/Dashboard/VirtualTableSetting.vue +1 -1
- package/src/widgets/Dashboard.vue +45 -147
- package/src/widgets/PresetBar.vue +4 -136
- package/src/widgets/PresetBarPivot.vue +186 -0
package/package.json
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="$style.comp">
|
|
3
|
-
<div v-if="apiKey" ref="map" class="flex-1"
|
|
3
|
+
<div v-if="apiKey" ref="map" class="flex-1">
|
|
4
|
+
|
|
5
|
+
</div>
|
|
4
6
|
<div v-else class="flex-1 flex items-center justify-center text-text-400">{{ $t('Google maps api required') }}</div>
|
|
7
|
+
|
|
8
|
+
<div class="flex flex-row gap-2 p-1 px-3 pt-2">
|
|
9
|
+
<label class="text-sm text-text-400">Total points: {{ uniqueCount }}</label>
|
|
10
|
+
|
|
11
|
+
</div>
|
|
5
12
|
</div>
|
|
6
13
|
</template>
|
|
7
14
|
|
|
@@ -9,6 +16,8 @@
|
|
|
9
16
|
|
|
10
17
|
import { Loader } from '@googlemaps/js-api-loader';
|
|
11
18
|
|
|
19
|
+
let loader = null
|
|
20
|
+
|
|
12
21
|
export default{
|
|
13
22
|
|
|
14
23
|
name: "GHeatMaps",
|
|
@@ -43,9 +52,10 @@ export default{
|
|
|
43
52
|
if(!Array.isArray(this.datasets) || this.datasets.length < 1)
|
|
44
53
|
return
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
if(!loader)
|
|
56
|
+
loader = new Loader({
|
|
57
|
+
apiKey: this.apiKey // "AIzaSyBmzMlmrR5St-njtN--64y_oLTa9FDLYfQ"
|
|
58
|
+
})
|
|
49
59
|
|
|
50
60
|
loader.load()
|
|
51
61
|
.then(async () => {
|
|
@@ -63,6 +73,7 @@ export default{
|
|
|
63
73
|
mapTypeId: 'roadmap',
|
|
64
74
|
streetViewControl: false,
|
|
65
75
|
keyboardShortcuts: false,
|
|
76
|
+
disableDefaultUI: true,
|
|
66
77
|
styles: [
|
|
67
78
|
{ elementType: "geometry", stylers: [{ color: "#242f3e" }] },
|
|
68
79
|
{ elementType: "labels.text.stroke", stylers: [{ color: "#242f3e" }] },
|
|
@@ -207,8 +218,6 @@ export default{
|
|
|
207
218
|
"rgba(255, 0, 0, 1)",
|
|
208
219
|
];
|
|
209
220
|
heatmap.set("gradient", gradient);
|
|
210
|
-
|
|
211
|
-
//console.log('Gmap, data count:', this.data.length)
|
|
212
221
|
});
|
|
213
222
|
}
|
|
214
223
|
|
|
@@ -216,6 +225,15 @@ export default{
|
|
|
216
225
|
|
|
217
226
|
computed: {
|
|
218
227
|
|
|
228
|
+
uniqueCount(){
|
|
229
|
+
if(!Array.isArray(this.value?.items)) return 0
|
|
230
|
+
|
|
231
|
+
return Object.keys(this.value.items.reduce((acc, item) => {
|
|
232
|
+
acc[item[this.column]] = 1
|
|
233
|
+
return acc
|
|
234
|
+
}, {})).length
|
|
235
|
+
},
|
|
236
|
+
|
|
219
237
|
datasets(){
|
|
220
238
|
if(!Array.isArray(this.value?.items)) return []
|
|
221
239
|
|
|
@@ -250,7 +268,7 @@ export default{
|
|
|
250
268
|
<style module>
|
|
251
269
|
|
|
252
270
|
.comp{
|
|
253
|
-
@apply flex flex-col h-[40vh] bg-base-500;
|
|
271
|
+
@apply flex flex-col h-[40vh] border-[1px] border-text-50 bg-base-500 rounded-xl overflow-hidden;
|
|
254
272
|
}
|
|
255
273
|
|
|
256
274
|
</style>
|
|
@@ -147,11 +147,11 @@ const generatePivotColumns = (preset, items) => {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
(preset.pivot.columns ?? []).filter(_ => !pivotColumns.find(i => i.key === _.key))
|
|
150
|
+
/*(preset.pivot.columns ?? []).filter(_ => !pivotColumns.find(i => i.key === _.key))
|
|
151
151
|
.forEach(_ => {
|
|
152
152
|
_.visible = false
|
|
153
153
|
pivotColumns.push(_)
|
|
154
|
-
})
|
|
154
|
+
})*/
|
|
155
155
|
|
|
156
156
|
preset.pivot.columns = pivotColumns
|
|
157
157
|
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
16
|
<div v-else class="flex flex-col gap-3">
|
|
17
|
-
<
|
|
17
|
+
<div class="flex flex-row items-center gap-4">
|
|
18
|
+
<label class="text-text-400 text-ellipsis overflow-hidden whitespace-nowrap flex-1">{{ label }}</label>
|
|
19
|
+
</div>
|
|
18
20
|
|
|
19
21
|
<div class="flex-1">
|
|
20
22
|
<Bar :style="barStyles"
|
|
@@ -22,14 +24,47 @@
|
|
|
22
24
|
:data="chartData"/>
|
|
23
25
|
</div>
|
|
24
26
|
|
|
25
|
-
<div v-if="yAxeMultiple && yLegends?.length
|
|
26
|
-
<div v-for="yLegend in
|
|
27
|
-
|
|
28
|
-
class="p-0.5 px-1 rounded-
|
|
29
|
-
:
|
|
30
|
-
|
|
27
|
+
<div v-if="yAxeMultiple && yLegends?.length > 0" class="flex flex-row items-center flex-wrap justify-center gap-1">
|
|
28
|
+
<div v-for="yLegend in showedYLegends"
|
|
29
|
+
@click="toggleExcludes(yLegend)"
|
|
30
|
+
class="p-0.5 px-1 rounded-full text-black cursor-default text-xs min-w-[50px] max-w-[60px] text-center text-ellipsis overflow-hidden whitespace-nowrap capitalize"
|
|
31
|
+
:class="excluded.includes(yLegend.key) ? 'bg-text-200' : ''"
|
|
32
|
+
:style="{ backgroundColor:excluded.includes(yLegend.key) ? '' : yLegend.color }">
|
|
33
|
+
{{ yLegend.key }}
|
|
31
34
|
</div>
|
|
35
|
+
<button v-if="yLegends.length > showedYLegends.length" @click="$refs.legendModal.open()"
|
|
36
|
+
class="bg-text-200 hover:bg-primary-600 w-[21px] h-[21px] rounded-full flex items-center justify-center">
|
|
37
|
+
<svg width="14" height="14" class="fill-white opacity-70" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M64 192C28.61 192 0 220.6 0 256s28.61 64 64 64s64-28.62 64-64S99.39 192 64 192zM256 192C220.6 192 192 220.6 192 256s28.61 64 64 64s64-28.62 64-64S291.4 192 256 192zM448 192c-35.39 0-64 28.62-64 64s28.61 64 64 64s64-28.62 64-64S483.4 192 448 192z"/></svg>
|
|
38
|
+
</button>
|
|
32
39
|
</div>
|
|
40
|
+
|
|
41
|
+
<Modal ref="legendModal" width="320" height="360" :dismissable="true" @dismiss="$refs.legendModal.close()">
|
|
42
|
+
<template v-slot:head>
|
|
43
|
+
<div class="relative p-5">
|
|
44
|
+
<h3>Legend</h3>
|
|
45
|
+
<div class="absolute top-0 right-0 p-2">
|
|
46
|
+
<button type="button" class="p-2" @click="$refs.legendModal.close()">
|
|
47
|
+
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
48
|
+
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
49
|
+
</svg>
|
|
50
|
+
</button>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
<div class="flex-1 p-5 pt-0">
|
|
55
|
+
|
|
56
|
+
<div class="flex flex-col divide-y divide-text-50">
|
|
57
|
+
<div v-for="yLegend in yLegends" class="flex flex-row items-center gap-2 py-2">
|
|
58
|
+
<div class="w-[19px] h-[19px] rounded-full" :style="{ backgroundColor:yLegend.color }"></div>
|
|
59
|
+
<div class="flex-1 text-ellipsis whitespace-nowrap overflow-hidden">{{ yLegend.key }}</div>
|
|
60
|
+
<Checkbox :value="!excluded.includes(yLegend.key)" @click.prevent="toggleExcludes(yLegend)" />
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<br />
|
|
65
|
+
|
|
66
|
+
</div>
|
|
67
|
+
</Modal>
|
|
33
68
|
</div>
|
|
34
69
|
|
|
35
70
|
</div>
|
|
@@ -63,16 +98,18 @@ export default{
|
|
|
63
98
|
|
|
64
99
|
return {
|
|
65
100
|
labels: this.value?.labels ?? [],
|
|
66
|
-
datasets: this.value.datasets
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
101
|
+
datasets: this.value.datasets
|
|
102
|
+
.filter(_ => !this.excluded.includes(_.label))
|
|
103
|
+
.map(_ => {
|
|
104
|
+
return {
|
|
105
|
+
..._,
|
|
106
|
+
borderWidth: 0,
|
|
107
|
+
borderColor: function(context, options) {
|
|
108
|
+
const hex = options.color;
|
|
109
|
+
return color(hex).darken(0.5).rgbString()
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
})
|
|
76
113
|
}
|
|
77
114
|
},
|
|
78
115
|
|
|
@@ -93,7 +130,15 @@ export default{
|
|
|
93
130
|
label: (tooltipItem) => {
|
|
94
131
|
if(this.yAxeMultiple && this.usePercentage)
|
|
95
132
|
return `${tooltipItem.dataset.label}: ${tooltipItem.dataset.data0[tooltipItem.dataIndex]} (${tooltipItem.raw}%)`
|
|
96
|
-
|
|
133
|
+
else{
|
|
134
|
+
if(this.stacked){
|
|
135
|
+
const total = this.value.datasets.reduce((acc, cur) => acc + cur.data[tooltipItem.dataIndex], 0)
|
|
136
|
+
const percentage = ((tooltipItem.raw / total) * 100).toFixed(1)
|
|
137
|
+
|
|
138
|
+
return `${tooltipItem.dataset.label}: ${tooltipItem.raw} (${percentage}%)`;
|
|
139
|
+
}
|
|
140
|
+
return `${tooltipItem.dataset.label}: ${tooltipItem.raw}`;
|
|
141
|
+
}
|
|
97
142
|
}
|
|
98
143
|
},
|
|
99
144
|
}
|
|
@@ -122,10 +167,15 @@ export default{
|
|
|
122
167
|
y: {
|
|
123
168
|
beginAtZero: true,
|
|
124
169
|
ticks: {
|
|
125
|
-
display:
|
|
170
|
+
display: true,
|
|
126
171
|
font: {
|
|
127
172
|
size: 11,
|
|
128
173
|
},
|
|
174
|
+
callback: (value, index, ticks) => {
|
|
175
|
+
if(this.usePercentage)
|
|
176
|
+
return Math.round(index / (ticks.length - 1) * 100) + '%'
|
|
177
|
+
return value
|
|
178
|
+
},
|
|
129
179
|
},
|
|
130
180
|
grid: {
|
|
131
181
|
display: true,
|
|
@@ -146,7 +196,11 @@ export default{
|
|
|
146
196
|
|
|
147
197
|
yLegends(){
|
|
148
198
|
return this.value?.yLegends ?? []
|
|
149
|
-
}
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
showedYLegends(){
|
|
202
|
+
return this.yLegends.slice(0, 5)
|
|
203
|
+
},
|
|
150
204
|
|
|
151
205
|
},
|
|
152
206
|
|
|
@@ -215,6 +269,13 @@ export default{
|
|
|
215
269
|
this.readyState = state
|
|
216
270
|
},
|
|
217
271
|
|
|
272
|
+
toggleExcludes(yLegend){
|
|
273
|
+
if(this.excluded.includes(yLegend.key))
|
|
274
|
+
this.excluded.splice(this.excluded.indexOf(yLegend.key), 1)
|
|
275
|
+
else
|
|
276
|
+
this.excluded.push(yLegend.key)
|
|
277
|
+
}
|
|
278
|
+
|
|
218
279
|
},
|
|
219
280
|
|
|
220
281
|
props: {
|
|
@@ -236,6 +297,11 @@ export default{
|
|
|
236
297
|
xAxeMultiple: Boolean,
|
|
237
298
|
yAxeMultiple: Boolean,
|
|
238
299
|
|
|
300
|
+
excluded: {
|
|
301
|
+
type: Array,
|
|
302
|
+
default: []
|
|
303
|
+
},
|
|
304
|
+
|
|
239
305
|
segments: Array,
|
|
240
306
|
xAxesGroup: String,
|
|
241
307
|
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
<div class="flex flex-col gap-1">
|
|
27
27
|
<label class="flex-1">Label</label>
|
|
28
|
-
<Textbox v-model="value.props.label" maxlength="
|
|
28
|
+
<Textbox v-model="value.props.label" maxlength="50" placeholder="Label" :readonly="readonly" />
|
|
29
29
|
</div>
|
|
30
30
|
|
|
31
31
|
<div v-if="value.props.datasourceUid" class="flex flex-col gap-5">
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
134
134
|
</div>
|
|
135
135
|
<div class="flex-1 flex flex-row gap-2">
|
|
136
|
-
<Dropdown v-model="item.key" :readonly="readonly" class="flex-1">
|
|
136
|
+
<Dropdown v-model="item.key" :readonly="readonly" class="flex-1" @change="clearExcluded">
|
|
137
137
|
<option v-for="column in selectedDatasourceColumns"
|
|
138
138
|
:value="column.key">
|
|
139
139
|
{{ selectedDatasource.pivot?.enabled ? column.key : column.label }}
|
|
@@ -273,6 +273,10 @@ export default{
|
|
|
273
273
|
this.$util.push(this.interactions, obj)
|
|
274
274
|
},
|
|
275
275
|
|
|
276
|
+
clearExcluded(){
|
|
277
|
+
this.value.props.excluded = []
|
|
278
|
+
},
|
|
279
|
+
|
|
276
280
|
swap(){
|
|
277
281
|
const yAxes = this.value.props.yAxes
|
|
278
282
|
const xAxes = this.value.props.xAxes
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
export default{
|
|
30
30
|
|
|
31
|
-
inject: [ 'alert', 'socket' ],
|
|
31
|
+
inject: [ 'alert', 'preview', 'socket' ],
|
|
32
32
|
|
|
33
33
|
props: {
|
|
34
34
|
src: String
|
|
@@ -67,13 +67,9 @@ export default{
|
|
|
67
67
|
},
|
|
68
68
|
|
|
69
69
|
load(){
|
|
70
|
-
this.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
.then(res => {
|
|
74
|
-
this.res = res
|
|
75
|
-
})
|
|
76
|
-
.catch(err => this.alert(err))
|
|
70
|
+
this.preview(this.datasource)
|
|
71
|
+
.then(res => this.res = res)
|
|
72
|
+
.catch(err => this.alert(err))
|
|
77
73
|
},
|
|
78
74
|
|
|
79
75
|
open(datasource){
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex flex-col gap-2">
|
|
2
|
+
<div class="flex flex-col gap-2" @click="log(datasourceUid)">
|
|
3
3
|
|
|
4
4
|
<Doughnut class="aspect-square"
|
|
5
5
|
:options="chartOptions"
|
|
@@ -55,6 +55,19 @@ export default{
|
|
|
55
55
|
legend: {
|
|
56
56
|
display: false
|
|
57
57
|
},
|
|
58
|
+
tooltip: {
|
|
59
|
+
callbacks: {
|
|
60
|
+
title: function(tooltipItems) {
|
|
61
|
+
return `${tooltipItems[0].label}`;
|
|
62
|
+
},
|
|
63
|
+
label: (tooltipItem) => {
|
|
64
|
+
const total = tooltipItem.dataset.data.reduce((a, b) => a + b, 0)
|
|
65
|
+
const percentage = ((tooltipItem.raw / total) * 100).toFixed(1)
|
|
66
|
+
|
|
67
|
+
return `${tooltipItem.dataset.label}: ${tooltipItem.raw} (${percentage}%)`;
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
},
|
|
58
71
|
},
|
|
59
72
|
onClick: this.onClick
|
|
60
73
|
}
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
<Dropdown class="min-w-[150px]"
|
|
12
12
|
:readonly="readonly"
|
|
13
13
|
v-model="value.props.datasourceUid"
|
|
14
|
-
@change="delete value.props.columns">
|
|
14
|
+
@change="delete value.props.columns;">
|
|
15
|
+
<option disabled selected>Select Datasource</option>
|
|
15
16
|
<option v-for="obj in datasource"
|
|
16
17
|
:value="obj.uid">
|
|
17
18
|
{{ obj.name }}
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
|
|
22
23
|
<div>
|
|
23
24
|
<label class="text-text-400">Label</label>
|
|
24
|
-
<Textbox v-model="value.props.label" maxlength="
|
|
25
|
+
<Textbox v-model="value.props.label" maxlength="50" placeholder="Label" :readonly="readonly" />
|
|
25
26
|
</div>
|
|
26
27
|
|
|
27
28
|
<div v-if="value.props.datasourceUid" class="flex flex-col gap-5">
|
|
@@ -40,7 +41,8 @@
|
|
|
40
41
|
|
|
41
42
|
<Dropdown v-model="value.props.rowsModifier"
|
|
42
43
|
:readonly="readonly"
|
|
43
|
-
:class="!value.props.rowsModifier ? 'w-[80px]' : 'w-[150px]'"
|
|
44
|
+
:class="!value.props.rowsModifier ? 'w-[80px]' : 'w-[150px]'"
|
|
45
|
+
@change="$emit('change')">
|
|
44
46
|
<option value="">-</option>
|
|
45
47
|
<option value="lowercase">Lower</option>
|
|
46
48
|
<option value="capitalize">Capitalize</option>
|
|
@@ -70,7 +72,8 @@
|
|
|
70
72
|
|
|
71
73
|
<Dropdown v-model="value.props.columnModifier"
|
|
72
74
|
:readonly="readonly"
|
|
73
|
-
:class="!value.props.columnModifier ? 'w-[80px]' : 'w-[150px]'"
|
|
75
|
+
:class="!value.props.columnModifier ? 'w-[80px]' : 'w-[150px]'"
|
|
76
|
+
@change="$emit('change')">
|
|
74
77
|
<option value="">-</option>
|
|
75
78
|
<option value="count">Count</option>
|
|
76
79
|
<option value="countDistinct">Unique Count</option>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
<div>
|
|
23
23
|
<label class="text-text-400">Label</label>
|
|
24
|
-
<Textbox v-model="value.props.label" maxlength="
|
|
24
|
+
<Textbox v-model="value.props.label" maxlength="50" placeholder="Label" :readonly="readonly" />
|
|
25
25
|
</div>
|
|
26
26
|
|
|
27
27
|
<div v-if="value.props.datasourceUid" class="flex flex-col gap-5">
|
|
@@ -54,6 +54,19 @@ export default{
|
|
|
54
54
|
legend: {
|
|
55
55
|
display: false
|
|
56
56
|
},
|
|
57
|
+
tooltip: {
|
|
58
|
+
callbacks: {
|
|
59
|
+
title: function(tooltipItems) {
|
|
60
|
+
return `${tooltipItems[0].label}`;
|
|
61
|
+
},
|
|
62
|
+
label: (tooltipItem) => {
|
|
63
|
+
const total = tooltipItem.dataset.data.reduce((a, b) => a + b, 0)
|
|
64
|
+
const percentage = ((tooltipItem.raw / total) * 100).toFixed(1)
|
|
65
|
+
|
|
66
|
+
return `${tooltipItem.dataset.label}: ${tooltipItem.raw} (${percentage}%)`;
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
},
|
|
57
70
|
},
|
|
58
71
|
onClick: this.onClick
|
|
59
72
|
}
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
<div class="flex flex-col gap-1">
|
|
27
27
|
<label class="text-text-400">Label</label>
|
|
28
|
-
<Textbox v-model="value.props.label" maxlength="
|
|
28
|
+
<Textbox v-model="value.props.label" maxlength="50" placeholder="Label" :readonly="readonly" />
|
|
29
29
|
</div>
|
|
30
30
|
|
|
31
31
|
<div v-if="value.props.datasourceUid" class="flex flex-col gap-5">
|
|
@@ -50,11 +50,23 @@ export default{
|
|
|
50
50
|
return {
|
|
51
51
|
responsive: true,
|
|
52
52
|
maintainAspectRatio: true,
|
|
53
|
-
/*animation: false,*/
|
|
54
53
|
plugins: {
|
|
55
54
|
legend: {
|
|
56
55
|
display: false
|
|
57
56
|
},
|
|
57
|
+
tooltip: {
|
|
58
|
+
callbacks: {
|
|
59
|
+
title: function(tooltipItems) {
|
|
60
|
+
return `${tooltipItems[0].label}`;
|
|
61
|
+
},
|
|
62
|
+
label: (tooltipItem) => {
|
|
63
|
+
const total = tooltipItem.dataset.data.reduce((a, b) => a + b, 0)
|
|
64
|
+
const percentage = ((tooltipItem.raw / total) * 100).toFixed(1)
|
|
65
|
+
|
|
66
|
+
return `${tooltipItem.dataset.label}: ${tooltipItem.raw} (${percentage}%)`;
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
},
|
|
58
70
|
},
|
|
59
71
|
scales: {
|
|
60
72
|
r: {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
<div>
|
|
23
23
|
<label class="text-text-400">Label</label>
|
|
24
|
-
<Textbox v-model="value.props.label" maxlength="
|
|
24
|
+
<Textbox v-model="value.props.label" maxlength="50" placeholder="Label" :readonly="readonly" />
|
|
25
25
|
</div>
|
|
26
26
|
|
|
27
27
|
<div v-if="value.props.datasourceUid" class="flex flex-col gap-5">
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
|
|
41
41
|
<Dropdown v-model="value.props.rowsModifier"
|
|
42
42
|
:readonly="readonly"
|
|
43
|
-
class="w-[125px]"
|
|
43
|
+
class="w-[125px]"
|
|
44
|
+
@change="$emit('change')">
|
|
44
45
|
<option value="">-</option>
|
|
45
46
|
<option value="lowercase">Lower</option>
|
|
46
47
|
<option value="capitalize">Capitalize</option>
|
|
@@ -70,7 +71,8 @@
|
|
|
70
71
|
|
|
71
72
|
<Dropdown v-model="value.props.columnModifier"
|
|
72
73
|
:readonly="readonly"
|
|
73
|
-
class="w-[125px]"
|
|
74
|
+
class="w-[125px]"
|
|
75
|
+
@change="$emit('change')">
|
|
74
76
|
<option value="">-</option>
|
|
75
77
|
<option value="count">Count</option>
|
|
76
78
|
<option value="countDistinct">Unique Count</option>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
<div class="flex flex-col gap-1">
|
|
17
17
|
<label class="text-text-400">Label</label>
|
|
18
|
-
<Textbox v-model="value.props.label" maxlength="
|
|
18
|
+
<Textbox v-model="value.props.label" maxlength="50" placeholder="Label" :readonly="readonly" />
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
21
|
<div class="flex flex-row items-center">
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
<button type="button" @click="delete cConfig.selectedView">
|
|
12
12
|
<svg width="16" height="16" class="fill-text hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M447.1 256C447.1 273.7 433.7 288 416 288H109.3l105.4 105.4c12.5 12.5 12.5 32.75 0 45.25C208.4 444.9 200.2 448 192 448s-16.38-3.125-22.62-9.375l-160-160c-12.5-12.5-12.5-32.75 0-45.25l160-160c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25L109.3 224H416C433.7 224 447.1 238.3 447.1 256z"/></svg>
|
|
13
13
|
</button>
|
|
14
|
-
<div class="leading-tight">
|
|
14
|
+
<div class="leading-tight flex-1">
|
|
15
15
|
<small class="text-xs text-text-400">{{ selectedView.type }}</small>
|
|
16
|
-
<h5 class="flex-1" @click="log(selectedView)">
|
|
16
|
+
<h5 class="flex-1 text-ellipsis overflow-hidden whitespace-nowrap" @click="log(selectedView)">
|
|
17
17
|
{{ selectedView.props.label ?? selectedView.name }}
|
|
18
18
|
</h5>
|
|
19
19
|
</div>
|
|
@@ -214,136 +214,10 @@
|
|
|
214
214
|
</div>
|
|
215
215
|
|
|
216
216
|
<div v-else-if="selectedDatasource.tabIndex === 4" class="p-5 flex-1 flex flex-col gap-5">
|
|
217
|
-
<div>
|
|
218
|
-
<Checkbox v-model="selectedDatasourcePivot.enabled"
|
|
219
|
-
@change="" :disabled="selectedPreset.readonly">
|
|
220
|
-
Pivot Enabled
|
|
221
|
-
</Checkbox>
|
|
222
|
-
</div>
|
|
223
|
-
|
|
224
|
-
<div class="grid grid-cols-1 gap-6">
|
|
225
|
-
|
|
226
|
-
<div>
|
|
227
|
-
<div class="flex flex-row items-center gap-2">
|
|
228
|
-
<label>Groups</label>
|
|
229
|
-
<button v-if="!selectedPreset.readonly" type="button" @click="$refs.columnSelector.open(obj => addPivot('rows', obj), selectedDatasourcePivotColumns)">
|
|
230
|
-
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
231
|
-
</button>
|
|
232
|
-
</div>
|
|
233
|
-
<ListItem :items="selectedDatasourcePivot.rows"
|
|
234
|
-
@reorder="(from, to) => { selectedDatasourcePivot.rows.splice(to, 0, selectedDatasourcePivot.rows.splice(from, 1)[0]); }"
|
|
235
|
-
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
236
|
-
container-class="divide-y divide-text-50">
|
|
237
|
-
<template v-slot="{ item, index }">
|
|
238
|
-
<div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
|
|
239
|
-
<div data-reorder v-if="(selectedDatasourcePivot.rows ?? []).length > 1 && !selectedPreset.readonly">
|
|
240
|
-
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
241
|
-
</div>
|
|
242
|
-
<div class="flex-1 flex flex-row gap-3">
|
|
243
|
-
<strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
|
|
244
|
-
@click="!selectedPreset.readonly ? $refs.columnSelector.open(obj => { Object.assign(item, obj); }, selectedDatasourcePivotColumns) : null;">
|
|
245
|
-
{{ item.label ? item.label : item.key }}
|
|
246
|
-
</strong>
|
|
247
|
-
<select v-if="item.type === 'date'"
|
|
248
|
-
v-model="item.aggregrate"
|
|
249
|
-
class="px-1 appearance-none bg-base-300 rounded-md border-[1px] border-text-50 outline-none"
|
|
250
|
-
@change="">
|
|
251
|
-
<option value="hour">Hour</option>
|
|
252
|
-
<option value="date">Date</option>
|
|
253
|
-
<option value="month">Month</option>
|
|
254
|
-
<option value="year">Year</option>
|
|
255
|
-
</select>
|
|
256
|
-
</div>
|
|
257
|
-
<button v-if="!selectedPreset.readonly" type="button" @click="selectedDatasourcePivot.rows.splice(index, 1); loadPivotData()">
|
|
258
|
-
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
259
|
-
</button>
|
|
260
|
-
</div>
|
|
261
|
-
</template>
|
|
262
|
-
</ListItem>
|
|
263
|
-
</div>
|
|
264
217
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
<button v-if="!selectedPreset.readonly" type="button" @click="$refs.columnSelector.open(obj => addPivot('values', obj), selectedDatasourcePivotColumns)">
|
|
269
|
-
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
270
|
-
</button>
|
|
271
|
-
</div>
|
|
272
|
-
<ListItem :items="selectedDatasourcePivot.values"
|
|
273
|
-
@reorder="(from, to) => { selectedDatasourcePivot.values.splice(to, 0, selectedDatasourcePivot.values.splice(from, 1)[0]); }"
|
|
274
|
-
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
275
|
-
container-class="divide-y divide-text-50">
|
|
276
|
-
<template v-slot="{ item, index }">
|
|
277
|
-
<div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
|
|
278
|
-
<div data-reorder v-if="(selectedDatasourcePivot.values ?? []).length > 1 && !selectedPreset.readonly">
|
|
279
|
-
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
280
|
-
</div>
|
|
281
|
-
<div class="flex-1 flex flex-row gap-3">
|
|
282
|
-
<strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
|
|
283
|
-
@click="!selectedPreset.readonly ? $refs.columnSelector.open(obj => { Object.assign(item, obj); }, selectedDatasourcePivotColumns) : null;">
|
|
284
|
-
{{ item.label ? item.label : item.key }}
|
|
285
|
-
</strong>
|
|
286
|
-
<select v-model="item.aggregrate"
|
|
287
|
-
:disabled="selectedPreset.readonly"
|
|
288
|
-
class="px-1 appearance-none bg-base-300 w-[80px] rounded-md border-[1px] border-text-50 outline-none"
|
|
289
|
-
@change="loadPivotData">
|
|
290
|
-
<option value="">Default</option>
|
|
291
|
-
<option value="count">Count</option>
|
|
292
|
-
<option value="countDistinct">Distinct Count</option>
|
|
293
|
-
<option v-if="[ 'number' ].includes(item.type)" value="sum">Sum</option>
|
|
294
|
-
<option v-if="[ 'number' ].includes(item.type)" value="avg">Average</option>
|
|
295
|
-
<option v-if="[ 'number' ].includes(item.type)" value="min">Min</option>
|
|
296
|
-
<option v-if="[ 'number' ].includes(item.type)" value="max">Max</option>
|
|
297
|
-
</select>
|
|
298
|
-
</div>
|
|
299
|
-
<button v-if="!selectedPreset.readonly" type="button" @click="selectedDatasourcePivot.values.splice(index, 1); loadPivotData()">
|
|
300
|
-
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
301
|
-
</button>
|
|
302
|
-
</div>
|
|
303
|
-
</template>
|
|
304
|
-
</ListItem>
|
|
305
|
-
</div>
|
|
306
|
-
|
|
307
|
-
<div>
|
|
308
|
-
<div class="flex flex-row items-center gap-2">
|
|
309
|
-
<label class="flex-1">Columns</label>
|
|
310
|
-
<button v-if="selectedDatasourcePivot.manualColumns && !selectedPreset.readonly"
|
|
311
|
-
type="button"
|
|
312
|
-
class="text-primary"
|
|
313
|
-
@click="delete selectedDatasourcePivot.manualColumns; ">Reset</button>
|
|
314
|
-
</div>
|
|
315
|
-
<ListItem :items="selectedDatasourcePivot.columns"
|
|
316
|
-
@reorder="(from, to) => { selectedDatasourcePivot.columns.splice(to, 0, selectedDatasourcePivot.columns.splice(from, 1)[0]); selectedDatasourcePivot.manualColumns = true; }"
|
|
317
|
-
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
318
|
-
container-class="divide-y divide-text-50">
|
|
319
|
-
<template v-slot="{ item, index }">
|
|
320
|
-
<div class="flex flex-row gap-2 items-center px-2 bg-base-500">
|
|
321
|
-
<div data-reorder v-if="!selectedPreset.readonly">
|
|
322
|
-
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
323
|
-
</div>
|
|
324
|
-
<Textbox class="flex-1 border-none" :readonly="selectedPreset.readonly" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
|
|
325
|
-
item-class="p-1"/>
|
|
326
|
-
<button type="button" v-if="[ 'number' ].includes(item.type) && !selectedPreset.readonly" @click="">
|
|
327
|
-
<svg width="13" height="13" :class="(item.appearances ?? []).length > 0 ? 'fill-primary' : 'fill-text-300 hover:fill-primary'"
|
|
328
|
-
@click="$refs.presetBarPivotColumnEdit.open(item, next => { Object.assign(item, next); })"
|
|
329
|
-
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M176 0h-128C21.49 0 0 21.49 0 48v128C0 202.5 21.49 224 48 224h128C202.5 224 224 202.5 224 176v-128C224 21.49 202.5 0 176 0zM176 288h-128C21.49 288 0 309.5 0 336v128C0 490.5 21.49 512 48 512h128C202.5 512 224 490.5 224 464v-128C224 309.5 202.5 288 176 288zM464 0h-128C309.5 0 288 21.49 288 48v128C288 202.5 309.5 224 336 224h128C490.5 224 512 202.5 512 176v-128C512 21.49 490.5 0 464 0zM488 376h-64v-64C424 298.8 413.3 288 400 288s-24 10.75-24 24v64h-64c-13.25 0-24 10.75-24 24s10.75 24 24 24h64v64c0 13.25 10.75 24 24 24s24-10.75 24-24v-64h64c13.25 0 24-10.75 24-24S501.3 376 488 376z"/></svg>
|
|
330
|
-
</button>
|
|
331
|
-
<button v-if="!selectedPreset.readonly" type="button" @click="selectedDatasourcePivot.columns.splice(index, 1); selectedDatasourcePivot.manualColumns = true; ">
|
|
332
|
-
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
333
|
-
</button>
|
|
334
|
-
</div>
|
|
335
|
-
</template>
|
|
336
|
-
</ListItem>
|
|
337
|
-
|
|
338
|
-
<PresetBarPivotColumnEdit ref="presetBarPivotColumnEdit" />
|
|
339
|
-
</div>
|
|
340
|
-
|
|
341
|
-
<div class="flex flex-row items-center gap-3">
|
|
342
|
-
<label>Total</label>
|
|
343
|
-
<Switch v-model="selectedDatasourcePivot.useTotal" :readonly="selectedPreset.readonly" @change=""/>
|
|
344
|
-
</div>
|
|
345
|
-
|
|
346
|
-
</div>
|
|
218
|
+
<PresetBarPivot :pivot="selectedDatasourcePivot"
|
|
219
|
+
:columns="selectedDatasourcePivotColumns"
|
|
220
|
+
@apply="updatePivot" />
|
|
347
221
|
|
|
348
222
|
<br />
|
|
349
223
|
</div>
|
|
@@ -575,7 +449,8 @@
|
|
|
575
449
|
container-class="divide-y divide-text-50">
|
|
576
450
|
<template v-slot="{ item, index }">
|
|
577
451
|
<div class="flex flex-row items-center gap-1 bg-base-500 hover:bg-text-50 pl-3">
|
|
578
|
-
<Radio class="flex-1 py-3"
|
|
452
|
+
<Radio class="flex-1 py-3" :checked="item.uid === cConfig.viewedUid"
|
|
453
|
+
@click="(e) => e.shiftKey ? openPreset(item.uid) : selectPreset(item.uid)">
|
|
579
454
|
{{ item.name }}
|
|
580
455
|
</Radio>
|
|
581
456
|
<button :ref="`sharedPresetItemBtn${index}`"
|
|
@@ -774,6 +649,7 @@ import {defineAsyncComponent} from "vue";
|
|
|
774
649
|
import SharingModal from "./Dashboard/SharingModal.vue";
|
|
775
650
|
import PresetSelectorFilterItem from "../components/PresetSelectorFilterItem.vue";
|
|
776
651
|
import {generatePivotColumns} from "../utils/preset-selector.mjs";
|
|
652
|
+
import PresetBarPivot from "./PresetBarPivot.vue";
|
|
777
653
|
|
|
778
654
|
const findComponents = (items, uid) => {
|
|
779
655
|
if(!Array.isArray(items)) return
|
|
@@ -793,6 +669,7 @@ const findComponents = (items, uid) => {
|
|
|
793
669
|
export default{
|
|
794
670
|
|
|
795
671
|
components: {
|
|
672
|
+
PresetBarPivot,
|
|
796
673
|
DatasourcePreview: defineAsyncComponent(() => import('./Dashboard/DatasourcePreview.vue')),
|
|
797
674
|
PresetSelectorFilterItem,
|
|
798
675
|
SharingModal,
|
|
@@ -1210,20 +1087,22 @@ export default{
|
|
|
1210
1087
|
|
|
1211
1088
|
const currentDatasource = this.viewedPreset.datasource.find(_ => _.uid === item.datasourceUid)
|
|
1212
1089
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1090
|
+
if(currentDatasource){
|
|
1091
|
+
results.push({
|
|
1092
|
+
datasource: {
|
|
1093
|
+
...currentDatasource,
|
|
1094
|
+
...(uids && uids[item.uid] ? uids[item.uid] : {}),
|
|
1095
|
+
type: currentDatasource.type,
|
|
1096
|
+
filters: [
|
|
1097
|
+
...(currentDatasource.filters ?? []),
|
|
1098
|
+
...(this.queryFilters[currentDatasource.uid] ?? [])
|
|
1099
|
+
]
|
|
1100
|
+
},
|
|
1101
|
+
type: item.type,
|
|
1102
|
+
uid: item.uid,
|
|
1103
|
+
...item
|
|
1104
|
+
})
|
|
1105
|
+
}
|
|
1227
1106
|
}
|
|
1228
1107
|
else if(item.items){
|
|
1229
1108
|
const subResults = this.recurseViews(item.items, uids)
|
|
@@ -1381,6 +1260,24 @@ export default{
|
|
|
1381
1260
|
this.$router.replace({ query })
|
|
1382
1261
|
},
|
|
1383
1262
|
|
|
1263
|
+
async preview(datasource){
|
|
1264
|
+
return new Promise((resolve, reject) => {
|
|
1265
|
+
this.socket.send(this.previewSrc, { datasource })
|
|
1266
|
+
.then(res => {
|
|
1267
|
+
this.previewData = res
|
|
1268
|
+
resolve(res)
|
|
1269
|
+
})
|
|
1270
|
+
.catch(err => reject(err))
|
|
1271
|
+
})
|
|
1272
|
+
},
|
|
1273
|
+
|
|
1274
|
+
updatePivot(){
|
|
1275
|
+
this.preview(this.selectedDatasource)
|
|
1276
|
+
.then(res => {
|
|
1277
|
+
generatePivotColumns(this.selectedDatasource, res.items)
|
|
1278
|
+
})
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1384
1281
|
},
|
|
1385
1282
|
|
|
1386
1283
|
props:{
|
|
@@ -1410,7 +1307,8 @@ export default{
|
|
|
1410
1307
|
previewDatasource: this.previewDatasource,
|
|
1411
1308
|
emitRoot: this.emitRoot,
|
|
1412
1309
|
getConfig: this.getConfig,
|
|
1413
|
-
selectPreset: this.selectPreset
|
|
1310
|
+
selectPreset: this.selectPreset,
|
|
1311
|
+
preview: this.preview
|
|
1414
1312
|
}
|
|
1415
1313
|
},
|
|
1416
1314
|
|
|
@@ -454,137 +454,9 @@
|
|
|
454
454
|
|
|
455
455
|
</div>
|
|
456
456
|
|
|
457
|
-
<div v-else-if="config.presetBarTabIndex === 5" class="flex-1
|
|
457
|
+
<div v-else-if="config.presetBarTabIndex === 5" class="flex-1 p-6">
|
|
458
458
|
|
|
459
|
-
<
|
|
460
|
-
<Checkbox v-model="presetPivot.enabled"
|
|
461
|
-
@change="apply()">
|
|
462
|
-
Pivot Enabled
|
|
463
|
-
</Checkbox>
|
|
464
|
-
</div>
|
|
465
|
-
|
|
466
|
-
<div class="grid grid-cols-1 gap-6">
|
|
467
|
-
|
|
468
|
-
<div>
|
|
469
|
-
<div class="flex flex-row items-center gap-2">
|
|
470
|
-
<label>Groups</label>
|
|
471
|
-
<button type="button" @click="$refs.columnSelector.open(obj => addPivot('rows', obj), pivotColumns)">
|
|
472
|
-
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
473
|
-
</button>
|
|
474
|
-
</div>
|
|
475
|
-
<ListItem :items="presetPivot.rows"
|
|
476
|
-
@reorder="(from, to) => { presetPivot.rows.splice(to, 0, presetPivot.rows.splice(from, 1)[0]); apply() }"
|
|
477
|
-
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
478
|
-
container-class="divide-y divide-text-50">
|
|
479
|
-
<template v-slot="{ item, index }">
|
|
480
|
-
<div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
|
|
481
|
-
<div data-reorder v-if="(presetPivot.rows ?? []).length > 1">
|
|
482
|
-
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
483
|
-
</div>
|
|
484
|
-
<div class="flex-1 flex flex-row gap-3">
|
|
485
|
-
<strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
|
|
486
|
-
@click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, pivotColumns);">
|
|
487
|
-
{{ item.label ? item.label : item.key }}
|
|
488
|
-
</strong>
|
|
489
|
-
<select v-if="item.type === 'date'"
|
|
490
|
-
v-model="item.aggregrate"
|
|
491
|
-
class="px-1 appearance-none bg-base-300 rounded-md border-[1px] border-text-50 outline-none"
|
|
492
|
-
@change="apply()">
|
|
493
|
-
<option value="hour">Hour</option>
|
|
494
|
-
<option value="date">Date</option>
|
|
495
|
-
<option value="month">Month</option>
|
|
496
|
-
<option value="year">Year</option>
|
|
497
|
-
</select>
|
|
498
|
-
</div>
|
|
499
|
-
<button type="button" @click="presetPivot.rows.splice(index, 1); apply()">
|
|
500
|
-
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
501
|
-
</button>
|
|
502
|
-
</div>
|
|
503
|
-
</template>
|
|
504
|
-
</ListItem>
|
|
505
|
-
</div>
|
|
506
|
-
|
|
507
|
-
<div>
|
|
508
|
-
<div class="flex flex-row items-center gap-2">
|
|
509
|
-
<label>Aggregrates</label>
|
|
510
|
-
<button type="button" @click="$refs.columnSelector.open(obj => addPivot('values', obj), pivotColumns)">
|
|
511
|
-
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
512
|
-
</button>
|
|
513
|
-
</div>
|
|
514
|
-
<ListItem :items="presetPivot.values"
|
|
515
|
-
@reorder="(from, to) => { presetPivot.values.splice(to, 0, presetPivot.values.splice(from, 1)[0]); }"
|
|
516
|
-
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
517
|
-
container-class="divide-y divide-text-50">
|
|
518
|
-
<template v-slot="{ item, index }">
|
|
519
|
-
<div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
|
|
520
|
-
<div data-reorder v-if="(presetPivot.values ?? []).length > 1">
|
|
521
|
-
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
522
|
-
</div>
|
|
523
|
-
<div class="flex-1 flex flex-row gap-3">
|
|
524
|
-
<strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
|
|
525
|
-
@click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, pivotColumns);">
|
|
526
|
-
{{ item.label ? item.label : item.key }}
|
|
527
|
-
</strong>
|
|
528
|
-
<select v-model="item.aggregrate"
|
|
529
|
-
class="px-1 appearance-none bg-base-300 w-[80px] rounded-md border-[1px] border-text-50 outline-none"
|
|
530
|
-
@change="apply()">
|
|
531
|
-
<option value="">Default</option>
|
|
532
|
-
<option value="count">Count</option>
|
|
533
|
-
<option value="countDistinct">Distinct Count</option>
|
|
534
|
-
<option v-if="[ 'number' ].includes(item.type)" value="sum">Sum</option>
|
|
535
|
-
<option v-if="[ 'number' ].includes(item.type)" value="avg">Average</option>
|
|
536
|
-
<option v-if="[ 'number' ].includes(item.type)" value="min">Min</option>
|
|
537
|
-
<option v-if="[ 'number' ].includes(item.type)" value="max">Max</option>
|
|
538
|
-
</select>
|
|
539
|
-
</div>
|
|
540
|
-
<button type="button" @click="presetPivot.values.splice(index, 1); apply()">
|
|
541
|
-
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
542
|
-
</button>
|
|
543
|
-
</div>
|
|
544
|
-
</template>
|
|
545
|
-
</ListItem>
|
|
546
|
-
</div>
|
|
547
|
-
|
|
548
|
-
<div>
|
|
549
|
-
<div class="flex flex-row items-center gap-2">
|
|
550
|
-
<label class="flex-1">Columns</label>
|
|
551
|
-
<button v-if="presetPivot.manualColumns"
|
|
552
|
-
type="button"
|
|
553
|
-
class="text-primary"
|
|
554
|
-
@click="delete presetPivot.manualColumns; apply()">Reset</button>
|
|
555
|
-
</div>
|
|
556
|
-
<ListItem :items="presetPivot.columns"
|
|
557
|
-
@reorder="(from, to) => { presetPivot.columns.splice(to, 0, presetPivot.columns.splice(from, 1)[0]); presetPivot.manualColumns = true; apply() }"
|
|
558
|
-
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
559
|
-
container-class="divide-y divide-text-50">
|
|
560
|
-
<template v-slot="{ item, index }">
|
|
561
|
-
<div class="flex flex-row gap-2 items-center px-2 bg-base-500">
|
|
562
|
-
<div data-reorder>
|
|
563
|
-
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
564
|
-
</div>
|
|
565
|
-
<Textbox class="flex-1 border-none" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
|
|
566
|
-
item-class="p-1"/>
|
|
567
|
-
<button type="button" v-if="[ 'number' ].includes(item.type)" @click="">
|
|
568
|
-
<svg width="13" height="13" :class="(item.appearances ?? []).length > 0 ? 'fill-primary' : 'fill-text-300 hover:fill-primary'"
|
|
569
|
-
@click="$refs.presetBarPivotColumnEdit.open(item, next => { Object.assign(item, next); apply() })"
|
|
570
|
-
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M176 0h-128C21.49 0 0 21.49 0 48v128C0 202.5 21.49 224 48 224h128C202.5 224 224 202.5 224 176v-128C224 21.49 202.5 0 176 0zM176 288h-128C21.49 288 0 309.5 0 336v128C0 490.5 21.49 512 48 512h128C202.5 512 224 490.5 224 464v-128C224 309.5 202.5 288 176 288zM464 0h-128C309.5 0 288 21.49 288 48v128C288 202.5 309.5 224 336 224h128C490.5 224 512 202.5 512 176v-128C512 21.49 490.5 0 464 0zM488 376h-64v-64C424 298.8 413.3 288 400 288s-24 10.75-24 24v64h-64c-13.25 0-24 10.75-24 24s10.75 24 24 24h64v64c0 13.25 10.75 24 24 24s24-10.75 24-24v-64h64c13.25 0 24-10.75 24-24S501.3 376 488 376z"/></svg>
|
|
571
|
-
</button>
|
|
572
|
-
<button type="button" @click="presetPivot.columns.splice(index, 1); presetPivot.manualColumns = true; apply()">
|
|
573
|
-
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
574
|
-
</button>
|
|
575
|
-
</div>
|
|
576
|
-
</template>
|
|
577
|
-
</ListItem>
|
|
578
|
-
|
|
579
|
-
<PresetBarPivotColumnEdit ref="presetBarPivotColumnEdit" />
|
|
580
|
-
</div>
|
|
581
|
-
|
|
582
|
-
<div class="flex flex-row items-center gap-3">
|
|
583
|
-
<label>Total</label>
|
|
584
|
-
<Switch v-model="presetPivot.useTotal" @change="apply()"/>
|
|
585
|
-
</div>
|
|
586
|
-
|
|
587
|
-
</div>
|
|
459
|
+
<PresetBarPivot :pivot="presetPivot" :columns="pivotColumns" @apply="apply"/>
|
|
588
460
|
|
|
589
461
|
</div>
|
|
590
462
|
|
|
@@ -622,10 +494,11 @@
|
|
|
622
494
|
<script>
|
|
623
495
|
|
|
624
496
|
import PresetSelectorFilterItem from "../components/PresetSelectorFilterItem.vue";
|
|
497
|
+
import PresetBarPivot from "./PresetBarPivot.vue";
|
|
625
498
|
|
|
626
499
|
export default{
|
|
627
500
|
|
|
628
|
-
components: {PresetSelectorFilterItem},
|
|
501
|
+
components: {PresetBarPivot, PresetSelectorFilterItem},
|
|
629
502
|
|
|
630
503
|
emits: [ 'apply' ],
|
|
631
504
|
|
|
@@ -648,11 +521,6 @@ export default{
|
|
|
648
521
|
this.apply()
|
|
649
522
|
},
|
|
650
523
|
|
|
651
|
-
addPivot(type, obj){
|
|
652
|
-
this.presetPivot[type].push(Object.assign({}, obj))
|
|
653
|
-
this.apply()
|
|
654
|
-
},
|
|
655
|
-
|
|
656
524
|
addSort(obj){
|
|
657
525
|
if(!Array.isArray(this.preset.sorts))
|
|
658
526
|
this.preset.sorts = []
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col gap-6">
|
|
3
|
+
|
|
4
|
+
<div>
|
|
5
|
+
<Checkbox v-model="pivot.enabled"
|
|
6
|
+
@change="apply()">
|
|
7
|
+
Pivot Enabled
|
|
8
|
+
</Checkbox>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div class="grid grid-cols-1 gap-6">
|
|
12
|
+
|
|
13
|
+
<div>
|
|
14
|
+
<div class="flex flex-row items-center gap-2">
|
|
15
|
+
<label>Groups</label>
|
|
16
|
+
<button type="button" @click="$refs.columnSelector.open(obj => addPivot('rows', obj), columns)">
|
|
17
|
+
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
18
|
+
</button>
|
|
19
|
+
</div>
|
|
20
|
+
<ListItem :items="pivot.rows"
|
|
21
|
+
@reorder="(from, to) => { pivot.rows.splice(to, 0, pivot.rows.splice(from, 1)[0]); apply() }"
|
|
22
|
+
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
23
|
+
container-class="divide-y divide-text-50">
|
|
24
|
+
<template v-slot="{ item, index }">
|
|
25
|
+
<div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
|
|
26
|
+
<div data-reorder v-if="(pivot.rows ?? []).length > 1">
|
|
27
|
+
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="flex-1 flex flex-row gap-3">
|
|
30
|
+
<strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
|
|
31
|
+
@click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, columns);">
|
|
32
|
+
{{ item.label ? item.label : item.key }}
|
|
33
|
+
</strong>
|
|
34
|
+
<select v-if="item.type === 'date'"
|
|
35
|
+
v-model="item.aggregrate"
|
|
36
|
+
class="px-1 appearance-none bg-base-300 rounded-md border-[1px] border-text-50 outline-none"
|
|
37
|
+
@change="apply()">
|
|
38
|
+
<option value="hour">Hour</option>
|
|
39
|
+
<option value="date">Date</option>
|
|
40
|
+
<option value="month">Month</option>
|
|
41
|
+
<option value="year">Year</option>
|
|
42
|
+
</select>
|
|
43
|
+
</div>
|
|
44
|
+
<button type="button" @click="pivot.rows.splice(index, 1); apply()">
|
|
45
|
+
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
46
|
+
</button>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
</ListItem>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div>
|
|
53
|
+
<div class="flex flex-row items-center gap-2">
|
|
54
|
+
<label>Aggregrates</label>
|
|
55
|
+
<button type="button" @click="$refs.columnSelector.open(obj => addPivot('values', obj), columns)">
|
|
56
|
+
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
<ListItem :items="pivot.values"
|
|
60
|
+
@reorder="(from, to) => { pivot.values.splice(to, 0, pivot.values.splice(from, 1)[0]); }"
|
|
61
|
+
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
62
|
+
container-class="divide-y divide-text-50">
|
|
63
|
+
<template v-slot="{ item, index }">
|
|
64
|
+
<div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
|
|
65
|
+
<div data-reorder v-if="(pivot.values ?? []).length > 1">
|
|
66
|
+
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="flex-1 flex flex-row gap-3">
|
|
69
|
+
<strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
|
|
70
|
+
@click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, columns);">
|
|
71
|
+
{{ item.label ? item.label : item.key }}
|
|
72
|
+
</strong>
|
|
73
|
+
<select v-model="item.aggregrate"
|
|
74
|
+
class="px-1 appearance-none bg-base-300 w-[80px] rounded-md border-[1px] border-text-50 outline-none"
|
|
75
|
+
@change="apply()">
|
|
76
|
+
<option value="">Default</option>
|
|
77
|
+
<option value="count">Count</option>
|
|
78
|
+
<option value="countDistinct">Distinct Count</option>
|
|
79
|
+
<option v-if="[ 'number' ].includes(item.type)" value="sum">Sum</option>
|
|
80
|
+
<option v-if="[ 'number' ].includes(item.type)" value="avg">Average</option>
|
|
81
|
+
<option v-if="[ 'number' ].includes(item.type)" value="min">Min</option>
|
|
82
|
+
<option v-if="[ 'number' ].includes(item.type)" value="max">Max</option>
|
|
83
|
+
</select>
|
|
84
|
+
</div>
|
|
85
|
+
<button type="button" @click="pivot.values.splice(index, 1); apply()">
|
|
86
|
+
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
87
|
+
</button>
|
|
88
|
+
</div>
|
|
89
|
+
</template>
|
|
90
|
+
</ListItem>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<div>
|
|
94
|
+
<div class="flex flex-row items-center gap-2">
|
|
95
|
+
<label class="flex-1">Columns</label>
|
|
96
|
+
<button v-if="pivot.manualColumns"
|
|
97
|
+
type="button"
|
|
98
|
+
class="text-primary"
|
|
99
|
+
@click="delete pivot.manualColumns; apply()">Reset</button>
|
|
100
|
+
</div>
|
|
101
|
+
<ListItem :items="pivot.columns"
|
|
102
|
+
@reorder="(from, to) => { pivot.columns.splice(to, 0, pivot.columns.splice(from, 1)[0]); pivot.manualColumns = true; apply() }"
|
|
103
|
+
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
104
|
+
container-class="divide-y divide-text-50">
|
|
105
|
+
<template v-slot="{ item, index }">
|
|
106
|
+
<div class="flex flex-row gap-2 items-center px-2 bg-base-500">
|
|
107
|
+
<div data-reorder>
|
|
108
|
+
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
109
|
+
</div>
|
|
110
|
+
<Textbox class="flex-1 border-none" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
|
|
111
|
+
item-class="p-1"/>
|
|
112
|
+
<button type="button" v-if="[ 'number' ].includes(item.type)" @click="">
|
|
113
|
+
<svg width="13" height="13" :class="(item.appearances ?? []).length > 0 ? 'fill-primary' : 'fill-text-300 hover:fill-primary'"
|
|
114
|
+
@click="$refs.presetBarPivotColumnEdit.open(item, next => { Object.assign(item, next); apply() })"
|
|
115
|
+
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M176 0h-128C21.49 0 0 21.49 0 48v128C0 202.5 21.49 224 48 224h128C202.5 224 224 202.5 224 176v-128C224 21.49 202.5 0 176 0zM176 288h-128C21.49 288 0 309.5 0 336v128C0 490.5 21.49 512 48 512h128C202.5 512 224 490.5 224 464v-128C224 309.5 202.5 288 176 288zM464 0h-128C309.5 0 288 21.49 288 48v128C288 202.5 309.5 224 336 224h128C490.5 224 512 202.5 512 176v-128C512 21.49 490.5 0 464 0zM488 376h-64v-64C424 298.8 413.3 288 400 288s-24 10.75-24 24v64h-64c-13.25 0-24 10.75-24 24s10.75 24 24 24h64v64c0 13.25 10.75 24 24 24s24-10.75 24-24v-64h64c13.25 0 24-10.75 24-24S501.3 376 488 376z"/></svg>
|
|
116
|
+
</button>
|
|
117
|
+
<button type="button" @click="pivot.columns.splice(index, 1); pivot.manualColumns = true; apply()">
|
|
118
|
+
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
119
|
+
</button>
|
|
120
|
+
</div>
|
|
121
|
+
</template>
|
|
122
|
+
</ListItem>
|
|
123
|
+
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div class="flex flex-row items-center gap-3">
|
|
127
|
+
<label>Total</label>
|
|
128
|
+
<Switch v-model="pivot.useTotal" @change="apply()"/>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<ColumnSelector ref="columnSelector" />
|
|
134
|
+
|
|
135
|
+
<PresetBarPivotColumnEdit ref="presetBarPivotColumnEdit" />
|
|
136
|
+
|
|
137
|
+
</div>
|
|
138
|
+
</template>
|
|
139
|
+
|
|
140
|
+
<script>
|
|
141
|
+
|
|
142
|
+
import PresetBarPivotColumnEdit from "./PresetBarPivotColumnEdit.vue";
|
|
143
|
+
import ColumnSelector from "./ColumnSelector.vue";
|
|
144
|
+
|
|
145
|
+
export default{
|
|
146
|
+
components: {ColumnSelector, PresetBarPivotColumnEdit},
|
|
147
|
+
|
|
148
|
+
emits: [ 'apply' ],
|
|
149
|
+
|
|
150
|
+
methods: {
|
|
151
|
+
|
|
152
|
+
apply(){
|
|
153
|
+
this.$emit('apply')
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
addPivot(type, obj){
|
|
157
|
+
console.log(this.pivot, type)
|
|
158
|
+
this.pivot[type].push(Object.assign({}, obj))
|
|
159
|
+
this.apply()
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
props:{
|
|
165
|
+
|
|
166
|
+
columns: Array,
|
|
167
|
+
|
|
168
|
+
pivot: Object
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
</script>
|
|
175
|
+
|
|
176
|
+
<style module>
|
|
177
|
+
|
|
178
|
+
.comp{
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.columnTextbox input::placeholder{
|
|
183
|
+
@apply text-text;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
</style>
|