@mixd-id/web-scaffold 0.1.230406366 → 0.1.230406367
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/configs/dashboard/data-table.js +9 -0
- package/src/index.js +1 -0
- package/src/utils/dashboard.js +1 -0
- package/src/utils/wss.js +0 -1
- package/src/widgets/Dashboard/BarChart.vue +42 -7
- package/src/widgets/Dashboard/DataTable.vue +125 -0
- package/src/widgets/Dashboard/DataTableSetting.vue +239 -0
- package/src/widgets/Dashboard/Doughnut.vue +47 -6
- package/src/widgets/Dashboard/DoughnutSetting.vue +1 -1
- package/src/widgets/Dashboard/Metric.vue +98 -13
- package/src/widgets/Dashboard/MetricSetting.vue +80 -27
- package/src/widgets/Dashboard/Pie.vue +52 -4
- package/src/widgets/Dashboard/PolarArea.vue +46 -5
- package/src/widgets/Dashboard/ViewSelector.vue +1 -1
- package/src/widgets/Dashboard.vue +25 -4
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -679,6 +679,7 @@ export default{
|
|
|
679
679
|
app.component('PolarArea', defineAsyncComponent(() => import("./widgets/Dashboard/PolarArea.vue")))
|
|
680
680
|
app.component('Metric', defineAsyncComponent(() => import("./widgets/Dashboard/Metric.vue")))
|
|
681
681
|
app.component('BarChart', defineAsyncComponent(() => import("./widgets/Dashboard/BarChart.vue")))
|
|
682
|
+
app.component('DataTable', defineAsyncComponent(() => import("./widgets/Dashboard/DataTable.vue")))
|
|
682
683
|
|
|
683
684
|
app.component('BotEditor', defineAsyncComponent(() => import("./widgets/BotEditor.vue")))
|
|
684
685
|
}
|
package/src/utils/dashboard.js
CHANGED
package/src/utils/wss.js
CHANGED
|
@@ -247,7 +247,6 @@ class WSS extends EventEmitter2{
|
|
|
247
247
|
socket.close(1002, 'ping timeout')
|
|
248
248
|
if(subscriber){
|
|
249
249
|
subscriber.disconnect()
|
|
250
|
-
console.log('CLOSE SOCKET', token.substring(0, 10) + '...')
|
|
251
250
|
}
|
|
252
251
|
else{
|
|
253
252
|
console.log('CLOSE SOCKET#2', token.substring(0, 10) + '...')
|
|
@@ -74,7 +74,7 @@ import {Bar} from 'vue-chartjs'
|
|
|
74
74
|
import Chart from 'chart.js/auto'
|
|
75
75
|
import { color } from 'chart.js/helpers'
|
|
76
76
|
import {strVars} from "../../utils/helpers.mjs";
|
|
77
|
-
import {
|
|
77
|
+
import {useEmitter} from "../../utils/event-bus";
|
|
78
78
|
|
|
79
79
|
export default{
|
|
80
80
|
|
|
@@ -225,14 +225,43 @@ export default{
|
|
|
225
225
|
],
|
|
226
226
|
|
|
227
227
|
height: '',
|
|
228
|
-
datasets: null
|
|
228
|
+
datasets: null,
|
|
229
|
+
readyState: 1,
|
|
230
|
+
value: null
|
|
229
231
|
}
|
|
230
232
|
},
|
|
231
233
|
|
|
232
|
-
inject: [ 'selectPreset' ],
|
|
234
|
+
inject: [ 'getSrc', 'getViewedPreset', 'getQueryFilters', 'selectPreset', 'socket' ],
|
|
233
235
|
|
|
234
236
|
methods: {
|
|
235
237
|
|
|
238
|
+
load(){
|
|
239
|
+
const preset = this.getViewedPreset()
|
|
240
|
+
const {name, datasource} = preset
|
|
241
|
+
|
|
242
|
+
this.readyState = 2
|
|
243
|
+
this.socket.send(this.getSrc(), {
|
|
244
|
+
name,
|
|
245
|
+
views: [{
|
|
246
|
+
...this.$props,
|
|
247
|
+
type: 'BarChart'
|
|
248
|
+
}],
|
|
249
|
+
datasource: datasource.map(_datasource => {
|
|
250
|
+
return {
|
|
251
|
+
..._datasource,
|
|
252
|
+
filters: [
|
|
253
|
+
...(_datasource.filters ?? []),
|
|
254
|
+
...(this.getQueryFilters()[_datasource.uid] ?? [])
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
})
|
|
259
|
+
.then(_ => {
|
|
260
|
+
this.value = _[this.uid]
|
|
261
|
+
})
|
|
262
|
+
.finally(_ => this.readyState = 1)
|
|
263
|
+
},
|
|
264
|
+
|
|
236
265
|
onClick(e, segments){
|
|
237
266
|
|
|
238
267
|
const clickInteractions = (this.interactions ?? []).filter(_ => _.event === 'click')
|
|
@@ -276,9 +305,17 @@ export default{
|
|
|
276
305
|
|
|
277
306
|
mounted() {
|
|
278
307
|
this.height = this.$el.clientHeight + 'px'
|
|
279
|
-
},
|
|
280
308
|
|
|
281
|
-
|
|
309
|
+
this.load()
|
|
310
|
+
|
|
311
|
+
this.emitter = useEmitter()
|
|
312
|
+
this.emitter.on(`${this.uid}.load`, () => {
|
|
313
|
+
this.load()
|
|
314
|
+
})
|
|
315
|
+
this.emitter.on(`dashboard.load`, () => {
|
|
316
|
+
this.load()
|
|
317
|
+
})
|
|
318
|
+
},
|
|
282
319
|
|
|
283
320
|
props: {
|
|
284
321
|
|
|
@@ -309,8 +346,6 @@ export default{
|
|
|
309
346
|
|
|
310
347
|
yAxeOnClick: Array,
|
|
311
348
|
|
|
312
|
-
value: Object,
|
|
313
|
-
|
|
314
349
|
interactions: Array,
|
|
315
350
|
|
|
316
351
|
uid: String
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
<VirtualTable class="flex-1"
|
|
4
|
+
:columns="datasourceColumns"
|
|
5
|
+
@scroll-end="loadNext"
|
|
6
|
+
:items="items">
|
|
7
|
+
|
|
8
|
+
</VirtualTable>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
import {useEmitter} from "../../utils/event-bus";
|
|
14
|
+
import VirtualTable from "../../components/VirtualTable.vue";
|
|
15
|
+
|
|
16
|
+
export default{
|
|
17
|
+
components: {VirtualTable},
|
|
18
|
+
|
|
19
|
+
data(){
|
|
20
|
+
return {
|
|
21
|
+
value: null,
|
|
22
|
+
readyState: 1,
|
|
23
|
+
items: null,
|
|
24
|
+
hasNext: false
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
inject: [ 'getSrc', 'getViewedPreset', 'getQueryFilters', 'socket' ],
|
|
29
|
+
|
|
30
|
+
methods: {
|
|
31
|
+
|
|
32
|
+
load(){
|
|
33
|
+
const preset = this.getViewedPreset()
|
|
34
|
+
const {name, datasource} = preset
|
|
35
|
+
|
|
36
|
+
this.readyState = 2
|
|
37
|
+
this.socket.send(this.getSrc(), {
|
|
38
|
+
name,
|
|
39
|
+
views: [{
|
|
40
|
+
...this.$props,
|
|
41
|
+
type: 'DataTable'
|
|
42
|
+
}],
|
|
43
|
+
datasource: datasource.map(_datasource => {
|
|
44
|
+
return {
|
|
45
|
+
..._datasource,
|
|
46
|
+
filters: [
|
|
47
|
+
...(_datasource.filters ?? []),
|
|
48
|
+
...(this.getQueryFilters()[_datasource.uid] ?? [])
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
.then(_ => {
|
|
54
|
+
const { items, hasNext } = _[this.uid] ?? {}
|
|
55
|
+
this.items = items
|
|
56
|
+
this.hasNext = hasNext
|
|
57
|
+
})
|
|
58
|
+
.finally(_ => this.readyState = 1)
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
loadNext(){
|
|
62
|
+
if(!this.hasNext) return
|
|
63
|
+
|
|
64
|
+
const preset = this.getViewedPreset()
|
|
65
|
+
const {name, datasource} = preset
|
|
66
|
+
const afterItem = this.items[this.items.length - 1]
|
|
67
|
+
|
|
68
|
+
this.socket.send(this.getSrc(), {
|
|
69
|
+
name,
|
|
70
|
+
views: [{
|
|
71
|
+
...this.$props,
|
|
72
|
+
type: 'DataTable',
|
|
73
|
+
afterItem
|
|
74
|
+
}],
|
|
75
|
+
datasource: datasource.map(_datasource => {
|
|
76
|
+
return {
|
|
77
|
+
..._datasource,
|
|
78
|
+
filters: [
|
|
79
|
+
...(_datasource.filters ?? []),
|
|
80
|
+
...(this.getQueryFilters()[_datasource.uid] ?? [])
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
.then(_ => {
|
|
86
|
+
const { items, hasNext } = _[this.uid] ?? {}
|
|
87
|
+
this.items.push(...items)
|
|
88
|
+
this.hasNext = hasNext
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
mounted() {
|
|
95
|
+
this.load()
|
|
96
|
+
|
|
97
|
+
this.emitter = useEmitter()
|
|
98
|
+
this.emitter.on(`${this.uid}.load`, () => {
|
|
99
|
+
this.load()
|
|
100
|
+
})
|
|
101
|
+
this.emitter.on(`dashboard.load`, () => {
|
|
102
|
+
this.load()
|
|
103
|
+
})
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
props: {
|
|
107
|
+
|
|
108
|
+
datasourceColumns: Array,
|
|
109
|
+
datasourceUid: String,
|
|
110
|
+
label: String,
|
|
111
|
+
uid: String,
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<style module>
|
|
120
|
+
|
|
121
|
+
.comp{
|
|
122
|
+
@apply min-h-[50vh] flex flex-col;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
</style>
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
|
|
4
|
+
<div class="flex justify-center border-b-[1px] border-text-50" v-if="tabItems.length > 1">
|
|
5
|
+
<Tabs :items="tabItems" v-model="value.tabIndex" />
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div class="flex-1 overflow-y-auto flex flex-col">
|
|
9
|
+
<div v-if="value.tabIndex === 1" class="flex-1 flex flex-col gap-5 p-6">
|
|
10
|
+
|
|
11
|
+
<div class="flex flex-row items-center ">
|
|
12
|
+
<label class="flex-1">Active</label>
|
|
13
|
+
<Switch v-model="value.props.enabled" :readonly="readonly" />
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="flex flex-col gap-1">
|
|
17
|
+
<label class="text-text-400">Label</label>
|
|
18
|
+
<Textbox v-model="value.props.label" maxlength="50" placeholder="Label" :readonly="readonly" />
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="flex flex-row items-center">
|
|
22
|
+
<label class="flex-1">Datasource</label>
|
|
23
|
+
<div>
|
|
24
|
+
<Dropdown class="min-w-[150px]"
|
|
25
|
+
:readonly="readonly"
|
|
26
|
+
v-model="value.props.datasourceUid">
|
|
27
|
+
<option v-for="_datasource in datasource"
|
|
28
|
+
:value="_datasource.uid">
|
|
29
|
+
{{ _datasource.name }}
|
|
30
|
+
</option>
|
|
31
|
+
</Dropdown>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div v-else-if="value.tabIndex === 2" class="flex-1 flex flex-col gap-5 p-6">
|
|
38
|
+
|
|
39
|
+
<div>
|
|
40
|
+
<Textbox placeholder="Search..." v-model="search">
|
|
41
|
+
<template #start>
|
|
42
|
+
<div class="pl-3">
|
|
43
|
+
<svg width="14" height="14" class="fill-text-300" 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="M500.3 443.7l-119.7-119.7c27.22-40.41 40.65-90.9 33.46-144.7C401.8 87.79 326.8 13.32 235.2 1.723C99.01-15.51-15.51 99.01 1.724 235.2c11.6 91.64 86.08 166.7 177.6 178.9c53.8 7.189 104.3-6.236 144.7-33.46l119.7 119.7c15.62 15.62 40.95 15.62 56.57 0C515.9 484.7 515.9 459.3 500.3 443.7zM79.1 208c0-70.58 57.42-128 128-128s128 57.42 128 128c0 70.58-57.42 128-128 128S79.1 278.6 79.1 208z"/></svg>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
</Textbox>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<VirtualGrid class="flex-1 border-[1px] border-text-50 rounded-xl"
|
|
50
|
+
container-class="divide-y divide-text-50"
|
|
51
|
+
:items="columns">
|
|
52
|
+
<template #item="{ item }">
|
|
53
|
+
<div class="flex-1 flex flex-row gap-2 items-center p-1 px-3 group">
|
|
54
|
+
<div>
|
|
55
|
+
<Checkbox v-model="item.visible"
|
|
56
|
+
default="true"
|
|
57
|
+
:disabled="readonly"
|
|
58
|
+
@change="$emit('change')" />
|
|
59
|
+
</div>
|
|
60
|
+
<Textbox v-model="item.label2" :placeholder="item.label" :readonly="readonly"
|
|
61
|
+
class="flex-1 border-none bg-transparent" :class="$style.columnTextbox"
|
|
62
|
+
item-class="p-1 px-0" />
|
|
63
|
+
<div class="hidden flex-col justify-center group-hover:flex">
|
|
64
|
+
<button type="button" @click="moveUp(item)">
|
|
65
|
+
<svg width="11" height="11" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M9.39 265.4l127.1-128C143.6 131.1 151.8 128 160 128s16.38 3.125 22.63 9.375l127.1 128c9.156 9.156 11.9 22.91 6.943 34.88S300.9 320 287.1 320H32.01c-12.94 0-24.62-7.781-29.58-19.75S.2333 274.5 9.39 265.4z"/></svg>
|
|
66
|
+
</button>
|
|
67
|
+
<button type="button" @click="moveDown(item)">
|
|
68
|
+
<svg width="11" height="11" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z"/></svg>
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</template>
|
|
73
|
+
</VirtualGrid>
|
|
74
|
+
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
</div>
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
<script>
|
|
82
|
+
|
|
83
|
+
import WebPagePropertySelector from "../WebPageBuilder4/WebPagePropertySelector.vue";
|
|
84
|
+
import {defineAsyncComponent} from "vue";
|
|
85
|
+
import InteractionEdit from "./InteractionEdit.vue";
|
|
86
|
+
|
|
87
|
+
export default{
|
|
88
|
+
components: {
|
|
89
|
+
InteractionEdit,
|
|
90
|
+
HeightSetting: defineAsyncComponent(() => import('../WebPageBuilder4/HeightSetting.vue')),
|
|
91
|
+
WebPagePropertySelector
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
computed: {
|
|
95
|
+
|
|
96
|
+
interactions(){
|
|
97
|
+
if(!Array.isArray(this.value.props.interactions))
|
|
98
|
+
this.value.props.interactions = []
|
|
99
|
+
return this.value.props.interactions
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
selectedDatasource(){
|
|
103
|
+
return this.datasource.find(d => d.uid === this.value.props.datasourceUid)
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
definedProperties(){
|
|
107
|
+
const settings = []
|
|
108
|
+
|
|
109
|
+
for(let key in this.properties){
|
|
110
|
+
if(key in this.value.props){
|
|
111
|
+
settings.push(this.properties[key])
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return settings
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
tabItems(){
|
|
119
|
+
return [
|
|
120
|
+
{ text:'General', value:1 },
|
|
121
|
+
this.value.props.datasourceUid ? { text:'Columns', value:2 } : null,
|
|
122
|
+
]
|
|
123
|
+
.filter(_ => _)
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
columns(){
|
|
127
|
+
const searches = this.search.toLowerCase().split(' ').filter(_ => _.length > 2)
|
|
128
|
+
return (this.value.props.datasourceColumns ?? []).filter(_ => {
|
|
129
|
+
return !_.key.startsWith('_') &&
|
|
130
|
+
(searches.length < 1 || searches.every(search => _.label.toLowerCase().includes(search)))
|
|
131
|
+
})
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
data(){
|
|
137
|
+
return {
|
|
138
|
+
properties: {
|
|
139
|
+
'height': { component:"HeightSetting", text:'Height', group:'Layout' }
|
|
140
|
+
},
|
|
141
|
+
search: ''
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
emits: [ 'change' ],
|
|
146
|
+
|
|
147
|
+
inject: [ 'uploadImage', 'viewTypes' ],
|
|
148
|
+
|
|
149
|
+
props: {
|
|
150
|
+
|
|
151
|
+
datasource: Object,
|
|
152
|
+
|
|
153
|
+
index: Number,
|
|
154
|
+
|
|
155
|
+
readonly: [ Boolean, Number ],
|
|
156
|
+
|
|
157
|
+
value: {
|
|
158
|
+
type: Object,
|
|
159
|
+
required: true
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
viewType: String,
|
|
163
|
+
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
methods: {
|
|
167
|
+
|
|
168
|
+
addInteraction(obj){
|
|
169
|
+
this.$util.push(this.interactions, obj)
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
applyDefault(){
|
|
173
|
+
if(!this.value.props.datasourceUid && this.datasource?.length === 1){
|
|
174
|
+
this.value.props.datasourceUid = this.datasource[0].uid
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if(!this.value.tabIndex)
|
|
178
|
+
this.value.tabIndex = 1
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
generateColumns(){
|
|
182
|
+
this.value.props.datasourceColumns = (this.selectedDatasource.pivot?.enabled ?
|
|
183
|
+
this.selectedDatasource.pivot.columns :
|
|
184
|
+
this.selectedDatasource.columns)
|
|
185
|
+
.map((_, __) => ({
|
|
186
|
+
..._,
|
|
187
|
+
visible: __ < 10
|
|
188
|
+
}))
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
moveDown(item){
|
|
192
|
+
const index = this.value.props.datasourceColumns.indexOf(item)
|
|
193
|
+
if(index + 1 < this.value.props.datasourceColumns.length){
|
|
194
|
+
this.value.props.datasourceColumns.splice(index + 1, 0, this.value.props.datasourceColumns.splice(index, 1)[0])
|
|
195
|
+
this.$emit('change')
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
moveUp(item){
|
|
200
|
+
const index = this.value.props.datasourceColumns.indexOf(item)
|
|
201
|
+
if(index - 1 >= 0){
|
|
202
|
+
this.value.props.datasourceColumns.splice(index - 1, 0, this.value.props.datasourceColumns.splice(index, 1)[0])
|
|
203
|
+
this.$emit('change')
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
mounted() {
|
|
211
|
+
this.applyDefault()
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
watch: {
|
|
215
|
+
|
|
216
|
+
'value.props.datasourceUid'(to){
|
|
217
|
+
if(to){
|
|
218
|
+
this.generateColumns()
|
|
219
|
+
this.$emit('change')
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
</script>
|
|
228
|
+
|
|
229
|
+
<style module>
|
|
230
|
+
|
|
231
|
+
.comp{
|
|
232
|
+
@apply flex-1 flex flex-col;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.columnTextbox input::placeholder{
|
|
236
|
+
@apply text-text;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
</style>
|
|
@@ -22,7 +22,7 @@ import { Doughnut } from 'vue-chartjs'
|
|
|
22
22
|
import Chart from 'chart.js/auto'
|
|
23
23
|
import {color} from "chart.js/helpers";
|
|
24
24
|
import {strVars} from "../../utils/helpers.mjs";
|
|
25
|
-
import {
|
|
25
|
+
import {useEmitter} from "../../utils/event-bus";
|
|
26
26
|
|
|
27
27
|
export default{
|
|
28
28
|
|
|
@@ -93,14 +93,43 @@ export default{
|
|
|
93
93
|
'#FFCE54',
|
|
94
94
|
'#ED5565',
|
|
95
95
|
'#EC87C0'
|
|
96
|
-
]
|
|
96
|
+
],
|
|
97
|
+
readyState: 1,
|
|
98
|
+
value: null,
|
|
97
99
|
}
|
|
98
100
|
},
|
|
99
101
|
|
|
100
|
-
inject: [ 'selectPreset' ],
|
|
102
|
+
inject: [ 'getSrc', 'getViewedPreset', 'getQueryFilters', 'selectPreset', 'socket' ],
|
|
101
103
|
|
|
102
104
|
methods: {
|
|
103
105
|
|
|
106
|
+
load(){
|
|
107
|
+
const preset = this.getViewedPreset()
|
|
108
|
+
const {name, datasource} = preset
|
|
109
|
+
|
|
110
|
+
this.readyState = 2
|
|
111
|
+
this.socket.send(this.getSrc(), {
|
|
112
|
+
name,
|
|
113
|
+
views: [{
|
|
114
|
+
...this.$props,
|
|
115
|
+
type: 'Doughnut'
|
|
116
|
+
}],
|
|
117
|
+
datasource: datasource.map(_datasource => {
|
|
118
|
+
return {
|
|
119
|
+
..._datasource,
|
|
120
|
+
filters: [
|
|
121
|
+
...(_datasource.filters ?? []),
|
|
122
|
+
...(this.getQueryFilters()[_datasource.uid] ?? [])
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
.then(_ => {
|
|
128
|
+
this.value = _[this.uid]
|
|
129
|
+
})
|
|
130
|
+
.finally(_ => this.readyState = 1)
|
|
131
|
+
},
|
|
132
|
+
|
|
104
133
|
onClick(e, segments){
|
|
105
134
|
|
|
106
135
|
const clickInteractions = (this.interactions ?? []).filter(_ => _.event === 'click')
|
|
@@ -135,15 +164,27 @@ export default{
|
|
|
135
164
|
|
|
136
165
|
},
|
|
137
166
|
|
|
138
|
-
|
|
167
|
+
mounted() {
|
|
168
|
+
this.load()
|
|
169
|
+
|
|
170
|
+
this.emitter = useEmitter()
|
|
171
|
+
this.emitter.on(`${this.uid}.load`, () => {
|
|
172
|
+
this.load()
|
|
173
|
+
})
|
|
174
|
+
this.emitter.on(`dashboard.load`, () => {
|
|
175
|
+
this.load()
|
|
176
|
+
})
|
|
177
|
+
},
|
|
139
178
|
|
|
140
179
|
props: {
|
|
141
180
|
|
|
142
181
|
label: String,
|
|
143
182
|
|
|
144
|
-
value: Object,
|
|
145
|
-
|
|
146
183
|
column: String,
|
|
184
|
+
columnModifier: String,
|
|
185
|
+
|
|
186
|
+
rows: String,
|
|
187
|
+
rowsModifier: String,
|
|
147
188
|
|
|
148
189
|
datasourceUid: String,
|
|
149
190
|
|
|
@@ -11,7 +11,7 @@
|
|
|
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; $emit('change')">
|
|
15
15
|
<option disabled selected>Select Datasource</option>
|
|
16
16
|
<option v-for="obj in datasource"
|
|
17
17
|
:value="obj.uid">
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="$style.comp">
|
|
3
3
|
<label class="text-text-400 text-ellipsis overflow-hidden whitespace-nowrap">{{ label }}</label>
|
|
4
|
-
<div class="flex flex-row gap-2">
|
|
4
|
+
<div class="flex flex-row items-end gap-2">
|
|
5
5
|
<h1 v-if="readyState === 1" class="text-ellipsis overflow-hidden whitespace-nowrap" :class="column2Enabled ? '' : 'text-green-600'">
|
|
6
6
|
{{ cValue }}
|
|
7
7
|
</h1>
|
|
@@ -10,8 +10,16 @@
|
|
|
10
10
|
</h1>
|
|
11
11
|
|
|
12
12
|
<div class="flex flex-col" v-if="column2Enabled && readyState === 1">
|
|
13
|
-
<div class="text-sm text-ellipsis whitespace-nowrap overflow-hidden"
|
|
14
|
-
|
|
13
|
+
<div class="text-sm text-ellipsis whitespace-nowrap overflow-hidden"
|
|
14
|
+
:class="showPercentage ? '' : 'text-green-600'">
|
|
15
|
+
{{ ccValue }}
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div v-if="showPercentage"
|
|
19
|
+
class="text-sm text-ellipsis whitespace-nowrap overflow-hidden"
|
|
20
|
+
:class="value?.comparedPercent <= 50 ? 'text-red-600' : 'text-green-600'">
|
|
21
|
+
{{ value?.comparedPercent }}
|
|
22
|
+
</div>
|
|
15
23
|
</div>
|
|
16
24
|
</div>
|
|
17
25
|
</div>
|
|
@@ -19,29 +27,44 @@
|
|
|
19
27
|
|
|
20
28
|
<script>
|
|
21
29
|
|
|
22
|
-
import {
|
|
30
|
+
import {useEmitter} from "../../utils/event-bus";
|
|
31
|
+
import dayjs from "dayjs";
|
|
23
32
|
|
|
24
33
|
export default{
|
|
25
34
|
|
|
26
35
|
computed: {
|
|
27
36
|
|
|
28
37
|
cValue(){
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return
|
|
38
|
+
if(!this.column) return 'N/A'
|
|
39
|
+
const column = this.datasource?.columns.find(_ => _.key === this.column)
|
|
40
|
+
return this.getValue(this.value?.value, column)
|
|
32
41
|
},
|
|
33
42
|
|
|
34
43
|
ccValue(){
|
|
35
44
|
if(!this.column2Enabled) return
|
|
45
|
+
if(!this.value?.comparedValue) return
|
|
36
46
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
const column = this.datasource?.columns.find(_ => _.key === this.column2)
|
|
48
|
+
return this.getValue(this.value?.comparedValue, column)
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
datasource(){
|
|
52
|
+
const preset = this.getViewedPreset()
|
|
53
|
+
if(preset){
|
|
54
|
+
return preset.datasource.find(_ => _.uid === this.datasourceUid)
|
|
55
|
+
}
|
|
40
56
|
}
|
|
41
57
|
|
|
42
58
|
},
|
|
43
59
|
|
|
44
|
-
|
|
60
|
+
data(){
|
|
61
|
+
return {
|
|
62
|
+
value: null,
|
|
63
|
+
readyState: 1,
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
inject: [ 'getSrc', 'getViewedPreset', 'getQueryFilters', 'socket' ],
|
|
45
68
|
|
|
46
69
|
props: {
|
|
47
70
|
|
|
@@ -54,12 +77,74 @@ export default{
|
|
|
54
77
|
|
|
55
78
|
datasourceUid: String,
|
|
56
79
|
|
|
80
|
+
showPercentage: [ Number, Boolean ],
|
|
81
|
+
|
|
57
82
|
label: String,
|
|
58
83
|
|
|
59
|
-
|
|
84
|
+
uid: String
|
|
85
|
+
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
methods: {
|
|
89
|
+
|
|
90
|
+
getValue(val, column){
|
|
91
|
+
let value
|
|
92
|
+
|
|
93
|
+
switch(column?.type){
|
|
94
|
+
|
|
95
|
+
case 'date':
|
|
96
|
+
value = dayjs(val).format('D MMM')
|
|
97
|
+
break
|
|
98
|
+
|
|
99
|
+
default:
|
|
100
|
+
value = parseFloat(val)
|
|
101
|
+
value = isNaN(value) ?
|
|
102
|
+
'N/A' :
|
|
103
|
+
value.toLocaleString()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return value
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
load(){
|
|
110
|
+
const preset = this.getViewedPreset()
|
|
111
|
+
const {name, datasource} = preset
|
|
112
|
+
|
|
113
|
+
this.readyState = 2
|
|
114
|
+
this.socket.send(this.getSrc(), {
|
|
115
|
+
name,
|
|
116
|
+
views: [{
|
|
117
|
+
...this.$props,
|
|
118
|
+
type: 'Metric'
|
|
119
|
+
}],
|
|
120
|
+
datasource: datasource.map(_datasource => {
|
|
121
|
+
return {
|
|
122
|
+
..._datasource,
|
|
123
|
+
filters: [
|
|
124
|
+
...(_datasource.filters ?? []),
|
|
125
|
+
...(this.getQueryFilters()[_datasource.uid] ?? [])
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
.then(_ => {
|
|
131
|
+
this.value = _[this.uid]
|
|
132
|
+
})
|
|
133
|
+
.finally(_ => this.readyState = 1)
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
},
|
|
60
137
|
|
|
61
|
-
|
|
138
|
+
mounted() {
|
|
139
|
+
this.load()
|
|
62
140
|
|
|
141
|
+
this.emitter = useEmitter()
|
|
142
|
+
this.emitter.on(`${this.uid}.load`, () => {
|
|
143
|
+
this.load()
|
|
144
|
+
})
|
|
145
|
+
this.emitter.on(`dashboard.load`, () => {
|
|
146
|
+
this.load()
|
|
147
|
+
})
|
|
63
148
|
}
|
|
64
149
|
|
|
65
150
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex flex-col gap-
|
|
2
|
+
<div class="flex flex-col gap-8 p-6">
|
|
3
3
|
|
|
4
|
-
<div class="flex flex-row items-center">
|
|
4
|
+
<div class="flex flex-row items-center" @click="log(value)">
|
|
5
5
|
<label class="flex-1">Active</label>
|
|
6
6
|
<Switch v-model="value.props.enabled" :readonly="readonly" @change="$emit('change')" />
|
|
7
7
|
</div>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<Dropdown class="min-w-[150px]"
|
|
16
16
|
:readonly="readonly"
|
|
17
17
|
v-model="value.props.datasourceUid"
|
|
18
|
-
@change="delete value.props.columns">
|
|
18
|
+
@change="delete value.props.columns;$emit('change')">
|
|
19
19
|
<option v-for="obj in datasource"
|
|
20
20
|
:value="obj.uid">
|
|
21
21
|
{{ obj.name }}
|
|
@@ -28,25 +28,13 @@
|
|
|
28
28
|
<Textbox v-model="value.props.label"
|
|
29
29
|
maxlength="30"
|
|
30
30
|
placeholder="Label"
|
|
31
|
-
:readonly="readonly"
|
|
32
|
-
@keyup.enter="$emit('change')"
|
|
33
|
-
@blur="$emit('change')" />
|
|
31
|
+
:readonly="readonly" />
|
|
34
32
|
</div>
|
|
35
33
|
|
|
36
|
-
<div v-if="value.props.datasourceUid" class="flex flex-col gap-
|
|
34
|
+
<div v-if="value.props.datasourceUid" class="flex flex-col gap-8">
|
|
37
35
|
<div class="flex flex-col gap-1">
|
|
38
36
|
<label class="flex-1">Column</label>
|
|
39
37
|
<div class="flex flex-row gap-2">
|
|
40
|
-
<Dropdown class="min-w-[150px] flex-1"
|
|
41
|
-
:readonly="readonly"
|
|
42
|
-
v-model="value.props.column"
|
|
43
|
-
@change="$emit('change')">
|
|
44
|
-
<option v-for="column in selectedDatasourceColumns"
|
|
45
|
-
:value="column.key">
|
|
46
|
-
{{ selectedDatasource.pivot?.enabled ? column.key : column.label }}
|
|
47
|
-
</option>
|
|
48
|
-
</Dropdown>
|
|
49
|
-
|
|
50
38
|
<Dropdown class="w-[125px]"
|
|
51
39
|
:readonly="readonly"
|
|
52
40
|
v-model="value.props.columnModifier"
|
|
@@ -60,6 +48,16 @@
|
|
|
60
48
|
<option value="first">First</option>
|
|
61
49
|
<option value="last">Last</option>
|
|
62
50
|
</Dropdown>
|
|
51
|
+
|
|
52
|
+
<Dropdown class="min-w-[150px] flex-1"
|
|
53
|
+
:readonly="readonly"
|
|
54
|
+
v-model="value.props.column"
|
|
55
|
+
@change="$emit('change')">
|
|
56
|
+
<option v-for="column in selectedDatasourceColumns"
|
|
57
|
+
:value="column.key">
|
|
58
|
+
{{ selectedDatasource.pivot?.enabled ? column.key : column.label }}
|
|
59
|
+
</option>
|
|
60
|
+
</Dropdown>
|
|
63
61
|
</div>
|
|
64
62
|
</div>
|
|
65
63
|
|
|
@@ -70,16 +68,6 @@
|
|
|
70
68
|
</Checkbox>
|
|
71
69
|
</div>
|
|
72
70
|
<div class="flex flex-row gap-2">
|
|
73
|
-
<Dropdown class="min-w-[150px] flex-1"
|
|
74
|
-
:readonly="readonly || !value.props.column2Enabled"
|
|
75
|
-
v-model="value.props.column2"
|
|
76
|
-
@change="$emit('change')">
|
|
77
|
-
<option v-for="column in selectedDatasourceColumns"
|
|
78
|
-
:value="column.key">
|
|
79
|
-
{{ selectedDatasource.pivot?.enabled ? column.key : column.label }}
|
|
80
|
-
</option>
|
|
81
|
-
</Dropdown>
|
|
82
|
-
|
|
83
71
|
<Dropdown class="w-[125px]"
|
|
84
72
|
:readonly="readonly || !value.props.column2Enabled"
|
|
85
73
|
v-model="value.props.column2Modifier"
|
|
@@ -93,6 +81,32 @@
|
|
|
93
81
|
<option value="first">First</option>
|
|
94
82
|
<option value="last">Last</option>
|
|
95
83
|
</Dropdown>
|
|
84
|
+
|
|
85
|
+
<Dropdown class="min-w-[150px] flex-1"
|
|
86
|
+
:readonly="readonly || !value.props.column2Enabled"
|
|
87
|
+
v-model="value.props.column2"
|
|
88
|
+
@change="$emit('change')">
|
|
89
|
+
<option v-for="column in selectedDatasourceColumns"
|
|
90
|
+
:value="column.key">
|
|
91
|
+
{{ selectedDatasource.pivot?.enabled ? column.key : column.label }}
|
|
92
|
+
</option>
|
|
93
|
+
</Dropdown>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<div class="flex flex-col gap-2" v-if="canShowPercentage">
|
|
98
|
+
<div>
|
|
99
|
+
<Checkbox v-model="value.props.showPercentage" :disabled="readonly">
|
|
100
|
+
Show Percentage
|
|
101
|
+
</Checkbox>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="flex flex-row gap-2">
|
|
104
|
+
<Dropdown class="w-full"
|
|
105
|
+
:readonly="readonly || !value.props.column2Enabled"
|
|
106
|
+
v-model="value.props.showPercentageOpt"
|
|
107
|
+
@change="$emit('change')">
|
|
108
|
+
<option v-for="arr in showPercentageOptValues" :value="arr[0]">{{ arr[1] }}</option>
|
|
109
|
+
</Dropdown>
|
|
96
110
|
</div>
|
|
97
111
|
</div>
|
|
98
112
|
|
|
@@ -113,10 +127,49 @@ export default{
|
|
|
113
127
|
|
|
114
128
|
computed: {
|
|
115
129
|
|
|
130
|
+
column1(){
|
|
131
|
+
if(!this.value || !this.value.props.column) return
|
|
132
|
+
return this.selectedDatasource.columns.find(_ => _.key === this.value.props.column)
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
column2(){
|
|
136
|
+
if(!this.value || !this.value.props.column2) return
|
|
137
|
+
return this.selectedDatasource.columns.find(_ => _.key === this.value.props.column2)
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
canShowPercentage(){
|
|
141
|
+
return this.column1 && this.column2 && this.column1.type === this.column2.type
|
|
142
|
+
},
|
|
143
|
+
|
|
116
144
|
selectedDatasource(){
|
|
117
145
|
return this.datasource.find(d => d.uid === this.value.props.datasourceUid)
|
|
118
146
|
},
|
|
119
147
|
|
|
148
|
+
showPercentageOptValues(){
|
|
149
|
+
if(!this.canShowPercentage) return
|
|
150
|
+
|
|
151
|
+
switch(this.column1.type){
|
|
152
|
+
|
|
153
|
+
case 'date':
|
|
154
|
+
return [
|
|
155
|
+
[ 'day', 'Day' ],
|
|
156
|
+
[ 'hour', 'Hour' ],
|
|
157
|
+
[ 'minute', 'Minute' ],
|
|
158
|
+
[ 'month', 'Month' ],
|
|
159
|
+
[ 'week', 'Week' ],
|
|
160
|
+
[ 'year', 'Year' ],
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
case 'number':
|
|
164
|
+
default:
|
|
165
|
+
return [
|
|
166
|
+
[ 'percentage', 'Percentage' ],
|
|
167
|
+
[ 'number', 'Number' ],
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
|
|
120
173
|
selectedDatasourceColumns(){
|
|
121
174
|
if(!this.selectedDatasource) return []
|
|
122
175
|
|
|
@@ -22,7 +22,7 @@ import { Pie } from 'vue-chartjs'
|
|
|
22
22
|
import Chart from 'chart.js/auto'
|
|
23
23
|
import { color } from 'chart.js/helpers'
|
|
24
24
|
import {strVars} from "../../utils/helpers.mjs";
|
|
25
|
-
import {
|
|
25
|
+
import {useEmitter} from "../../utils/event-bus";
|
|
26
26
|
|
|
27
27
|
export default{
|
|
28
28
|
|
|
@@ -79,10 +79,44 @@ export default{
|
|
|
79
79
|
|
|
80
80
|
},
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
data(){
|
|
83
|
+
return {
|
|
84
|
+
readyState: 1,
|
|
85
|
+
value: null,
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
inject: [ 'getSrc', 'getViewedPreset', 'getQueryFilters', 'selectPreset', 'socket' ],
|
|
83
90
|
|
|
84
91
|
methods: {
|
|
85
92
|
|
|
93
|
+
load(){
|
|
94
|
+
const preset = this.getViewedPreset()
|
|
95
|
+
const {name, datasource} = preset
|
|
96
|
+
|
|
97
|
+
this.readyState = 2
|
|
98
|
+
this.socket.send(this.getSrc(), {
|
|
99
|
+
name,
|
|
100
|
+
views: [{
|
|
101
|
+
...this.$props,
|
|
102
|
+
type: 'Pie'
|
|
103
|
+
}],
|
|
104
|
+
datasource: datasource.map(_datasource => {
|
|
105
|
+
return {
|
|
106
|
+
..._datasource,
|
|
107
|
+
filters: [
|
|
108
|
+
...(_datasource.filters ?? []),
|
|
109
|
+
...(this.getQueryFilters()[_datasource.uid] ?? [])
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
.then(_ => {
|
|
115
|
+
this.value = _[this.uid]
|
|
116
|
+
})
|
|
117
|
+
.finally(_ => this.readyState = 1)
|
|
118
|
+
},
|
|
119
|
+
|
|
86
120
|
onClick(e, segments){
|
|
87
121
|
|
|
88
122
|
const clickInteractions = (this.interactions ?? []).filter(_ => _.event === 'click')
|
|
@@ -117,7 +151,17 @@ export default{
|
|
|
117
151
|
|
|
118
152
|
},
|
|
119
153
|
|
|
120
|
-
|
|
154
|
+
mounted() {
|
|
155
|
+
this.load()
|
|
156
|
+
|
|
157
|
+
this.emitter = useEmitter()
|
|
158
|
+
this.emitter.on(`${this.uid}.load`, () => {
|
|
159
|
+
this.load()
|
|
160
|
+
})
|
|
161
|
+
this.emitter.on(`dashboard.load`, () => {
|
|
162
|
+
this.load()
|
|
163
|
+
})
|
|
164
|
+
},
|
|
121
165
|
|
|
122
166
|
props: {
|
|
123
167
|
|
|
@@ -125,7 +169,11 @@ export default{
|
|
|
125
169
|
|
|
126
170
|
value: Object,
|
|
127
171
|
|
|
128
|
-
column:
|
|
172
|
+
column: String,
|
|
173
|
+
columnModifier: String,
|
|
174
|
+
|
|
175
|
+
rows: String,
|
|
176
|
+
rowsModifier: String,
|
|
129
177
|
|
|
130
178
|
datasourceUid: String,
|
|
131
179
|
|
|
@@ -20,7 +20,7 @@ import { PolarArea } from 'vue-chartjs'
|
|
|
20
20
|
import Chart from 'chart.js/auto'
|
|
21
21
|
import { color } from 'chart.js/helpers'
|
|
22
22
|
import {strVars} from "../../utils/helpers.mjs";
|
|
23
|
-
import {
|
|
23
|
+
import {useEmitter} from "../../utils/event-bus";
|
|
24
24
|
|
|
25
25
|
export default{
|
|
26
26
|
|
|
@@ -96,13 +96,42 @@ export default{
|
|
|
96
96
|
'#ED5565',
|
|
97
97
|
'#EC87C0'
|
|
98
98
|
],
|
|
99
|
+
readyState: 1,
|
|
100
|
+
value: null,
|
|
99
101
|
}
|
|
100
102
|
},
|
|
101
103
|
|
|
102
|
-
inject: [ 'selectPreset' ],
|
|
104
|
+
inject: [ 'getSrc', 'getViewedPreset', 'getQueryFilters', 'selectPreset', 'socket' ],
|
|
103
105
|
|
|
104
106
|
methods: {
|
|
105
107
|
|
|
108
|
+
load(){
|
|
109
|
+
const preset = this.getViewedPreset()
|
|
110
|
+
const {name, datasource} = preset
|
|
111
|
+
|
|
112
|
+
this.readyState = 2
|
|
113
|
+
this.socket.send(this.getSrc(), {
|
|
114
|
+
name,
|
|
115
|
+
views: [{
|
|
116
|
+
...this.$props,
|
|
117
|
+
type: 'PolarArea'
|
|
118
|
+
}],
|
|
119
|
+
datasource: datasource.map(_datasource => {
|
|
120
|
+
return {
|
|
121
|
+
..._datasource,
|
|
122
|
+
filters: [
|
|
123
|
+
...(_datasource.filters ?? []),
|
|
124
|
+
...(this.getQueryFilters()[_datasource.uid] ?? [])
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
.then(_ => {
|
|
130
|
+
this.value = _[this.uid]
|
|
131
|
+
})
|
|
132
|
+
.finally(_ => this.readyState = 1)
|
|
133
|
+
},
|
|
134
|
+
|
|
106
135
|
onClick(e, segments){
|
|
107
136
|
|
|
108
137
|
const clickInteractions = (this.interactions ?? []).filter(_ => _.event === 'click')
|
|
@@ -137,15 +166,27 @@ export default{
|
|
|
137
166
|
|
|
138
167
|
},
|
|
139
168
|
|
|
140
|
-
|
|
169
|
+
mounted() {
|
|
170
|
+
this.load()
|
|
171
|
+
|
|
172
|
+
this.emitter = useEmitter()
|
|
173
|
+
this.emitter.on(`${this.uid}.load`, () => {
|
|
174
|
+
this.load()
|
|
175
|
+
})
|
|
176
|
+
this.emitter.on(`dashboard.load`, () => {
|
|
177
|
+
this.load()
|
|
178
|
+
})
|
|
179
|
+
},
|
|
141
180
|
|
|
142
181
|
props: {
|
|
143
182
|
|
|
144
183
|
label: String,
|
|
145
184
|
|
|
146
|
-
value: Object,
|
|
147
|
-
|
|
148
185
|
column: String,
|
|
186
|
+
columnModifier: String,
|
|
187
|
+
|
|
188
|
+
rows: String,
|
|
189
|
+
rowsModifier: String,
|
|
149
190
|
|
|
150
191
|
datasourceUid: String,
|
|
151
192
|
|
|
@@ -101,7 +101,7 @@ export default{
|
|
|
101
101
|
{ type:"Pie", name:"Pie", group:"components", import: () => import('../../configs/dashboard/pie.js'), thumbnailUrl:"/static/dashboard/pie.png" },
|
|
102
102
|
{ type:"Doughnut", name:"Doughnut", group:"components", import: () => import('../../configs/dashboard/doughnut.js'), thumbnailUrl:"/static/dashboard/doughnut.png" },
|
|
103
103
|
{ type:"PolarArea", name:"Polar Area", group:"components", import: () => import('../../configs/dashboard/polar-area.js'), thumbnailUrl:"/static/dashboard/polar-area.png" },
|
|
104
|
-
{ type:"
|
|
104
|
+
{ type:"DataTable", name:"DataTable", group:"components", import: () => import('../../configs/dashboard/data-table.js'), thumbnailUrl:"/static/dashboard/virtual-table.png" },
|
|
105
105
|
{ type:"Metric", name:"Metric", group:"components", import: () => import('../../configs/dashboard/metric.js'), thumbnailUrl:"/static/dashboard/metric.png" },
|
|
106
106
|
{ type:"BarChart", name:"Bar Chart", group:"components", import: () => import('../../configs/dashboard/bar.js'), thumbnailUrl:"/static/dashboard/bar.png" },
|
|
107
107
|
{ type:"GHeatMaps", name:"Heat Map", group:"components", import: () => import('../../configs/dashboard/gheatmaps.js'), thumbnailUrl:"/static/dashboard/gheatmaps.png" },
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
:readonly="selectedPreset.readonly"
|
|
34
34
|
:value="selectedView"
|
|
35
35
|
:view-type="config.viewType"
|
|
36
|
-
@change="load({ [selectedView.uid]:selectedView })"/>
|
|
36
|
+
@change="load({ [selectedView.uid]:selectedView })" />
|
|
37
37
|
|
|
38
38
|
</div>
|
|
39
39
|
</div>
|
|
@@ -945,6 +945,7 @@ export default {
|
|
|
945
945
|
BarChartSetting: defineAsyncComponent(() => import('./Dashboard/BarChartSetting.vue')),
|
|
946
946
|
MetricSetting: defineAsyncComponent(() => import('./Dashboard/MetricSetting.vue')),
|
|
947
947
|
GHeatMapsSetting: defineAsyncComponent(() => import('./Dashboard/GHeatMapsSetting.vue')),
|
|
948
|
+
DataTableSetting: defineAsyncComponent(() => import('./Dashboard/DataTableSetting.vue')),
|
|
948
949
|
VirtualTableSetting: defineAsyncComponent(() => import('./Dashboard/VirtualTableSetting.vue')),
|
|
949
950
|
PieSetting: defineAsyncComponent(() => import('./Dashboard/PieSetting.vue')),
|
|
950
951
|
PolarAreaSetting: defineAsyncComponent(() => import('./Dashboard/PolarAreaSetting.vue')),
|
|
@@ -1330,10 +1331,19 @@ export default {
|
|
|
1330
1331
|
|
|
1331
1332
|
duplicateComponent(item, parent) {
|
|
1332
1333
|
|
|
1334
|
+
const recurseSet = (item) => {
|
|
1335
|
+
item.uid = getPresetUid()
|
|
1336
|
+
|
|
1337
|
+
if(Array.isArray(item.items)){
|
|
1338
|
+
for(let subItem of item.items)
|
|
1339
|
+
recurseSet(subItem)
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1333
1343
|
const index = parent.findIndex(_ => _ === item)
|
|
1334
1344
|
|
|
1335
1345
|
const newItem = JSON.parse(JSON.stringify(item))
|
|
1336
|
-
newItem
|
|
1346
|
+
recurseSet(newItem)
|
|
1337
1347
|
newItem.name += ' (Copy)';
|
|
1338
1348
|
|
|
1339
1349
|
parent.splice(index + 1, null, newItem)
|
|
@@ -1363,6 +1373,14 @@ export default {
|
|
|
1363
1373
|
},
|
|
1364
1374
|
|
|
1365
1375
|
async load(uids) {
|
|
1376
|
+
if(uids){
|
|
1377
|
+
Object.keys(uids).forEach(uid => this.emitter.emit(`${uid}.load`))
|
|
1378
|
+
}
|
|
1379
|
+
else{
|
|
1380
|
+
this.emitter.emit(`dashboard.load`)
|
|
1381
|
+
}
|
|
1382
|
+
return
|
|
1383
|
+
|
|
1366
1384
|
if (this.readyState !== 1) return
|
|
1367
1385
|
if (!this.viewedComponents) return
|
|
1368
1386
|
if (!this.cConfig) return
|
|
@@ -1372,7 +1390,7 @@ export default {
|
|
|
1372
1390
|
|
|
1373
1391
|
const {name, datasource} = this.viewedPreset
|
|
1374
1392
|
|
|
1375
|
-
!uids ? this.readyState =
|
|
1393
|
+
!uids ? this.readyState = 2 : Object.keys(uids).forEach(uid => this.emitter.emit(`${uid}.readyState`, 2))
|
|
1376
1394
|
this.socket.send(this.src, {
|
|
1377
1395
|
name,
|
|
1378
1396
|
views,
|
|
@@ -1689,7 +1707,10 @@ export default {
|
|
|
1689
1707
|
getConfig: this.getConfig,
|
|
1690
1708
|
getPresets: this.getPresets,
|
|
1691
1709
|
selectPreset: this.selectPreset,
|
|
1692
|
-
preview: this.preview
|
|
1710
|
+
preview: this.preview,
|
|
1711
|
+
getSrc: () => this.src,
|
|
1712
|
+
getViewedPreset: () => this.viewedPreset,
|
|
1713
|
+
getQueryFilters: () => this.queryFilters,
|
|
1693
1714
|
}
|
|
1694
1715
|
},
|
|
1695
1716
|
|