@mixd-id/web-scaffold 0.1.230406337 → 0.1.230406338
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/List.vue +1 -1
- package/src/defs/dashboard-preset.js +22 -0
- package/src/index.js +1 -0
- package/src/themes/default/index.js +1 -1
- package/src/widgets/Dashboard/DatasourceSelector.vue +97 -0
- package/src/widgets/Dashboard/Doughnut.vue +99 -0
- package/src/widgets/Dashboard/DoughnutSetting.vue +80 -0
- package/src/widgets/Dashboard/ViewSelector.vue +102 -0
- package/src/widgets/Dashboard/VirtualTableSetting.vue +43 -0
- package/src/widgets/Dashboard.vue +502 -0
- package/src/widgets/WebPageBuilder4/TreeViewItem.vue +4 -1
package/package.json
CHANGED
package/src/components/List.vue
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
|
|
41
41
|
<div class="flex flex-row gap-2 md:gap-3 items-center" ref="title">
|
|
42
42
|
<div class="flex flex-col whitespace-nowrap text-ellipsis overflow-hidden">
|
|
43
|
-
<div class="cursor-pointer group" @click="$refs.contextMenu.open($refs.title)">
|
|
43
|
+
<div class="cursor-pointer group px-2 md:px-0" @click="$refs.contextMenu.open($refs.title)">
|
|
44
44
|
<small class="text-text-400 text-xs">{{ title ?? 'Untitled' }}</small>
|
|
45
45
|
<div class="flex flex-row items-baseline gap-1">
|
|
46
46
|
<h5 class="whitespace-nowrap relative top-[-2px] text-ellipsis overflow-hidden group-hover:text-primary">
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
|
|
3
|
+
uid: "uid-1",
|
|
4
|
+
name: "Dashboard 1",
|
|
5
|
+
|
|
6
|
+
datasource: [
|
|
7
|
+
{
|
|
8
|
+
uid: "uid-1",
|
|
9
|
+
type:"mpp.hmc",
|
|
10
|
+
name: "Datasource 1",
|
|
11
|
+
columns: [
|
|
12
|
+
{ key:"coo", label:"COO" },
|
|
13
|
+
{ key:"mppTgtLck", label:"MPP TGT LCK" },
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
|
|
18
|
+
views: [
|
|
19
|
+
{ uid:"uid-1", type:"List", name:"List" }
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
}
|
package/src/index.js
CHANGED
|
@@ -669,6 +669,7 @@ export default{
|
|
|
669
669
|
app.component('TypographySetting', defineAsyncComponent(() => import("./widgets/TypographySetting.vue")))
|
|
670
670
|
app.component('FiltersSetting', defineAsyncComponent(() => import("./widgets/FiltersSetting.vue")))
|
|
671
671
|
app.component('MenuEditor', defineAsyncComponent(() => import("./widgets/MenuEditor.vue")))
|
|
672
|
+
app.component('Dashboard', defineAsyncComponent(() => import("./widgets/Dashboard.vue")))
|
|
672
673
|
app.component('Text', defineAsyncComponent(() => import("./components/Text.vue")))
|
|
673
674
|
}
|
|
674
675
|
|
|
@@ -243,7 +243,7 @@ const plugin = Plugin(function({ addBase, addUtilities, config, theme }) {
|
|
|
243
243
|
|
|
244
244
|
'.openltr-enter-from, .openltr-leave-to': {
|
|
245
245
|
opacity: 0,
|
|
246
|
-
transform: 'translateX(
|
|
246
|
+
transform: 'translateX(100px)'
|
|
247
247
|
},
|
|
248
248
|
|
|
249
249
|
'.openltr-leave-active': {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal ref="modal"
|
|
3
|
+
width="320"
|
|
4
|
+
height="360">
|
|
5
|
+
<template v-slot:head>
|
|
6
|
+
<div class="relative p-6">
|
|
7
|
+
<h3>{{ $t('Select Datasource') }}</h3>
|
|
8
|
+
<div class="absolute top-0 right-0 p-2">
|
|
9
|
+
<button type="button" class="p-2" @click="close">
|
|
10
|
+
<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">
|
|
11
|
+
<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"/>
|
|
12
|
+
</svg>
|
|
13
|
+
</button>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
<template v-slot:foot>
|
|
18
|
+
<div class="p-6">
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
<div class="flex-1 p-6">
|
|
23
|
+
|
|
24
|
+
<button v-for="datasource in datasources"
|
|
25
|
+
type="button"
|
|
26
|
+
@click="add(datasource)">
|
|
27
|
+
{{ datasource.name }}
|
|
28
|
+
</button>
|
|
29
|
+
|
|
30
|
+
</div>
|
|
31
|
+
</Modal>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script>
|
|
35
|
+
|
|
36
|
+
import Modal from "../../components/Modal.vue"
|
|
37
|
+
import md5 from "md5";
|
|
38
|
+
|
|
39
|
+
export default{
|
|
40
|
+
|
|
41
|
+
components: { Modal },
|
|
42
|
+
|
|
43
|
+
emits: [ 'add' ],
|
|
44
|
+
|
|
45
|
+
inject: [ 'alert', 'socket' ],
|
|
46
|
+
|
|
47
|
+
props: {
|
|
48
|
+
|
|
49
|
+
src: String
|
|
50
|
+
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
data(){
|
|
54
|
+
return {
|
|
55
|
+
instance: null,
|
|
56
|
+
datasources: null,
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
methods: {
|
|
61
|
+
|
|
62
|
+
add(item){
|
|
63
|
+
const newItem = JSON.parse(JSON.stringify(item))
|
|
64
|
+
newItem.uid = md5(newItem.name + Date.now())
|
|
65
|
+
|
|
66
|
+
this.close()
|
|
67
|
+
this.$emit('add', newItem)
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
load(){
|
|
71
|
+
this.socket.send(this.src, {})
|
|
72
|
+
.then(res => this.datasources = res.items)
|
|
73
|
+
.catch(err => this.alert(err))
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
open(){
|
|
77
|
+
this.load()
|
|
78
|
+
this.$refs.modal.open()
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
close(){
|
|
82
|
+
this.$refs.modal.close()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<style module>
|
|
92
|
+
|
|
93
|
+
.comp{
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
</style>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col gap-2">
|
|
3
|
+
|
|
4
|
+
<Doughnut class="aspect-square"
|
|
5
|
+
:options="chartOptions"
|
|
6
|
+
:data="chartData" />
|
|
7
|
+
|
|
8
|
+
<div class="flex justify-center">
|
|
9
|
+
{{ column }}
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
|
|
17
|
+
import { Doughnut } from 'vue-chartjs'
|
|
18
|
+
import Chart from 'chart.js/auto'
|
|
19
|
+
|
|
20
|
+
export default{
|
|
21
|
+
|
|
22
|
+
components: {
|
|
23
|
+
Doughnut
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
computed: {
|
|
27
|
+
|
|
28
|
+
chartData(){
|
|
29
|
+
if(!Array.isArray(this.items)) return { labels:[], datasets:[] }
|
|
30
|
+
|
|
31
|
+
const labels = this.items.map(_ => _[this.rows])
|
|
32
|
+
|
|
33
|
+
const data = this.items.map(_ => _[this.column])
|
|
34
|
+
|
|
35
|
+
const backgroundColor = labels.map((_, i) => this.backgroundColors[i % this.backgroundColors.length])
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
labels,
|
|
39
|
+
datasets: [{
|
|
40
|
+
label: this.rows,
|
|
41
|
+
data: data,
|
|
42
|
+
backgroundColor,
|
|
43
|
+
hoverOffset: 4
|
|
44
|
+
}]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
chartOptions(){
|
|
49
|
+
return {
|
|
50
|
+
responsive: true,
|
|
51
|
+
maintainAspectRatio: true,
|
|
52
|
+
plugins: {
|
|
53
|
+
legend: {
|
|
54
|
+
display: false
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
data(){
|
|
63
|
+
return {
|
|
64
|
+
backgroundColors: [
|
|
65
|
+
'#5D9CEC',
|
|
66
|
+
'#A0D468',
|
|
67
|
+
'#FFCE54',
|
|
68
|
+
'#FC6E51',
|
|
69
|
+
'#48CFAD',
|
|
70
|
+
'#AC92EC',
|
|
71
|
+
'#4FC1E9',
|
|
72
|
+
'#FFCE54',
|
|
73
|
+
'#ED5565',
|
|
74
|
+
'#EC87C0'
|
|
75
|
+
],
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
props: {
|
|
80
|
+
|
|
81
|
+
items: Array,
|
|
82
|
+
|
|
83
|
+
column: String,
|
|
84
|
+
|
|
85
|
+
rows: String
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<style module>
|
|
94
|
+
|
|
95
|
+
.comp{
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
</style>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
|
|
4
|
+
<div class="flex flex-row items-center p-3">
|
|
5
|
+
<label class="flex-1">Datasource</label>
|
|
6
|
+
<div>
|
|
7
|
+
<Dropdown class="min-w-[150px]"
|
|
8
|
+
v-model="value.datasourceUid"
|
|
9
|
+
@change="delete value.columns">
|
|
10
|
+
<option v-for="datasource in preset.datasource"
|
|
11
|
+
:value="datasource.uid">
|
|
12
|
+
{{ datasource.name }}
|
|
13
|
+
</option>
|
|
14
|
+
</Dropdown>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div v-if="value.datasourceUid" class="flex flex-col">
|
|
19
|
+
<div class="flex flex-row items-center p-3">
|
|
20
|
+
<label class="flex-1">Column</label>
|
|
21
|
+
<div>
|
|
22
|
+
<Dropdown class="min-w-[150px]"
|
|
23
|
+
v-model="value.column">
|
|
24
|
+
<option v-for="column in datasource.columns"
|
|
25
|
+
:value="column.key">
|
|
26
|
+
{{ column.text }}
|
|
27
|
+
</option>
|
|
28
|
+
</Dropdown>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div class="flex flex-row items-center p-3">
|
|
33
|
+
<label class="flex-1">Rows</label>
|
|
34
|
+
<div>
|
|
35
|
+
<Dropdown class="min-w-[150px]"
|
|
36
|
+
v-model="value.rows">
|
|
37
|
+
<option v-for="column in datasource.columns"
|
|
38
|
+
:value="column.key">
|
|
39
|
+
{{ column.text }}
|
|
40
|
+
</option>
|
|
41
|
+
</Dropdown>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script>
|
|
51
|
+
|
|
52
|
+
export default{
|
|
53
|
+
|
|
54
|
+
computed: {
|
|
55
|
+
|
|
56
|
+
datasource(){
|
|
57
|
+
return this.preset.datasource.find(d => d.uid === this.value.datasourceUid)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
props: {
|
|
63
|
+
|
|
64
|
+
preset: Object,
|
|
65
|
+
|
|
66
|
+
value: Object
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<style module>
|
|
75
|
+
|
|
76
|
+
.comp{
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
</style>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal ref="modal"
|
|
3
|
+
width="320"
|
|
4
|
+
height="360">
|
|
5
|
+
<template v-slot:head>
|
|
6
|
+
<div class="relative p-6">
|
|
7
|
+
<h3>{{ $t('Select View') }}</h3>
|
|
8
|
+
<div class="absolute top-0 right-0 p-2">
|
|
9
|
+
<button type="button" class="p-2" @click="close">
|
|
10
|
+
<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">
|
|
11
|
+
<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"/>
|
|
12
|
+
</svg>
|
|
13
|
+
</button>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
<template v-slot:foot>
|
|
18
|
+
<div class="p-6">
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
<div class="flex-1 p-6">
|
|
23
|
+
|
|
24
|
+
<div class="flex flex-col">
|
|
25
|
+
<button v-for="component in components"
|
|
26
|
+
type="button"
|
|
27
|
+
:class="$style.button"
|
|
28
|
+
@click="add(component)">
|
|
29
|
+
{{ component.text }}
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
</div>
|
|
34
|
+
</Modal>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script>
|
|
38
|
+
|
|
39
|
+
import Modal from "../../components/Modal.vue"
|
|
40
|
+
import md5 from "md5";
|
|
41
|
+
|
|
42
|
+
export default{
|
|
43
|
+
|
|
44
|
+
components: { Modal },
|
|
45
|
+
|
|
46
|
+
emits: [ 'add' ],
|
|
47
|
+
|
|
48
|
+
inject: [ 'socketEmit2' ],
|
|
49
|
+
|
|
50
|
+
props: {
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
data(){
|
|
54
|
+
return {
|
|
55
|
+
callback: null,
|
|
56
|
+
instance: null,
|
|
57
|
+
|
|
58
|
+
components: [
|
|
59
|
+
{ type:"Bar", text:"Bar Chart" },
|
|
60
|
+
{ type:"Doughnut", text:"Doughnut" },
|
|
61
|
+
{ type:"Line", text:"Line Chart" },
|
|
62
|
+
{ type:"Metric", text:"Metric" },
|
|
63
|
+
{ type:"Row", text:"Row", items:[], isContainer:true },
|
|
64
|
+
{ type:"VirtualTable", text:"Table" },
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
methods: {
|
|
70
|
+
|
|
71
|
+
add(component){
|
|
72
|
+
const newComponent = JSON.parse(JSON.stringify(component))
|
|
73
|
+
newComponent.uid = md5(newComponent.type + Date.now())
|
|
74
|
+
if(typeof this.callback === 'function')
|
|
75
|
+
this.callback(newComponent)
|
|
76
|
+
this.$emit('add', newComponent)
|
|
77
|
+
this.close()
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
open(callback){
|
|
81
|
+
this.callback = callback
|
|
82
|
+
this.$refs.modal.open()
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
close(){
|
|
86
|
+
this.$refs.modal.close()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<style module>
|
|
96
|
+
|
|
97
|
+
.button{
|
|
98
|
+
@apply text-left p-3 border-[1px] border-transparent rounded-lg;
|
|
99
|
+
@apply hover:border-primary-300 hover:bg-primary-100;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
</style>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
|
|
4
|
+
<div class="flex flex-row items-center p-3">
|
|
5
|
+
<label class="flex-1">Datasource</label>
|
|
6
|
+
<div>
|
|
7
|
+
<Dropdown class="min-w-[150px]"
|
|
8
|
+
v-model="value.datasourceUid"
|
|
9
|
+
@change="delete value.columns">
|
|
10
|
+
<option v-for="datasource in preset.datasource"
|
|
11
|
+
:value="datasource.uid">
|
|
12
|
+
{{ datasource.name }}
|
|
13
|
+
</option>
|
|
14
|
+
</Dropdown>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
|
|
23
|
+
export default{
|
|
24
|
+
|
|
25
|
+
props: {
|
|
26
|
+
|
|
27
|
+
preset: Object,
|
|
28
|
+
|
|
29
|
+
value: Object
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<style module>
|
|
38
|
+
|
|
39
|
+
.comp{
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
</style>
|
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="cConfig" :class="$style.comp">
|
|
3
|
+
|
|
4
|
+
<div class="relative flex flex-col border-r-[1px] border-text-50 panel-400 overflow-hidden"
|
|
5
|
+
:style="sidebarStyle">
|
|
6
|
+
|
|
7
|
+
<TransitionGroup name="openltr" tag="div" class="flex-1 flex flex-col">
|
|
8
|
+
|
|
9
|
+
<div v-if="selectedView" class="flex-1 flex flex-col p-3">
|
|
10
|
+
<div class="p-3 flex flex-row gap-2">
|
|
11
|
+
<button type="button" @click="delete cConfig.selectedView">
|
|
12
|
+
<svg width="16" height="16" class="fill-text" 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
|
+
</button>
|
|
14
|
+
<h5>{{ selectedView.type }}</h5>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="flex-1">
|
|
18
|
+
|
|
19
|
+
<component :is="`${selectedView.type}Setting`"
|
|
20
|
+
:preset="selectedPreset"
|
|
21
|
+
:value="selectedView" />
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div v-else-if="selectedDatasource" class="flex-1 flex flex-col gap-3 p-3">
|
|
27
|
+
<div class="p-3 flex flex-row gap-2">
|
|
28
|
+
<button type="button" @click="delete cConfig.selectedDatasource">
|
|
29
|
+
<svg width="16" height="16" class="fill-text" 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>
|
|
30
|
+
</button>
|
|
31
|
+
<h5 @click="log(selectedDatasource)">{{ selectedDatasource.name }}</h5>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="flex justify-center">
|
|
35
|
+
<Tabs :items="datasourceTabs" v-model="datasourceTabIndex" />
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div>
|
|
39
|
+
|
|
40
|
+
<div v-if="datasourceTabIndex === 1">
|
|
41
|
+
<ListItem :items="selectedDatasource.columns"
|
|
42
|
+
@reorder="(from, to) => { selectedDatasource.columns.splice(to, 0, selectedDatasource.columns.splice(from, 1)[0]) }"
|
|
43
|
+
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
44
|
+
container-class="divide-y divide-text-50">
|
|
45
|
+
<template v-slot="{ item }">
|
|
46
|
+
<div class="flex flex-row gap-2 items-center px-2 bg-base-500">
|
|
47
|
+
<div data-reorder>
|
|
48
|
+
<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>
|
|
49
|
+
</div>
|
|
50
|
+
<Textbox class="flex-1 border-none" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
|
|
51
|
+
item-class="p-1" />
|
|
52
|
+
<button type="button" @click="selectedDatasource.columns.splice(index, 1);">
|
|
53
|
+
<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>
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
</ListItem>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div v-else-if="datasourceTabIndex === 2">
|
|
61
|
+
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div v-else-if="selectedPreset" class="flex-1 flex flex-col p-3">
|
|
68
|
+
<div class="p-3 flex flex-row gap-2">
|
|
69
|
+
<button type="button" @click="$router.replace({ hash:'' })">
|
|
70
|
+
<svg width="16" height="16" class="fill-text" 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>
|
|
71
|
+
</button>
|
|
72
|
+
<Textbox v-model="selectedPreset.name"
|
|
73
|
+
item-class="p-0 text-lg"
|
|
74
|
+
@click="log(selectedPreset)"
|
|
75
|
+
class="border-none bg-transparent"/>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="flex-1">
|
|
79
|
+
<div class="p-3">
|
|
80
|
+
<div class="flex flex-row gap-2">
|
|
81
|
+
<label class="flex-1">Datasource</label>
|
|
82
|
+
<button type="button"
|
|
83
|
+
class="text-primary"
|
|
84
|
+
@click="$refs.chooseDatasource.open()">
|
|
85
|
+
Add Datasource
|
|
86
|
+
</button>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="flex flex-col mt-2">
|
|
89
|
+
<ListItem :items="selectedPreset.datasource">
|
|
90
|
+
<template v-slot="{ item, index }">
|
|
91
|
+
<div class="flex flex-row items-center gap-3 p-3">
|
|
92
|
+
<div class="flex-1" @click="cConfig.selectedDatasource = item.uid">
|
|
93
|
+
{{ item.name }}
|
|
94
|
+
</div>
|
|
95
|
+
<button type="button" @click="selectedPreset.datasource.splice(index, 1)">
|
|
96
|
+
<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>
|
|
97
|
+
</button>
|
|
98
|
+
</div>
|
|
99
|
+
</template>
|
|
100
|
+
</ListItem>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div class="p-3">
|
|
105
|
+
<div class="flex flex-row gap-2">
|
|
106
|
+
<label class="flex-1">Views</label>
|
|
107
|
+
<button type="button" class="text-primary"
|
|
108
|
+
@click="$refs.chooseView.open(_ => selectedPreset.views.push(_))">
|
|
109
|
+
Add View
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="flex flex-col">
|
|
113
|
+
<TreeView :items="selectedPreset.views"
|
|
114
|
+
:config="componentsConfig"
|
|
115
|
+
v-model="selectedViewUid"
|
|
116
|
+
class="mt-2">
|
|
117
|
+
<template #item="{ item, parent }">
|
|
118
|
+
<div class="flex-1 p-3 overflow-hidden text-ellipsis cursor-pointer flex flex-row gap-2">
|
|
119
|
+
<div class="flex-1">
|
|
120
|
+
<strong @click="cConfig.selectedView = item.uid" class="hover:text-primary">{{ item.text }}</strong>
|
|
121
|
+
</div>
|
|
122
|
+
<button type="button"
|
|
123
|
+
v-if="Array.isArray(item.items)"
|
|
124
|
+
@click="$refs.chooseView.open(_ => item.items.push(_))">
|
|
125
|
+
<svg width="14" height="14" class="fill-text-300 hover:fill-primary-600" 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 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z"/></svg>
|
|
126
|
+
</button>
|
|
127
|
+
<button type="button" @click="parent.splice(parent.indexOf(item), 1)">
|
|
128
|
+
<svg width="14" height="14" class="fill-text-300 hover:fill-red-600" 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 361.4c12.5 12.5 12.5 32.75 0 45.25C304.4 412.9 296.2 416 288 416s-16.38-3.125-22.62-9.375L160 301.3L54.63 406.6C48.38 412.9 40.19 416 32 416S15.63 412.9 9.375 406.6c-12.5-12.5-12.5-32.75 0-45.25l105.4-105.4L9.375 150.6c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L160 210.8l105.4-105.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-105.4 105.4L310.6 361.4z"/></svg>
|
|
129
|
+
</button>
|
|
130
|
+
</div>
|
|
131
|
+
</template>
|
|
132
|
+
</TreeView>
|
|
133
|
+
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div v-else class="flex-1 flex flex-col">
|
|
141
|
+
<div class="p-6 flex flex-row items-start gap-2">
|
|
142
|
+
<div class="flex-1">
|
|
143
|
+
<h5 @click="log(cConfig)">{{ title }}</h5>
|
|
144
|
+
</div>
|
|
145
|
+
<button type="button" @click="addPreset">
|
|
146
|
+
<svg width="19" height="19" 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 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z"/></svg>
|
|
147
|
+
</button>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div v-if="(cConfig.presets ?? []).length > 0" class="flex-1 overflow-y-auto px-6">
|
|
151
|
+
<ListItem :items="cConfig.presets" container-class="divide-y divide-text-50">
|
|
152
|
+
<template v-slot="{ item, index }">
|
|
153
|
+
<div class="flex flex-row items-center gap-3 p-3">
|
|
154
|
+
<Radio v-model="cConfig.viewedUid" :value="item.uid" />
|
|
155
|
+
<div class="flex-1" @click="openPreset(item.uid)">
|
|
156
|
+
{{ item.name }}
|
|
157
|
+
</div>
|
|
158
|
+
<button type="button" @click="confirm('Remove this preset?', () => cConfig.presets.splice(index, 1))">
|
|
159
|
+
<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>
|
|
160
|
+
</button>
|
|
161
|
+
</div>
|
|
162
|
+
</template>
|
|
163
|
+
</ListItem>
|
|
164
|
+
</div>
|
|
165
|
+
<div v-else class="flex-1 flex items-center justify-center">
|
|
166
|
+
<button type="button"
|
|
167
|
+
class="cursor-pointer flex flex-col gap-1 items-center"
|
|
168
|
+
@click="addPreset">
|
|
169
|
+
<svg width="21" height="21" 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 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z"/></svg>
|
|
170
|
+
Create new preset
|
|
171
|
+
</button>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
</TransitionGroup>
|
|
177
|
+
|
|
178
|
+
<div :class="$style.resize1"
|
|
179
|
+
@mousedown="(e) => $util.dragResize(e, resize1)"></div>
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
<div v-if="viewedPreset" class="flex-1 px-8 py-5 overflow-y-auto flex flex-col gap-6">
|
|
183
|
+
|
|
184
|
+
<div class="flex flex-row gap-2 md:gap-2 items-center" ref="title">
|
|
185
|
+
<button type="button"
|
|
186
|
+
class="p-2 rounded-xl"
|
|
187
|
+
:class="sidebar.open ? 'bg-primary' : ''"
|
|
188
|
+
@click="sidebar.open = !sidebar.open">
|
|
189
|
+
<svg width="21" height="21" :class="sidebar.open ? 'fill-text' : 'fill-text hover:fill-primary'" 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="M480 384H249.2C236.9 355.8 208.8 336 176 336S115.1 355.8 102.8 384H32c-17.67 0-32 14.33-32 32s14.33 32 32 32h70.75C115.1 476.2 143.2 496 176 496s60.89-19.77 73.25-48H480c17.67 0 32-14.33 32-32S497.7 384 480 384zM176 448c-17.64 0-32-14.36-32-32s14.36-32 32-32s32 14.36 32 32S193.6 448 176 448zM480 224h-70.75C396.9 195.8 368.8 176 336 176S275.1 195.8 262.8 224H32C14.33 224 0 238.3 0 256s14.33 32 32 32h230.8C275.1 316.2 303.2 336 336 336s60.89-19.77 73.25-48H480c17.67 0 32-14.33 32-32S497.7 224 480 224zM336 288c-17.64 0-32-14.36-32-32s14.36-32 32-32s32 14.36 32 32S353.6 288 336 288zM32 128h102.8C147.1 156.2 175.2 176 208 176s60.89-19.77 73.25-48H480c17.67 0 32-14.33 32-32s-14.33-32-32-32h-198.8C268.9 35.77 240.8 16 208 16S147.1 35.77 134.8 64H32C14.33 64 0 78.33 0 96S14.33 128 32 128zM208 64c17.64 0 32 14.36 32 32s-14.36 32-32 32s-32-14.36-32-32S190.4 64 208 64z"/></svg>
|
|
190
|
+
</button>
|
|
191
|
+
<div class="flex flex-col whitespace-nowrap text-ellipsis overflow-hidden">
|
|
192
|
+
<div class="cursor-pointer group px-2 md:px-0" @click="$refs.contextMenu.open($refs.title)">
|
|
193
|
+
<small class="text-text-400 text-xs">{{ title ?? 'Untitled' }}</small>
|
|
194
|
+
<div class="flex flex-row items-baseline gap-1">
|
|
195
|
+
<h5 class="whitespace-nowrap relative top-[-2px] text-ellipsis overflow-hidden group-hover:text-primary">
|
|
196
|
+
{{ viewedPreset.name ?? 'Preset Name' }}
|
|
197
|
+
</h5>
|
|
198
|
+
<svg width="13" height="13" class="fill-text group-hover:fill-primary relative top-[-1px]" 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>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
<ContextMenu ref="contextMenu" class="panel-400">
|
|
202
|
+
<div class="flex flex-col min-w-[300px] divide-y divide-text-50">
|
|
203
|
+
|
|
204
|
+
<div class="p-3 flex flex-col gap-1 bg-base-300">
|
|
205
|
+
<button v-for="(preset, idx) in config.presets"
|
|
206
|
+
class="p-2 px-5 text-left flex flex-row items-center rounded-md"
|
|
207
|
+
:class="config.presetIdx === idx ? 'bg-primary-200 text-white' : 'hover:bg-primary-100'"
|
|
208
|
+
type="button"
|
|
209
|
+
@click="selectPreset(idx)">
|
|
210
|
+
<label class="flex-1 pr-12">
|
|
211
|
+
{{ preset.name }}
|
|
212
|
+
</label>
|
|
213
|
+
<div class="p-1">
|
|
214
|
+
<div v-if="idx < 10"
|
|
215
|
+
class="border-[1px] border-text-300 px-2 text-mono text-xs text-text-400 rounded-lg">
|
|
216
|
+
Alt {{ idx + 1 }}
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</button>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
<div class="px-3">
|
|
223
|
+
<button type="button" class="text-primary p-5 text-left w-full" @click="openPreset">Edit</button>
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
</div>
|
|
227
|
+
</ContextMenu>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
<div v-for="view in viewedPreset.views">
|
|
232
|
+
|
|
233
|
+
<div v-if="view.type === 'Row'" class="grid grid-cols-6 gap-5">
|
|
234
|
+
<div v-for="subView in view.items">
|
|
235
|
+
|
|
236
|
+
<Doughnut v-if="subView.type === 'Doughnut'"
|
|
237
|
+
:items="data[subView.datasourceUid]?.items"
|
|
238
|
+
:="subView" />
|
|
239
|
+
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<VirtualTable v-if="view.type === 'VirtualTable'"
|
|
244
|
+
:columns="viewColumns(view)"
|
|
245
|
+
class="h-[50vh]"
|
|
246
|
+
:items="data[view.datasourceUid]?.items" />
|
|
247
|
+
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<DatasourceSelector ref="chooseDatasource"
|
|
253
|
+
:src="datasourceSrc"
|
|
254
|
+
@add="addDatasource" />
|
|
255
|
+
|
|
256
|
+
<ViewSelector ref="chooseView" />
|
|
257
|
+
|
|
258
|
+
</div>
|
|
259
|
+
</template>
|
|
260
|
+
|
|
261
|
+
<script>
|
|
262
|
+
|
|
263
|
+
import DatasourceSelector from "./Dashboard/DatasourceSelector.vue";
|
|
264
|
+
import ViewSelector from "./Dashboard/ViewSelector.vue";
|
|
265
|
+
import md5 from "md5";
|
|
266
|
+
import TreeView from "./WebPageBuilder4/TreeView.vue";
|
|
267
|
+
import Doughnut from "./Dashboard/Doughnut.vue";
|
|
268
|
+
import DoughnutSetting from "./Dashboard/DoughnutSetting.vue";
|
|
269
|
+
import VirtualTableSetting from "./Dashboard/VirtualTableSetting.vue";
|
|
270
|
+
|
|
271
|
+
const findComponents = (items, uid) => {
|
|
272
|
+
if(!Array.isArray(items)) return
|
|
273
|
+
|
|
274
|
+
for(let item of items){
|
|
275
|
+
if(item.uid === uid)
|
|
276
|
+
return item
|
|
277
|
+
|
|
278
|
+
if(item.items){
|
|
279
|
+
const component = findComponents(item.items, uid)
|
|
280
|
+
if(component)
|
|
281
|
+
return component
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export default{
|
|
287
|
+
components: {
|
|
288
|
+
Doughnut,
|
|
289
|
+
DoughnutSetting,
|
|
290
|
+
TreeView,
|
|
291
|
+
ViewSelector,
|
|
292
|
+
DatasourceSelector,
|
|
293
|
+
VirtualTableSetting,
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
computed: {
|
|
297
|
+
|
|
298
|
+
cConfig(){
|
|
299
|
+
return this.config ?? this._config
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
componentsConfig(){
|
|
303
|
+
if(!this.cConfig.components)
|
|
304
|
+
this.cConfig.components = {}
|
|
305
|
+
return this.cConfig.components
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
selectedDatasource(){
|
|
309
|
+
const datasource = this.selectedPreset?.datasource[this.selectedPreset.datasource.findIndex(_ => _.uid === this.cConfig.selectedDatasource)]
|
|
310
|
+
|
|
311
|
+
if(datasource){
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return datasource
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
selectedPreset(){
|
|
321
|
+
const preset = this.cConfig.presets[this.cConfig.presets.findIndex(_ => _.uid === this.cConfig.selectedUid)]
|
|
322
|
+
|
|
323
|
+
if(preset){
|
|
324
|
+
if(!Array.isArray(preset.datasource))
|
|
325
|
+
preset.datasource = []
|
|
326
|
+
|
|
327
|
+
if(!Array.isArray(preset.views))
|
|
328
|
+
preset.views = []
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return preset
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
selectedView(){
|
|
335
|
+
return findComponents(this.selectedPreset?.views, this.cConfig.selectedView)
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
sidebar(){
|
|
339
|
+
if(!this.cConfig.sidebar || !('open' in this.cConfig.sidebar))
|
|
340
|
+
this.cConfig.sidebar = {
|
|
341
|
+
open: true,
|
|
342
|
+
width: 360
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return this.cConfig.sidebar
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
sidebarStyle(){
|
|
349
|
+
return {
|
|
350
|
+
width: !this.sidebar.open ? 0 : this.sidebar.width + 'px'
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
|
|
354
|
+
viewedPreset(){
|
|
355
|
+
return this.cConfig?.presets[this.cConfig.presets.findIndex(_ => _.uid === this.cConfig.viewedUid)]
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
data(){
|
|
361
|
+
return {
|
|
362
|
+
data: {},
|
|
363
|
+
|
|
364
|
+
datasourceTabs: [
|
|
365
|
+
{ text:"Columns", value:1 },
|
|
366
|
+
{ text:"Filters", value:2 },
|
|
367
|
+
{ text:"Sorts", value:3 },
|
|
368
|
+
],
|
|
369
|
+
|
|
370
|
+
datasourceTabIndex: 1,
|
|
371
|
+
|
|
372
|
+
selectedViewUid: null
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
inject: [ 'alert', 'confirm', 'socket' ],
|
|
377
|
+
|
|
378
|
+
methods: {
|
|
379
|
+
|
|
380
|
+
addDatasource(datasource){
|
|
381
|
+
this.selectedPreset.datasource.push(datasource)
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
addPreset(){
|
|
385
|
+
if(!Array.isArray(this.cConfig.presets))
|
|
386
|
+
this.cConfig.presets = []
|
|
387
|
+
|
|
388
|
+
const newPreset = {
|
|
389
|
+
name: 'New Preset',
|
|
390
|
+
uid: md5('Preset' + Date.now()),
|
|
391
|
+
}
|
|
392
|
+
this.cConfig.presets.push(newPreset)
|
|
393
|
+
this.openPreset(newPreset.uid)
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
viewColumns(view){
|
|
397
|
+
|
|
398
|
+
if(!view.columns){
|
|
399
|
+
view.columns = Object.keys(((this.data[view.datasourceUid] ?? {}).items ?? [])[0] ?? [])
|
|
400
|
+
.map(key => {
|
|
401
|
+
return {
|
|
402
|
+
key,
|
|
403
|
+
label: key
|
|
404
|
+
}
|
|
405
|
+
})
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return view.columns
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
async load(){
|
|
412
|
+
for(let datasource of this.viewedPreset?.datasource ?? []){
|
|
413
|
+
this.socket.send(datasource.src)
|
|
414
|
+
.then(res => {
|
|
415
|
+
this.data[datasource.uid] = res
|
|
416
|
+
})
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
|
|
420
|
+
openPreset(uid){
|
|
421
|
+
this.$router.push({ hash:`#dashboard-${uid}` })
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
resize1(w){
|
|
425
|
+
if(this.sidebar.width + w >= 270 && this.sidebar.width + w <= 600){
|
|
426
|
+
this.sidebar.width += w
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
|
|
430
|
+
},
|
|
431
|
+
|
|
432
|
+
props:{
|
|
433
|
+
|
|
434
|
+
config: Object,
|
|
435
|
+
|
|
436
|
+
datasourceSrc: String,
|
|
437
|
+
|
|
438
|
+
title: String,
|
|
439
|
+
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
provide(){
|
|
443
|
+
return {
|
|
444
|
+
listStyle: () => {}
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
watch: {
|
|
449
|
+
|
|
450
|
+
'cConfig.presets'(){
|
|
451
|
+
if(this.$route.hash.startsWith('#dashboard')){
|
|
452
|
+
this.cConfig.selectedUid = this.$route.hash.replace('#dashboard-', '')
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
this.cConfig.selectedUid = false
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
'$route.hash': {
|
|
460
|
+
immediate: true,
|
|
461
|
+
handler(to){
|
|
462
|
+
if(this.cConfig){
|
|
463
|
+
if(to.startsWith('#dashboard')){
|
|
464
|
+
this.cConfig.selectedUid = to.replace('#dashboard-', '')
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
this.cConfig.selectedUid = false
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
|
|
473
|
+
viewedPreset: {
|
|
474
|
+
immediate: true,
|
|
475
|
+
handler(){
|
|
476
|
+
this.load()
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
</script>
|
|
485
|
+
|
|
486
|
+
<style>
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
</style>
|
|
491
|
+
|
|
492
|
+
<style module>
|
|
493
|
+
|
|
494
|
+
.comp{
|
|
495
|
+
@apply flex flex-row;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.resize1{
|
|
499
|
+
@apply w-[3px] cursor-ew-resize absolute top-0 right-0 bottom-0;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
</style>
|