@mixd-id/web-scaffold 0.1.230406346 → 0.1.230406348
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 +256 -0
- package/src/components/List.vue +0 -1
- package/src/components/VirtualTable.vue +2 -2
- package/src/configs/dashboard/gheatmaps.js +9 -0
- package/src/index.js +1 -2
- package/src/utils/dashboard.js +15 -7
- package/src/utils/helpers.js +8 -0
- package/src/utils/preset-selector.js +5 -2
- package/src/widgets/Dashboard/BarChart.vue +129 -34
- package/src/widgets/Dashboard/BarChartSetting.vue +76 -5
- package/src/widgets/Dashboard/DatasourcePreview.vue +22 -8
- package/src/widgets/Dashboard/DatasourceSelector.vue +8 -3
- package/src/widgets/Dashboard/Doughnut.vue +43 -1
- package/src/widgets/Dashboard/DoughnutSetting.vue +78 -5
- package/src/widgets/Dashboard/GHeatMapsSetting.vue +108 -0
- package/src/widgets/Dashboard/InteractionEdit.vue +41 -7
- package/src/widgets/Dashboard/MetricSetting.vue +7 -3
- package/src/widgets/Dashboard/Pie.vue +19 -8
- package/src/widgets/Dashboard/PieSetting.vue +47 -8
- package/src/widgets/Dashboard/PolarArea.vue +60 -4
- package/src/widgets/Dashboard/PolarAreaSetting.vue +80 -3
- package/src/widgets/Dashboard/ViewSelector.vue +1 -0
- package/src/widgets/Dashboard/VirtualTableSetting.vue +23 -12
- package/src/widgets/Dashboard.vue +111 -37
package/package.json
CHANGED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
<div v-if="apiKey" ref="map" class="flex-1"></div>
|
|
4
|
+
<div v-else class="flex-1 flex items-center justify-center text-text-400">{{ $t('Google maps api required') }}</div>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
|
|
10
|
+
import { Loader } from '@googlemaps/js-api-loader';
|
|
11
|
+
|
|
12
|
+
export default{
|
|
13
|
+
|
|
14
|
+
name: "GHeatMaps",
|
|
15
|
+
|
|
16
|
+
props: {
|
|
17
|
+
column: String,
|
|
18
|
+
|
|
19
|
+
value: Object,
|
|
20
|
+
|
|
21
|
+
apiKey: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: 'AIzaSyBmzMlmrR5St-njtN--64y_oLTa9FDLYfQ'
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
data(){
|
|
28
|
+
return {
|
|
29
|
+
map: null,
|
|
30
|
+
zoom: 4,
|
|
31
|
+
center: null,
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
mounted() {
|
|
36
|
+
this.load()
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
methods: {
|
|
40
|
+
|
|
41
|
+
load(){
|
|
42
|
+
if(!this.apiKey) return
|
|
43
|
+
if(!Array.isArray(this.datasets) || this.datasets.length < 1)
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
const loader = new Loader({
|
|
47
|
+
apiKey: this.apiKey // "AIzaSyBmzMlmrR5St-njtN--64y_oLTa9FDLYfQ"
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
loader.load()
|
|
51
|
+
.then(async () => {
|
|
52
|
+
|
|
53
|
+
const { Map } = await google.maps.importLibrary([ "maps" ]);
|
|
54
|
+
await google.maps.importLibrary("visualization", ["HeatmapLayer"]);
|
|
55
|
+
|
|
56
|
+
var center = new google.maps.LatLng(
|
|
57
|
+
this.center ? this.center[0] : -6.2088,
|
|
58
|
+
this.center ? this.center[1] : 106.8456);
|
|
59
|
+
|
|
60
|
+
this.map = new Map(this.$refs.map, {
|
|
61
|
+
center: center,
|
|
62
|
+
zoom: this.zoom ?? 4,
|
|
63
|
+
mapTypeId: 'roadmap',
|
|
64
|
+
streetViewControl: false,
|
|
65
|
+
keyboardShortcuts: false,
|
|
66
|
+
styles: [
|
|
67
|
+
{ elementType: "geometry", stylers: [{ color: "#242f3e" }] },
|
|
68
|
+
{ elementType: "labels.text.stroke", stylers: [{ color: "#242f3e" }] },
|
|
69
|
+
{ elementType: "labels.text.fill", stylers: [{ color: "#746855" }] },
|
|
70
|
+
{
|
|
71
|
+
featureType: "administrative.locality",
|
|
72
|
+
elementType: "labels.text.fill",
|
|
73
|
+
stylers: [{ color: "#d59563" }],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
featureType: "poi",
|
|
77
|
+
elementType: "labels.text.fill",
|
|
78
|
+
stylers: [{ color: "#d59563" }],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
featureType: "poi.park",
|
|
82
|
+
elementType: "geometry",
|
|
83
|
+
stylers: [{ color: "#263c3f" }],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
featureType: "poi.park",
|
|
87
|
+
elementType: "labels.text.fill",
|
|
88
|
+
stylers: [{ color: "#6b9a76" }],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
featureType: "road",
|
|
92
|
+
elementType: "geometry",
|
|
93
|
+
stylers: [{ color: "#38414e" }],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
featureType: "road",
|
|
97
|
+
elementType: "geometry.stroke",
|
|
98
|
+
stylers: [{ color: "#212a37" }],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
featureType: "road",
|
|
102
|
+
elementType: "labels.text.fill",
|
|
103
|
+
stylers: [{ color: "#9ca5b3" }],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
featureType: "road.highway",
|
|
107
|
+
elementType: "geometry",
|
|
108
|
+
stylers: [{ color: "#746855" }],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
featureType: "road.highway",
|
|
112
|
+
elementType: "geometry.stroke",
|
|
113
|
+
stylers: [{ color: "#1f2835" }],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
featureType: "road.highway",
|
|
117
|
+
elementType: "labels.text.fill",
|
|
118
|
+
stylers: [{ color: "#f3d19c" }],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
featureType: "transit",
|
|
122
|
+
elementType: "geometry",
|
|
123
|
+
stylers: [{ color: "#2f3948" }],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
featureType: "transit.station",
|
|
127
|
+
elementType: "labels.text.fill",
|
|
128
|
+
stylers: [{ color: "#d59563" }],
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
featureType: "water",
|
|
132
|
+
elementType: "geometry",
|
|
133
|
+
stylers: [{ color: "#17263c" }],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
featureType: "water",
|
|
137
|
+
elementType: "labels.text.fill",
|
|
138
|
+
stylers: [{ color: "#515c6d" }],
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
featureType: "water",
|
|
142
|
+
elementType: "labels.text.stroke",
|
|
143
|
+
stylers: [{ color: "#17263c" }],
|
|
144
|
+
},
|
|
145
|
+
]
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
google.maps.event.addListener(this.map, 'zoom_changed', () => {
|
|
149
|
+
this.zoom = this.map.getZoom();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
google.maps.event.addListener(this.map, 'center_changed', () => {
|
|
153
|
+
this.center = [
|
|
154
|
+
this.map.getCenter().lat(),
|
|
155
|
+
this.map.getCenter().lng()
|
|
156
|
+
]
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
var heatMapData = [
|
|
160
|
+
/*{location: new google.maps.LatLng(37.782, -122.447), weight: 0.5},
|
|
161
|
+
new google.maps.LatLng(37.782, -122.445),
|
|
162
|
+
{location: new google.maps.LatLng(37.782, -122.443), weight: 2},
|
|
163
|
+
{location: new google.maps.LatLng(37.782, -122.441), weight: 3},
|
|
164
|
+
{location: new google.maps.LatLng(37.782, -122.439), weight: 2},
|
|
165
|
+
new google.maps.LatLng(37.782, -122.437),
|
|
166
|
+
{location: new google.maps.LatLng(37.782, -122.435), weight: 0.5},
|
|
167
|
+
|
|
168
|
+
{location: new google.maps.LatLng(37.785, -122.447), weight: 3},
|
|
169
|
+
{location: new google.maps.LatLng(37.785, -122.445), weight: 2},
|
|
170
|
+
new google.maps.LatLng(37.785, -122.443),
|
|
171
|
+
{location: new google.maps.LatLng(37.785, -122.441), weight: 0.5},
|
|
172
|
+
new google.maps.LatLng(37.785, -122.439),
|
|
173
|
+
{location: new google.maps.LatLng(37.785, -122.437), weight: 2},
|
|
174
|
+
{location: new google.maps.LatLng(37.785, -122.435), weight: 3}*/
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
this.datasets.forEach((item) => {
|
|
178
|
+
if(item[0] && item[1] && item[2]){
|
|
179
|
+
heatMapData.push({
|
|
180
|
+
location: new google.maps.LatLng(item[0], item[1]),
|
|
181
|
+
weight: item[2]
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
var heatmap = new google.maps.visualization.HeatmapLayer({
|
|
187
|
+
data: heatMapData,
|
|
188
|
+
dissipating: true
|
|
189
|
+
});
|
|
190
|
+
heatmap.set('radius', parseInt(this.mapRadius ?? 12))
|
|
191
|
+
heatmap.setMap(this.map);
|
|
192
|
+
|
|
193
|
+
const gradient = [
|
|
194
|
+
"rgba(0, 255, 255, 0)",
|
|
195
|
+
"rgba(0, 255, 255, 1)",
|
|
196
|
+
"rgba(0, 191, 255, 1)",
|
|
197
|
+
"rgba(0, 127, 255, 1)",
|
|
198
|
+
"rgba(0, 63, 255, 1)",
|
|
199
|
+
"rgba(0, 0, 255, 1)",
|
|
200
|
+
"rgba(0, 0, 223, 1)",
|
|
201
|
+
"rgba(0, 0, 191, 1)",
|
|
202
|
+
"rgba(0, 0, 159, 1)",
|
|
203
|
+
"rgba(0, 0, 127, 1)",
|
|
204
|
+
"rgba(63, 0, 91, 1)",
|
|
205
|
+
"rgba(127, 0, 63, 1)",
|
|
206
|
+
"rgba(191, 0, 31, 1)",
|
|
207
|
+
"rgba(255, 0, 0, 1)",
|
|
208
|
+
];
|
|
209
|
+
heatmap.set("gradient", gradient);
|
|
210
|
+
|
|
211
|
+
//console.log('Gmap, data count:', this.data.length)
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
computed: {
|
|
218
|
+
|
|
219
|
+
datasets(){
|
|
220
|
+
if(!Array.isArray(this.value?.items)) return []
|
|
221
|
+
|
|
222
|
+
const grouped = this.value.items.reduce((acc, item) => {
|
|
223
|
+
if(!acc[item[this.column]]) acc[item[this.column]] = 0
|
|
224
|
+
acc[item[this.column]] += 1
|
|
225
|
+
return acc
|
|
226
|
+
}, {})
|
|
227
|
+
|
|
228
|
+
const datasets = []
|
|
229
|
+
for(let coord in grouped){
|
|
230
|
+
datasets.push([parseFloat(coord.split(',')[0]), parseFloat(coord.split(',')[1]), grouped[coord]])
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return datasets
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
watch: {
|
|
239
|
+
|
|
240
|
+
datasets(){
|
|
241
|
+
this.load()
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
</script>
|
|
249
|
+
|
|
250
|
+
<style module>
|
|
251
|
+
|
|
252
|
+
.comp{
|
|
253
|
+
@apply flex flex-col h-[40vh] bg-base-500;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
</style>
|
package/src/components/List.vue
CHANGED
|
@@ -573,8 +573,8 @@ export default{
|
|
|
573
573
|
enumText = typeParam && typeParam.text ? typeParam.text : enumText
|
|
574
574
|
}
|
|
575
575
|
|
|
576
|
-
if(this.enumCache && this.enumCache[column.key] && this.enumCache[column.key][value]){
|
|
577
|
-
enumText = this.enumCache[column.key][value].text ?? enumText
|
|
576
|
+
else if(this.enumCache && this.enumCache[column.key] && this.enumCache[column.key][value?.toString()]){
|
|
577
|
+
enumText = this.enumCache[column.key][value?.toString()].text ?? enumText
|
|
578
578
|
}
|
|
579
579
|
|
|
580
580
|
text = enumText ? enumText : text
|
package/src/index.js
CHANGED
|
@@ -336,8 +336,6 @@ export default{
|
|
|
336
336
|
app.directive('tooltip', (el, binding) => {
|
|
337
337
|
if(!binding.value) return
|
|
338
338
|
|
|
339
|
-
console.log(binding)
|
|
340
|
-
|
|
341
339
|
if(!el.getAttribute('data-tooltip')) {
|
|
342
340
|
|
|
343
341
|
const uid = uniqid()
|
|
@@ -528,6 +526,7 @@ export default{
|
|
|
528
526
|
app.component('ErrorText', defineAsyncComponent(() => import("./components/ErrorText.vue")))
|
|
529
527
|
app.component('Feed', defineAsyncComponent(() => import("./components/Feed.vue")))
|
|
530
528
|
app.component('Gmaps', defineAsyncComponent(() => import("./components/Gmaps.vue")))
|
|
529
|
+
app.component('GHeatMaps', defineAsyncComponent(() => import("./components/GHeatMaps.vue")))
|
|
531
530
|
app.component('HTMLEditor', defineAsyncComponent(() => import("./components/HTMLEditor.vue")))
|
|
532
531
|
app.component('Switch', defineAsyncComponent(() => import("./components/Switch.vue")))
|
|
533
532
|
app.component('IconMenu', defineAsyncComponent(() => import("./components/IconMenu.vue")))
|
package/src/utils/dashboard.js
CHANGED
|
@@ -45,15 +45,23 @@ const backgroundColors = [
|
|
|
45
45
|
]
|
|
46
46
|
|
|
47
47
|
const getModelFromDatasource = async (datasource, opt) => {
|
|
48
|
-
if(!opt.conn.models[datasource.datasourceUid]){
|
|
49
|
-
const tableColumns = await getSequelizeColumns(datasource.columns, opt)
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
switch(datasource.type){
|
|
50
|
+
|
|
51
|
+
case 2:
|
|
52
|
+
return opt.conn.models[datasource.key]
|
|
53
|
+
|
|
54
|
+
default:
|
|
55
|
+
if(!opt.conn.models[datasource.datasourceUid]){
|
|
56
|
+
const tableColumns = await getSequelizeColumns(datasource.columns, opt)
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
opt.conn.define(datasource.datasourceUid, tableColumns, {
|
|
59
|
+
tableName: `datasource_${datasource.datasourceUid}`
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return opt.conn.models[datasource.datasourceUid]
|
|
64
|
+
}
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
const getDatasourceItems = async (datasource, opt) => {
|
package/src/utils/helpers.js
CHANGED
|
@@ -524,8 +524,16 @@ const dayTimeRange = (params, value) => {
|
|
|
524
524
|
})
|
|
525
525
|
}
|
|
526
526
|
|
|
527
|
+
function capitalize(str) {
|
|
528
|
+
return (str ?? '')
|
|
529
|
+
.toString()
|
|
530
|
+
.split(' ')
|
|
531
|
+
.map(_ => _.charAt(0).toUpperCase() + _.slice(1).toLowerCase())
|
|
532
|
+
.join(' ')
|
|
533
|
+
}
|
|
527
534
|
|
|
528
535
|
module.exports = {
|
|
536
|
+
capitalize,
|
|
529
537
|
ceil,
|
|
530
538
|
floor,
|
|
531
539
|
ftWildcard,
|
|
@@ -1270,9 +1270,11 @@ const presetToSequelizeList = async(preset, {
|
|
|
1270
1270
|
order:initialOrder
|
|
1271
1271
|
}) => {
|
|
1272
1272
|
|
|
1273
|
+
const updatedAtField = model.rawAttributes['updatedAt'] ?? model.rawAttributes['updated_at']
|
|
1274
|
+
|
|
1273
1275
|
if(!initialOrder){
|
|
1274
1276
|
initialOrder = [
|
|
1275
|
-
[
|
|
1277
|
+
[ updatedAtField.fieldName, 'desc' ],
|
|
1276
1278
|
[ 'id', 'desc' ],
|
|
1277
1279
|
]
|
|
1278
1280
|
}
|
|
@@ -1381,7 +1383,8 @@ const presetToSequelizeList = async(preset, {
|
|
|
1381
1383
|
...replacements,
|
|
1382
1384
|
...filterReplacements,
|
|
1383
1385
|
...searchReplacements
|
|
1384
|
-
]
|
|
1386
|
+
],
|
|
1387
|
+
itemsPerPage
|
|
1385
1388
|
}
|
|
1386
1389
|
}
|
|
1387
1390
|
}
|
|
@@ -1,20 +1,67 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="$style.comp"
|
|
2
|
+
<div :class="$style.comp">
|
|
3
3
|
|
|
4
|
-
<
|
|
4
|
+
<div v-if="readyState === 2" class="flex-1 flex">
|
|
5
|
+
<div :style="barStyles" class="flex-1 flex items-center justify-center">
|
|
6
|
+
<svg class="animate-spin aspect-square w-[24px] h-[24px]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
5
9
|
|
|
6
|
-
<div class="flex-1">
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
<div v-else-if="isError" class="flex-1 flex">
|
|
11
|
+
<div :style="barStyles" class="flex-1 flex items-center justify-center">
|
|
12
|
+
<p class="text-text-300">{{ value.message }}</p>
|
|
13
|
+
</div>
|
|
10
14
|
</div>
|
|
11
15
|
|
|
12
|
-
<div v-
|
|
13
|
-
<div
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
<div v-else class="flex flex-col gap-3">
|
|
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 v-if="yAxeMultiple && yLegends?.length > 0" class="flex flex-row items-center flex-wrap justify-center gap-1">
|
|
20
|
+
<div v-for="yLegend in showedYLegends"
|
|
21
|
+
v-tooltip="`${yLegend.key}`"
|
|
22
|
+
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"
|
|
23
|
+
:style="{ backgroundColor:yLegend.color }">
|
|
24
|
+
{{ (yLegend.key ?? '').toString().split(' ')[0].toLowerCase() }}
|
|
25
|
+
</div>
|
|
26
|
+
<button v-if="yLegends.length > showedYLegends.length" @click="$refs.legendModal.open()"
|
|
27
|
+
class="bg-text-200 hover:bg-primary-600 w-[21px] h-[21px] rounded-full flex items-center justify-center">
|
|
28
|
+
<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>
|
|
29
|
+
</button>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="flex-1">
|
|
34
|
+
<Bar :style="barStyles"
|
|
35
|
+
:options="chartOptions"
|
|
36
|
+
:data="chartData"/>
|
|
17
37
|
</div>
|
|
38
|
+
|
|
39
|
+
<Modal ref="legendModal" width="320" height="360" :dismissable="true" @dismiss="$refs.legendModal.close()">
|
|
40
|
+
<template v-slot:head>
|
|
41
|
+
<div class="relative p-5">
|
|
42
|
+
<h3>Legend</h3>
|
|
43
|
+
<div class="absolute top-0 right-0 p-2">
|
|
44
|
+
<button type="button" class="p-2" @click="$refs.legendModal.close()">
|
|
45
|
+
<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">
|
|
46
|
+
<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"/>
|
|
47
|
+
</svg>
|
|
48
|
+
</button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
<div class="flex-1 p-5 pt-0">
|
|
53
|
+
|
|
54
|
+
<div class="flex flex-col divide-y divide-text-50">
|
|
55
|
+
<div v-for="yLegend in yLegends" class="flex flex-row items-center gap-2 py-2">
|
|
56
|
+
<div class="w-[24px] h-[24px] rounded-full" :style="{ backgroundColor:yLegend.color }"></div>
|
|
57
|
+
<div class="flex-1 text-ellipsis whitespace-nowrap overflow-hidden">{{ yLegend.key }}</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<br />
|
|
62
|
+
|
|
63
|
+
</div>
|
|
64
|
+
</Modal>
|
|
18
65
|
</div>
|
|
19
66
|
|
|
20
67
|
</div>
|
|
@@ -25,7 +72,7 @@
|
|
|
25
72
|
import {Bar} from 'vue-chartjs'
|
|
26
73
|
import Chart from 'chart.js/auto'
|
|
27
74
|
import { color } from 'chart.js/helpers'
|
|
28
|
-
import {
|
|
75
|
+
import {strVars} from "../../utils/helpers.mjs";
|
|
29
76
|
|
|
30
77
|
export default{
|
|
31
78
|
|
|
@@ -51,7 +98,7 @@ export default{
|
|
|
51
98
|
datasets: this.value.datasets.map(_ => {
|
|
52
99
|
return {
|
|
53
100
|
..._,
|
|
54
|
-
borderWidth:
|
|
101
|
+
borderWidth: 0,
|
|
55
102
|
borderColor: function(context, options) {
|
|
56
103
|
const hex = options.color;
|
|
57
104
|
return color(hex).darken(0.5).rgbString()
|
|
@@ -76,7 +123,7 @@ export default{
|
|
|
76
123
|
return `${tooltipItems[0].label}`;
|
|
77
124
|
},
|
|
78
125
|
label: (tooltipItem) => {
|
|
79
|
-
if(this.usePercentage)
|
|
126
|
+
if(this.yAxeMultiple && this.usePercentage)
|
|
80
127
|
return `${tooltipItem.dataset.label}: ${tooltipItem.dataset.data0[tooltipItem.dataIndex]} (${tooltipItem.raw}%)`
|
|
81
128
|
return `${tooltipItem.dataset.label}: ${tooltipItem.raw}`;
|
|
82
129
|
}
|
|
@@ -94,10 +141,13 @@ export default{
|
|
|
94
141
|
ticks: {
|
|
95
142
|
callback: function(value) {
|
|
96
143
|
const label = this.getLabelForValue(value) ?? '';
|
|
97
|
-
return label.length > 10 ? label.slice(0,
|
|
144
|
+
return label.length > 10 ? label.slice(0, 30) + '...' : label;
|
|
98
145
|
},
|
|
99
146
|
minRotation: 0,
|
|
100
|
-
maxRotation: 0
|
|
147
|
+
maxRotation: 0,
|
|
148
|
+
font: {
|
|
149
|
+
size: 11
|
|
150
|
+
}
|
|
101
151
|
},
|
|
102
152
|
stacked: !!this.stacked,
|
|
103
153
|
},
|
|
@@ -105,6 +155,9 @@ export default{
|
|
|
105
155
|
beginAtZero: true,
|
|
106
156
|
ticks: {
|
|
107
157
|
display: !this.yAxeMultiple || this.usePercentage,
|
|
158
|
+
font: {
|
|
159
|
+
size: 11,
|
|
160
|
+
},
|
|
108
161
|
},
|
|
109
162
|
grid: {
|
|
110
163
|
display: true,
|
|
@@ -112,25 +165,24 @@ export default{
|
|
|
112
165
|
return `rgba(255,255,255, .1)`
|
|
113
166
|
}
|
|
114
167
|
},
|
|
115
|
-
stacked: !!this.stacked
|
|
168
|
+
stacked: !!this.stacked
|
|
116
169
|
}
|
|
117
170
|
},
|
|
118
|
-
onClick:
|
|
119
|
-
console.log(evt);
|
|
120
|
-
console.log(evt2);
|
|
121
|
-
}
|
|
171
|
+
onClick: this.onClick
|
|
122
172
|
}
|
|
123
173
|
},
|
|
124
174
|
|
|
125
|
-
|
|
126
|
-
return this.
|
|
127
|
-
this.datasource.keys[this.datasourceUid] :
|
|
128
|
-
this.value
|
|
175
|
+
isError(){
|
|
176
|
+
return this.value?.error === 1
|
|
129
177
|
},
|
|
130
178
|
|
|
131
179
|
yLegends(){
|
|
132
180
|
return this.value?.yLegends ?? []
|
|
133
|
-
}
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
showedYLegends(){
|
|
184
|
+
return this.yLegends.slice(0, 5)
|
|
185
|
+
},
|
|
134
186
|
|
|
135
187
|
},
|
|
136
188
|
|
|
@@ -150,9 +202,57 @@ export default{
|
|
|
150
202
|
],
|
|
151
203
|
|
|
152
204
|
datasets: null,
|
|
205
|
+
|
|
206
|
+
readyState: 1,
|
|
153
207
|
}
|
|
154
208
|
},
|
|
155
209
|
|
|
210
|
+
inject: [ 'selectPreset' ],
|
|
211
|
+
|
|
212
|
+
methods: {
|
|
213
|
+
|
|
214
|
+
onClick(e, segments){
|
|
215
|
+
|
|
216
|
+
const clickInteractions = (this.interactions ?? []).filter(_ => _.event === 'click')
|
|
217
|
+
const segment = segments[0]
|
|
218
|
+
if(!segment) return
|
|
219
|
+
|
|
220
|
+
const dataset = this.value.datasets[segment.datasetIndex]
|
|
221
|
+
const obj = {
|
|
222
|
+
segment: this.value.labels[segment.index],
|
|
223
|
+
key: dataset.label,
|
|
224
|
+
value: dataset.data[segment.index]
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
for(let click of clickInteractions){
|
|
228
|
+
const { action, presetUid, filters } = click
|
|
229
|
+
|
|
230
|
+
const params = filters.reduce((res, cur) => {
|
|
231
|
+
res[cur.datasourceUid + '.filters.' + cur.key + '.' + cur.operator] = strVars(cur.value, obj)
|
|
232
|
+
return res
|
|
233
|
+
}, {})
|
|
234
|
+
|
|
235
|
+
switch(action){
|
|
236
|
+
|
|
237
|
+
case 'openDashboardPreset':
|
|
238
|
+
if(typeof this.selectPreset === 'function')
|
|
239
|
+
this.selectPreset(presetUid, params)
|
|
240
|
+
break
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
resetState(){
|
|
247
|
+
this.setState(1)
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
setState(state){
|
|
251
|
+
this.readyState = state
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
},
|
|
255
|
+
|
|
156
256
|
props: {
|
|
157
257
|
|
|
158
258
|
datasourceUid: String,
|
|
@@ -177,15 +277,10 @@ export default{
|
|
|
177
277
|
|
|
178
278
|
yAxeOnClick: Array,
|
|
179
279
|
|
|
180
|
-
value: Object
|
|
280
|
+
value: Object,
|
|
181
281
|
|
|
182
|
-
|
|
282
|
+
interactions: Array
|
|
183
283
|
|
|
184
|
-
setup(){
|
|
185
|
-
const datasource = useDatasource()
|
|
186
|
-
return {
|
|
187
|
-
datasource
|
|
188
|
-
}
|
|
189
284
|
},
|
|
190
285
|
|
|
191
286
|
}
|
|
@@ -196,7 +291,7 @@ export default{
|
|
|
196
291
|
|
|
197
292
|
.comp{
|
|
198
293
|
@apply border-[1px] border-text-50 bg-base-500 rounded-lg;
|
|
199
|
-
@apply p-3;
|
|
294
|
+
@apply p-3 flex flex-col;
|
|
200
295
|
}
|
|
201
296
|
|
|
202
297
|
</style>
|