@mixd-id/web-scaffold 0.1.250801002 → 0.1.250801004
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/docs/components/Dashboard.md +56 -0
- package/package.json +1 -1
- package/src/components/Dashboard.vue +216 -0
- package/src/components/DashboardComponentSelector.vue +88 -0
- package/src/components/DashboardConfigs.vue +202 -0
- package/src/components/Dropdown.vue +1 -1
- package/src/components/List.vue +15 -15
- package/src/components/MarkdownEdit.vue +8 -3
- package/src/components/MarkdownPreview.vue +102 -0
- package/src/components/Modal.vue +31 -6
- package/src/components/OTPField.vue +3 -3
- package/src/components/Switch.vue +1 -1
- package/src/components/TextEditor.vue +2 -2
- package/src/components/TextWithTag.vue +1 -1
- package/src/components/Textbox.vue +1 -0
- package/src/components/TreeView2.vue +5 -3
- package/src/components/TreeViewItem2.vue +13 -6
- package/src/components/VirtualTable.vue +7 -10
- package/src/index.js +3 -1
- package/src/themes/default/index.js +1 -6
- package/src/utils/wss.mjs +0 -2
- package/src/widgets/ComponentSetting2.vue +1 -11
- package/src/widgets/Dashboard/VirtualTableSetting.vue +121 -180
- package/src/widgets/GridSetting.vue +0 -18
- /package/src/widgets/{Dashboard.vue → Dashboard0.vue} +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Dashboard
|
|
2
|
+
Dashboard components
|
|
3
|
+
|
|
4
|
+
## Configs
|
|
5
|
+
| Property | Type | Default | Description |
|
|
6
|
+
|----------|------|---------|-------------|
|
|
7
|
+
| params | Object | {} | | Dashboard parameters |
|
|
8
|
+
| params.presetUid | String | "" | | Preset unique identifier |
|
|
9
|
+
|
|
10
|
+
## Samples
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"params": {
|
|
14
|
+
"presetUid": "abc",
|
|
15
|
+
"viewUid": "def"
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
"presets": [
|
|
19
|
+
|
|
20
|
+
{
|
|
21
|
+
"name": "Preset Name",
|
|
22
|
+
|
|
23
|
+
"views": [
|
|
24
|
+
{
|
|
25
|
+
"type": "Grid",
|
|
26
|
+
"uid": ":uid"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
|
|
30
|
+
"datasource": {
|
|
31
|
+
|
|
32
|
+
":uid": {
|
|
33
|
+
"uid": ":uid",
|
|
34
|
+
"datasourceUid": "234",
|
|
35
|
+
"filters": [],
|
|
36
|
+
"sorts": [],
|
|
37
|
+
"groups": [],
|
|
38
|
+
"pivot": []
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## Sub Components
|
|
51
|
+
|
|
52
|
+
### Dashboard Configs
|
|
53
|
+
Dashboard configuration panel
|
|
54
|
+
|
|
55
|
+
### Dashboard Component Selector
|
|
56
|
+
Component selector for adding component to preset views
|
package/package.json
CHANGED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.comp">
|
|
3
|
+
|
|
4
|
+
<div :style="leftStyle" class="relative flex flex-col">
|
|
5
|
+
<DashboardConfigs :config="config" class="flex-1" />
|
|
6
|
+
|
|
7
|
+
<div :class="$style.resize1" @mousedown="(e) => $util.dragResize(e, resize1)"></div>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div class="flex-1 flex flex-col gap-4 py-4">
|
|
11
|
+
|
|
12
|
+
<div class="px-8 flex flex-row gap-6 items-center">
|
|
13
|
+
<h3>{{ preset?.name }}</h3>
|
|
14
|
+
<button type="button" class="p-3" @click="load">
|
|
15
|
+
<svg width="16" height="16" class="fill-primary hover:fill-primary-600" 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="M468.9 32.11c13.87 0 27.18 10.77 27.18 27.04v145.9c0 10.59-8.584 19.17-19.17 19.17h-145.7c-16.28 0-27.06-13.32-27.06-27.2c0-6.634 2.461-13.4 7.96-18.9l45.12-45.14c-28.22-23.14-63.85-36.64-101.3-36.64c-88.09 0-159.8 71.69-159.8 159.8S167.8 415.9 255.9 415.9c73.14 0 89.44-38.31 115.1-38.31c18.48 0 31.97 15.04 31.97 31.96c0 35.04-81.59 70.41-147 70.41c-123.4 0-223.9-100.5-223.9-223.9S132.6 32.44 256 32.44c54.6 0 106.2 20.39 146.4 55.26l47.6-47.63C455.5 34.57 462.3 32.11 468.9 32.11z"/></svg>
|
|
16
|
+
</button>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="flex-1 overflow-y-auto px-8">
|
|
20
|
+
<component :is="component.type"
|
|
21
|
+
v-for="component in components"
|
|
22
|
+
:="component" />
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script setup>
|
|
31
|
+
|
|
32
|
+
import {computed, inject, onMounted, ref, watch} from "vue";
|
|
33
|
+
import DashboardConfigs from "./DashboardConfigs.vue";
|
|
34
|
+
|
|
35
|
+
const { controller, presetKey } = defineProps({
|
|
36
|
+
|
|
37
|
+
controller: {
|
|
38
|
+
type: String,
|
|
39
|
+
required: true
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
presetKey: { type: String },
|
|
43
|
+
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const alert = inject('alert')
|
|
47
|
+
const loadConfig = inject('loadConfig')
|
|
48
|
+
const saveConfig = inject('saveConfig')
|
|
49
|
+
const useSocket = inject('useSocket')
|
|
50
|
+
const socket = useSocket()
|
|
51
|
+
|
|
52
|
+
const config = ref(Object.assign({
|
|
53
|
+
params: {},
|
|
54
|
+
presets: []
|
|
55
|
+
}, presetKey ? await loadConfig(presetKey, {}) : {}))
|
|
56
|
+
|
|
57
|
+
const data = ref({})
|
|
58
|
+
|
|
59
|
+
console.log('Config', config)
|
|
60
|
+
|
|
61
|
+
const leftStyle = computed(() => {
|
|
62
|
+
if(!config.value.params.leftWidth)
|
|
63
|
+
config.value.params.leftWidth = 300
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
width: `${config.value.params.leftWidth}px`
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
function load(){
|
|
71
|
+
if(!preset.value) return
|
|
72
|
+
|
|
73
|
+
socket.send(`${controller}.load`, preset.value.datasource)
|
|
74
|
+
.then(res => Object.assign(data.value, res))
|
|
75
|
+
.catch(err => alert(err))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function resize1(w){
|
|
79
|
+
if(config.value.params.leftWidth + w >= 100 && config.value.params.leftWidth + w <= 600){
|
|
80
|
+
config.value.params.leftWidth += w
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const preset = computed(() => {
|
|
85
|
+
return (config.value.presets ?? []).find(_ => _.uid === config.value.params.presetUid)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
const selectedPreset = computed(() => {
|
|
89
|
+
return (config.value.presets ?? []).find(_ => _.uid === config.value.params.selectedUid)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const compClasses = [
|
|
93
|
+
'aspectRatio', 'position', 'left', 'top', 'right', 'bottom',
|
|
94
|
+
|
|
95
|
+
'bdSize', 'bdColor', 'bdRadius', 'bdStyle',
|
|
96
|
+
'divideSize', 'divideColor', 'divideStyle',
|
|
97
|
+
'outlineWidth', 'outlineColor', 'outlineStyle',
|
|
98
|
+
'bgColors', 'bgSize', 'bgPosition', 'bgRepeat',
|
|
99
|
+
'textAlign', 'verticalAlign',
|
|
100
|
+
'gap',
|
|
101
|
+
'padding', 'margin',
|
|
102
|
+
'direction', 'columns', 'rows', 'display', 'wrap',
|
|
103
|
+
'width', 'minWidth', 'maxWidth',
|
|
104
|
+
'height', 'minHeight', 'maxHeight',
|
|
105
|
+
'fontFamily', 'fontSize', 'fontWeight', 'textColor', 'lineHeight', 'overflow',
|
|
106
|
+
'textTransform', 'whitespace', 'textOverflow', 'textDecoration',
|
|
107
|
+
'boxShadow', 'opacity',
|
|
108
|
+
'colSpan', 'rowSpan',
|
|
109
|
+
'flex', 'flexAlign', 'flexJustify', 'flexBasis', 'flexColumns', 'flexWrap',
|
|
110
|
+
'flexDirection',
|
|
111
|
+
'zIndex',
|
|
112
|
+
|
|
113
|
+
'autoFlow', 'alignItems', 'justifyContent',
|
|
114
|
+
'letterSpacing', 'lineClamp',
|
|
115
|
+
|
|
116
|
+
'animate',
|
|
117
|
+
|
|
118
|
+
'blur', 'grayscale',
|
|
119
|
+
]
|
|
120
|
+
const containerClasses = [
|
|
121
|
+
'containerVariant', 'containerGridColumn', 'containerGap'
|
|
122
|
+
]
|
|
123
|
+
const itemClasses = [
|
|
124
|
+
'itemMinWidth', 'itemRatio', 'itemVariant'
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
const components = computed(() => {
|
|
128
|
+
if(!selectedPreset.value) return
|
|
129
|
+
|
|
130
|
+
const getComponent = (component) => {
|
|
131
|
+
if (!component.uid) return
|
|
132
|
+
if (!component.props.enabled) return
|
|
133
|
+
|
|
134
|
+
const compUid = '_' + component.uid.substring(0, 4) + ' '
|
|
135
|
+
|
|
136
|
+
const instance = {
|
|
137
|
+
type: component.type,
|
|
138
|
+
uid: component.uid,
|
|
139
|
+
|
|
140
|
+
class: compUid + compClasses.map(key => {
|
|
141
|
+
return Array.isArray(component.props[key]) ? component.props[key].join(' ') : ''
|
|
142
|
+
})
|
|
143
|
+
.filter(_ => _)
|
|
144
|
+
.join(' '),
|
|
145
|
+
|
|
146
|
+
containerClass: containerClasses.map(key => {
|
|
147
|
+
return Array.isArray(component.props[key]) ? component.props[key].join(' ') : ''
|
|
148
|
+
})
|
|
149
|
+
.filter(_ => _)
|
|
150
|
+
.join(' '),
|
|
151
|
+
|
|
152
|
+
itemClass: itemClasses.map(key => {
|
|
153
|
+
return Array.isArray(component.props[key]) ? component.props[key].join(' ') : ''
|
|
154
|
+
})
|
|
155
|
+
.filter(_ => _)
|
|
156
|
+
.join(' ')
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
for (let key in component.props) {
|
|
160
|
+
if (!compClasses.includes(key) &&
|
|
161
|
+
!containerClasses.includes(key) &&
|
|
162
|
+
!itemClasses.includes(key) &&
|
|
163
|
+
!['enabled'].includes(key)) {
|
|
164
|
+
instance[key] = component.props[key]
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const whitelistProps = [
|
|
169
|
+
'column', 'datasourceUid', 'rows', 'columns'
|
|
170
|
+
]
|
|
171
|
+
whitelistProps.forEach((key) => {
|
|
172
|
+
if (component.props[key]) {
|
|
173
|
+
instance[key] = component.props[key]
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
if(data.value[component.uid]){
|
|
178
|
+
instance.items = data.value[component.uid].items
|
|
179
|
+
}
|
|
180
|
+
else if(Array.isArray(component.items)) {
|
|
181
|
+
instance.items = component.items.map((_) => getComponent(_)).filter(_ => _)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return instance
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return selectedPreset.value.views.map(view => {
|
|
188
|
+
return getComponent(view)
|
|
189
|
+
})
|
|
190
|
+
.filter(_ => _)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
if(presetKey){
|
|
194
|
+
console.log('Watch config changes')
|
|
195
|
+
watch(() => config, _ => saveConfig(presetKey, config.value), {
|
|
196
|
+
deep: true
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
onMounted(() => {
|
|
201
|
+
load()
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
</script>
|
|
205
|
+
|
|
206
|
+
<style module>
|
|
207
|
+
|
|
208
|
+
.comp {
|
|
209
|
+
@apply flex flex-row divide-x divide-text-50;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.resize1{
|
|
213
|
+
@apply w-[3px] cursor-ew-resize absolute top-0 right-0 bottom-0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
</style>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal ref="modal" width="360" height="480">
|
|
3
|
+
<template v-slot:head>
|
|
4
|
+
<div class="relative p-5">
|
|
5
|
+
<h3>Select Component</h3>
|
|
6
|
+
<div class="absolute top-0 right-0 p-2">
|
|
7
|
+
<button type="button" class="p-2" @click="$refs.modal.close()">
|
|
8
|
+
<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">
|
|
9
|
+
<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"/>
|
|
10
|
+
</svg>
|
|
11
|
+
</button>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
<template v-slot:foot>
|
|
16
|
+
<div class="p-5">
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
<div class="flex-1 divide-y divide-text-50">
|
|
21
|
+
|
|
22
|
+
<div class="flex flex-col">
|
|
23
|
+
<button v-for="component of components"
|
|
24
|
+
class="p-3 px-6 text-left"
|
|
25
|
+
@click="add(component)">
|
|
26
|
+
{{ component.type }}
|
|
27
|
+
</button>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
</div>
|
|
32
|
+
</Modal>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
|
|
37
|
+
import {ref, useTemplateRef} from "vue";
|
|
38
|
+
import md5 from "md5";
|
|
39
|
+
|
|
40
|
+
const modal = useTemplateRef('modal')
|
|
41
|
+
const callback = ref(null)
|
|
42
|
+
|
|
43
|
+
function open(_, cb){
|
|
44
|
+
callback.value = cb
|
|
45
|
+
modal.value.open()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function add(component){
|
|
49
|
+
if(typeof callback.value === 'function'){
|
|
50
|
+
const newComponent = JSON.parse(JSON.stringify(component))
|
|
51
|
+
newComponent.uid = md5(new Date().toString())
|
|
52
|
+
callback.value(newComponent)
|
|
53
|
+
}
|
|
54
|
+
modal.value.close()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const components = ref([
|
|
58
|
+
{
|
|
59
|
+
type: "Grid",
|
|
60
|
+
name: "Grid",
|
|
61
|
+
props: {
|
|
62
|
+
enabled: true
|
|
63
|
+
},
|
|
64
|
+
items: []
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: "VirtualTable",
|
|
68
|
+
name: "Virtual Table",
|
|
69
|
+
props: {
|
|
70
|
+
enabled: true
|
|
71
|
+
},
|
|
72
|
+
items: []
|
|
73
|
+
}
|
|
74
|
+
])
|
|
75
|
+
|
|
76
|
+
defineExpose({
|
|
77
|
+
open
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<style module>
|
|
83
|
+
|
|
84
|
+
.comp{
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
</style>
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col overflow-hidden relative">
|
|
3
|
+
|
|
4
|
+
<TransitionGroup name="openltr" tag="div" class="flex-1 flex flex-col">
|
|
5
|
+
|
|
6
|
+
<div v-if="view" class="flex-1 flex flex-col">
|
|
7
|
+
|
|
8
|
+
<div class="flex flex-row items-center gap-2 p-5">
|
|
9
|
+
<button type="button" @click="delete config.params.viewUid">
|
|
10
|
+
<svg width="14" height="14" 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>
|
|
11
|
+
</button>
|
|
12
|
+
<div class="flex-1">
|
|
13
|
+
<h5>{{ view.name }}</h5>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="flex-1 overflow-y-auto">
|
|
18
|
+
<component :is="`${view.type}Setting`"
|
|
19
|
+
:item="view"
|
|
20
|
+
:view-types="viewTypes"
|
|
21
|
+
:view-index="viewIndex"
|
|
22
|
+
:view-type="viewType">
|
|
23
|
+
</component>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div v-else-if="preset" class="flex-1 flex flex-col">
|
|
29
|
+
<div class="flex flex-row items-center gap-2 p-5">
|
|
30
|
+
<button type="button" @click="delete config.params.presetUid">
|
|
31
|
+
<svg width="14" height="14" 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>
|
|
32
|
+
</button>
|
|
33
|
+
<div class="flex-1">
|
|
34
|
+
<h5>{{ preset.name }}</h5>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div class="flex-1 overflow-y-auto">
|
|
39
|
+
<div class="p-5">
|
|
40
|
+
|
|
41
|
+
<div class="flex flex-col gap-1">
|
|
42
|
+
<div class="flex flex-row gap-3">
|
|
43
|
+
<label class="flex-1">Views</label>
|
|
44
|
+
<button type="button"
|
|
45
|
+
class="text-primary"
|
|
46
|
+
@click="$refs.componentSelector.open(null, comp => views.push(comp))">
|
|
47
|
+
Add
|
|
48
|
+
</button>
|
|
49
|
+
</div>
|
|
50
|
+
<TreeView2 :items="views">
|
|
51
|
+
<template #default="{ item, index, parent }">
|
|
52
|
+
<div class="flex flex-row gap-2 bg-base-500 hover:bg-text-50 p-3">
|
|
53
|
+
<div class="flex-1 flex flex-row"
|
|
54
|
+
@click="config.params.viewUid = item.uid">
|
|
55
|
+
<div class="text-ellipsis-nowrap flex-1">
|
|
56
|
+
{{ item.name }}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<button v-if="Array.isArray(item.items)" @click="$refs.componentSelector.open(null, comp => item.items.push(comp))">
|
|
60
|
+
<svg width="14" height="14" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="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>
|
|
61
|
+
</button>
|
|
62
|
+
<button type="button" @click="parent.splice(index, 1)">
|
|
63
|
+
<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>
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
</TreeView2>
|
|
68
|
+
|
|
69
|
+
<DashboardComponentSelector ref="componentSelector" />
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div v-else-if="config" class="flex-1 flex flex-col">
|
|
77
|
+
<div class="p-5">
|
|
78
|
+
<h5>Select Presets</h5>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div class="flex-1 overflow-y-auto">
|
|
82
|
+
<div class="p-5">
|
|
83
|
+
<div class="flex flex-row gap-3">
|
|
84
|
+
<label class="text-text-300 flex-1">Presets</label>
|
|
85
|
+
<button type="button" class="text-primary" @click="addPreset">Add</button>
|
|
86
|
+
</div>
|
|
87
|
+
<ListItem :items="presets"
|
|
88
|
+
class="mt-2"
|
|
89
|
+
@reorder="(from, to) => { presets.splice(to, 0, presets.splice(from, 1)[0]); }">
|
|
90
|
+
<template v-slot="{ item, index }">
|
|
91
|
+
<div class="flex flex-row items-center gap-3 p-3 bg-base-500 hover:bg-text-50">
|
|
92
|
+
<div data-reorder>
|
|
93
|
+
<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>
|
|
94
|
+
</div>
|
|
95
|
+
<Radio :value="item.uid" v-model="config.params.selectedUid" />
|
|
96
|
+
<div class="flex-1" @click="config.params.presetUid = item.uid">
|
|
97
|
+
{{ item.name }}
|
|
98
|
+
</div>
|
|
99
|
+
<div>
|
|
100
|
+
<button type="button" @click="presets.splice(index, 1)">
|
|
101
|
+
<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>
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</template>
|
|
106
|
+
</ListItem>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
</TransitionGroup>
|
|
112
|
+
|
|
113
|
+
</div>
|
|
114
|
+
</template>
|
|
115
|
+
|
|
116
|
+
<script setup>
|
|
117
|
+
|
|
118
|
+
import {computed, provide, ref} from "vue";
|
|
119
|
+
import md5 from "md5";
|
|
120
|
+
import DashboardComponentSelector from "./DashboardComponentSelector.vue";
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
const { config } = defineProps({
|
|
124
|
+
config: {
|
|
125
|
+
type: Object,
|
|
126
|
+
required: true
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const presets = computed(() => {
|
|
131
|
+
if(!Array.isArray(config.presets))
|
|
132
|
+
config.presets = []
|
|
133
|
+
return config.presets
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const preset = computed(() => {
|
|
137
|
+
return (presets.value ?? []).find(_ => _.uid === config.params.presetUid)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
const views = computed(() => {
|
|
141
|
+
if(!preset.value) return []
|
|
142
|
+
|
|
143
|
+
if(!Array.isArray(preset.value.views))
|
|
144
|
+
preset.value.views = []
|
|
145
|
+
return preset.value.views
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const view = computed(() => {
|
|
149
|
+
if(config.params.viewUid && preset){
|
|
150
|
+
|
|
151
|
+
const getView = (uid, items) => {
|
|
152
|
+
for(let item of items){
|
|
153
|
+
if(item.uid === uid){
|
|
154
|
+
return item
|
|
155
|
+
}
|
|
156
|
+
else if(Array.isArray(item.items)){
|
|
157
|
+
const subItem = getView(uid, item.items)
|
|
158
|
+
if(subItem)
|
|
159
|
+
return subItem
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return getView(config.params.viewUid, views.value)
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
const viewTypes = ref([
|
|
169
|
+
{text: 'Mobile', value: ''},
|
|
170
|
+
{text: 'Tablet', value: 'md:'},
|
|
171
|
+
{text: 'Desktop', value: 'xl:'},
|
|
172
|
+
{text: 'TV', value: '2xl:'},
|
|
173
|
+
])
|
|
174
|
+
|
|
175
|
+
const viewIndex = ref(1)
|
|
176
|
+
const viewType = ref('md:')
|
|
177
|
+
|
|
178
|
+
function addPreset(obj){
|
|
179
|
+
|
|
180
|
+
const preset = {
|
|
181
|
+
uid: md5(Date.now().toString() + Math.random().toString()),
|
|
182
|
+
name: "New Preset",
|
|
183
|
+
views: [],
|
|
184
|
+
datasource: {},
|
|
185
|
+
...obj,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
presets.value.push(preset)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function getPresetDatasource(){
|
|
192
|
+
return preset ? preset.value.datasource : {}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
provide('getPresetDatasource', getPresetDatasource)
|
|
196
|
+
|
|
197
|
+
</script>
|
|
198
|
+
|
|
199
|
+
<style module>
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
</style>
|
package/src/components/List.vue
CHANGED
|
@@ -288,7 +288,7 @@ export default{
|
|
|
288
288
|
|
|
289
289
|
emits: [ 'dragover', 'after-load', 'open-preset', 'signal', 'pivot-item-click' ],
|
|
290
290
|
|
|
291
|
-
inject: [ 'socket', 'toast' ],
|
|
291
|
+
inject: [ 'useSocket', 'socket', 'toast' ],
|
|
292
292
|
|
|
293
293
|
props: {
|
|
294
294
|
config: Object,
|
|
@@ -390,7 +390,7 @@ export default{
|
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
this.readyState = 2
|
|
393
|
-
return this.
|
|
393
|
+
return this.useSocket().send(this.computedSrc, {
|
|
394
394
|
...this.preset,
|
|
395
395
|
id: undefined,
|
|
396
396
|
uid: undefined,
|
|
@@ -419,7 +419,7 @@ export default{
|
|
|
419
419
|
const afterItem = this.dataItems[this.dataItems.length - 1]
|
|
420
420
|
|
|
421
421
|
this.readyState = 4
|
|
422
|
-
this.
|
|
422
|
+
this.useSocket().send(this.computedSrc, {
|
|
423
423
|
...this.preset,
|
|
424
424
|
id: undefined,
|
|
425
425
|
uid: undefined,
|
|
@@ -442,7 +442,7 @@ export default{
|
|
|
442
442
|
async loadPreset(){
|
|
443
443
|
if(!Object.keys(this.$route.query).map(_ => _.toLowerCase()).includes('reset')){
|
|
444
444
|
if(this.presetKey){
|
|
445
|
-
const config = await this.
|
|
445
|
+
const config = await this.useSocket().send(this.presetSrc, { key:this.presetKey })
|
|
446
446
|
if(config){
|
|
447
447
|
if((config.presets ?? []).length > 0){
|
|
448
448
|
Object.assign(this.cConfig, config)
|
|
@@ -504,7 +504,7 @@ export default{
|
|
|
504
504
|
if(reqItems.length > 0 && reqItems !== this.lastEnumItems){
|
|
505
505
|
|
|
506
506
|
const [ src, key, attr ] = column.enumSrc.split(':')
|
|
507
|
-
const res = await this.
|
|
507
|
+
const res = await this.useSocket().send(src, {
|
|
508
508
|
columns: [
|
|
509
509
|
{ key:attr, visible:true }
|
|
510
510
|
],
|
|
@@ -538,7 +538,7 @@ export default{
|
|
|
538
538
|
if(!this.extBar.open) return
|
|
539
539
|
|
|
540
540
|
this.readyState = 3
|
|
541
|
-
return this.
|
|
541
|
+
return this.useSocket().send(this.computedSrc, {
|
|
542
542
|
...this.preset,
|
|
543
543
|
id: undefined,
|
|
544
544
|
uid: undefined,
|
|
@@ -557,7 +557,7 @@ export default{
|
|
|
557
557
|
loadExtNext(){
|
|
558
558
|
if(!this.preset.filters) return
|
|
559
559
|
|
|
560
|
-
return this.
|
|
560
|
+
return this.useSocket().send(this.computedSrc, {
|
|
561
561
|
...this.preset,
|
|
562
562
|
id: undefined,
|
|
563
563
|
uid: undefined,
|
|
@@ -591,7 +591,7 @@ export default{
|
|
|
591
591
|
|
|
592
592
|
savePreset: invokeAfterIdle(function() {
|
|
593
593
|
if(this.presetKey) {
|
|
594
|
-
this.
|
|
594
|
+
this.useSocket().send(this.presetSrc,
|
|
595
595
|
{key: this.presetKey, config: this.cConfig})
|
|
596
596
|
}
|
|
597
597
|
}),
|
|
@@ -648,7 +648,7 @@ export default{
|
|
|
648
648
|
loadQueued(items){
|
|
649
649
|
const key = items[0] && items[0].uid ? 'uid' : 'id'
|
|
650
650
|
|
|
651
|
-
this.
|
|
651
|
+
this.useSocket().send(this.computedSrc, {
|
|
652
652
|
...this.preset,
|
|
653
653
|
id: undefined,
|
|
654
654
|
uid: undefined,
|
|
@@ -911,8 +911,8 @@ export default{
|
|
|
911
911
|
})
|
|
912
912
|
|
|
913
913
|
if(this.subscribeKey){
|
|
914
|
-
this.
|
|
915
|
-
this.
|
|
914
|
+
this.useSocket().send('user.subscribe', { name:this.subscribeKey })
|
|
915
|
+
this.useSocket().on(this.subscribeKey, this.onSignal)
|
|
916
916
|
}
|
|
917
917
|
|
|
918
918
|
window.addEventListener('keydown', this.onKeyDown)
|
|
@@ -922,7 +922,7 @@ export default{
|
|
|
922
922
|
delay: this.updateInterval
|
|
923
923
|
})
|
|
924
924
|
|
|
925
|
-
this.
|
|
925
|
+
this.useSocket().on('connect', this.onConnect)
|
|
926
926
|
},
|
|
927
927
|
|
|
928
928
|
unmounted() {
|
|
@@ -930,11 +930,11 @@ export default{
|
|
|
930
930
|
window.removeEventListener('keydown', this.onKeyDown)
|
|
931
931
|
|
|
932
932
|
if(this.subscribeKey) {
|
|
933
|
-
this.
|
|
934
|
-
this.
|
|
933
|
+
this.useSocket().send('user.unsubscribe', {name: this.subscribeKey})
|
|
934
|
+
this.useSocket().off(this.subscribeKey, this.onSignal)
|
|
935
935
|
}
|
|
936
936
|
|
|
937
|
-
this.
|
|
937
|
+
this.useSocket().off('connect', this.onConnect)
|
|
938
938
|
},
|
|
939
939
|
|
|
940
940
|
computed: {
|