@mixd-id/web-scaffold 0.1.230406281 → 0.1.230406282
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/Button.vue +1 -0
- package/src/components/List.vue +149 -69
- package/src/components/Modal.vue +1 -1
- package/src/components/PresetSelectorFilterItem.vue +28 -0
- package/src/components/Tabs.vue +1 -1
- package/src/components/VirtualTable.vue +8 -4
- package/src/themes/default/index.js +22 -0
- package/src/utils/preset-selector.js +126 -16
- package/src/utils/preset-selector.mjs +7 -0
- package/src/utils/wss.mjs +11 -4
- package/src/widgets/PresetBar.vue +56 -36
package/package.json
CHANGED
|
@@ -208,6 +208,7 @@ export default{
|
|
|
208
208
|
|
|
209
209
|
.button-secondary{
|
|
210
210
|
@apply bg-primary-100 border-primary-100 text-primary-700 rounded-lg text-text;
|
|
211
|
+
border: solid 1px rgb(var(--primary-100));
|
|
211
212
|
}
|
|
212
213
|
.button-secondary:hover{
|
|
213
214
|
@apply bg-primary-200 border-primary-200;
|
package/src/components/List.vue
CHANGED
|
@@ -4,48 +4,82 @@
|
|
|
4
4
|
<div v-if="readyState === 1"
|
|
5
5
|
class="flex-1 flex flex-row">
|
|
6
6
|
|
|
7
|
-
<div v-if="computedPresetMode === 'sidebar' &&
|
|
7
|
+
<div v-if="computedPresetMode === 'sidebar' && sidebar.open"
|
|
8
8
|
class="relative flex flex-col border-r-[1px] border-text-50 panel-400"
|
|
9
|
-
:style="
|
|
9
|
+
:style="sidebarStyle">
|
|
10
10
|
|
|
11
11
|
<PresetBar :config="config"
|
|
12
12
|
class="flex-1"
|
|
13
13
|
@apply="load">
|
|
14
|
+
|
|
14
15
|
<template #toolbar>
|
|
15
|
-
<button type="button" class="
|
|
16
|
-
<svg width="
|
|
16
|
+
<button type="button" class="p-1" @click="togglePreset">
|
|
17
|
+
<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"><!--! 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>
|
|
17
18
|
</button>
|
|
18
19
|
</template>
|
|
20
|
+
|
|
19
21
|
</PresetBar>
|
|
20
22
|
|
|
21
|
-
<div v-if="
|
|
23
|
+
<div v-if="sidebar.open"
|
|
22
24
|
:class="$style.resize1"
|
|
23
25
|
@mousedown="(e) => $util.dragResize(e, resize1)"></div>
|
|
24
26
|
</div>
|
|
25
27
|
|
|
26
|
-
<div class="flex-1 flex flex-col
|
|
28
|
+
<div class="flex-1 flex flex-col" :class="containerClass">
|
|
27
29
|
|
|
28
30
|
<slot name="head"
|
|
29
31
|
:preset="preset"
|
|
30
32
|
:presetSelector="$refs.presetSelector"
|
|
31
33
|
:compPrefix="compPrefix">
|
|
32
|
-
<div class="flex flex-col md:flex-row gap-3 md:items-start overflow-hidden leading-tight p-3 md:p-0 md:pl-3"
|
|
34
|
+
<div class="flex flex-col md:flex-row gap-3 md:items-start overflow-hidden leading-tight p-3 md:p-0 md:pl-3 panel-400 md:panel-none border-b-[1px] border-text-50 md:border-none"
|
|
33
35
|
:class="headerClass">
|
|
34
36
|
|
|
35
|
-
<div class="flex md:flex-1 flex-row gap-3">
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
<div class="flex md:flex-1 flex-row items-start gap-3">
|
|
38
|
+
|
|
39
|
+
<div class="flex flex-row gap-2 md:gap-3 items-center" ref="title">
|
|
40
|
+
<div class="flex flex-col whitespace-nowrap text-ellipsis overflow-hidden">
|
|
41
|
+
<div class="cursor-pointer group" @click="$refs.contextMenu.open($refs.title)">
|
|
42
|
+
<small class="text-text-400 text-xs">{{ title ?? 'Untitled' }}</small>
|
|
43
|
+
<div class="flex flex-row items-baseline gap-1">
|
|
44
|
+
<h5 class="whitespace-nowrap relative top-[-2px] text-ellipsis overflow-hidden group-hover:text-primary">
|
|
45
|
+
{{ preset.name ?? 'Preset Name' }}
|
|
46
|
+
</h5>
|
|
47
|
+
<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>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
<ContextMenu ref="contextMenu" class="panel-400">
|
|
51
|
+
<div class="flex flex-col min-w-[300px] divide-y divide-text-50">
|
|
52
|
+
|
|
53
|
+
<div class="p-3 flex flex-col gap-1 bg-base-300">
|
|
54
|
+
<button v-for="(preset, idx) in config.presets"
|
|
55
|
+
class="p-2 px-5 text-left flex flex-row items-center rounded-md"
|
|
56
|
+
:class="config.presetIdx === idx ? 'bg-primary-200 text-white' : 'hover:bg-primary-100'"
|
|
57
|
+
type="button"
|
|
58
|
+
@click="selectPreset(idx)">
|
|
59
|
+
<label class="flex-1 pr-12">
|
|
60
|
+
{{ preset.name }}
|
|
61
|
+
</label>
|
|
62
|
+
<div class="p-1">
|
|
63
|
+
<div v-if="idx < 10"
|
|
64
|
+
class="border-[1px] border-text-300 px-2 text-mono text-xs text-text-400 rounded-lg">
|
|
65
|
+
Alt {{ idx + 1 }}
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div class="px-3">
|
|
72
|
+
<button type="button" class="text-primary p-3 px-5 text-left w-full" @click="openPreset">Edit</button>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
</div>
|
|
76
|
+
</ContextMenu>
|
|
77
|
+
</div>
|
|
44
78
|
</div>
|
|
45
79
|
|
|
46
80
|
<div class="flex-1"></div>
|
|
47
81
|
|
|
48
|
-
<slot
|
|
82
|
+
<slot name="toolbar"></slot>
|
|
49
83
|
</div>
|
|
50
84
|
|
|
51
85
|
<div class="flex flex-row gap-2 gap-1" v-if="Boolean(toolbar)">
|
|
@@ -107,13 +141,13 @@
|
|
|
107
141
|
ref="grid"
|
|
108
142
|
:items="dataItems"
|
|
109
143
|
:column="computedGridColumn"
|
|
110
|
-
class="
|
|
144
|
+
:class="gridClass"
|
|
111
145
|
@scroll-end="loadNext"
|
|
112
146
|
:container-class="`${gridContainerClass}`"
|
|
113
147
|
:config="config">
|
|
114
148
|
<template #item="{ item }">
|
|
115
149
|
<slot name="gridItem" :item="item">
|
|
116
|
-
<div class="flex flex-row panel-400 rounded-lg overflow-hidden md:rounded-lg overflow-hidden">
|
|
150
|
+
<div class="flex flex-row panel-400 rounded-lg overflow-hidden md:rounded-lg overflow-hidden p-3 gap-3">
|
|
117
151
|
<div>
|
|
118
152
|
<Image :src="item.imageUrl" class="bg-text-50 w-[64px] h-[64px] rounded-lg" />
|
|
119
153
|
</div>
|
|
@@ -130,6 +164,7 @@
|
|
|
130
164
|
</div>
|
|
131
165
|
|
|
132
166
|
</div>
|
|
167
|
+
|
|
133
168
|
</div>
|
|
134
169
|
</template>
|
|
135
170
|
|
|
@@ -161,17 +196,26 @@ export default{
|
|
|
161
196
|
}
|
|
162
197
|
},
|
|
163
198
|
gridColumn: [ Number, String ],
|
|
164
|
-
|
|
199
|
+
gridClass: {
|
|
200
|
+
type: String,
|
|
201
|
+
default: "flex-1 md:p-3"
|
|
202
|
+
},
|
|
203
|
+
gridContainerClass: {
|
|
204
|
+
type: String,
|
|
205
|
+
default: "md:gap-5"
|
|
206
|
+
},
|
|
165
207
|
headerClass: String,
|
|
166
|
-
presetMode:
|
|
167
|
-
|
|
208
|
+
presetMode: {
|
|
209
|
+
type: String,
|
|
210
|
+
default: "sidebar"
|
|
211
|
+
},
|
|
212
|
+
containerClass: {
|
|
213
|
+
type: String,
|
|
214
|
+
default: "md:p-5 md:gap-3"
|
|
215
|
+
},
|
|
168
216
|
toolbar: {
|
|
169
217
|
type: [ String, Boolean ],
|
|
170
218
|
default: true
|
|
171
|
-
},
|
|
172
|
-
editHash: {
|
|
173
|
-
type: String,
|
|
174
|
-
default: '#719ed'
|
|
175
219
|
}
|
|
176
220
|
},
|
|
177
221
|
|
|
@@ -211,7 +255,8 @@ export default{
|
|
|
211
255
|
const columns = []
|
|
212
256
|
for(let key in data.items[0]){
|
|
213
257
|
if(key.startsWith('_')){
|
|
214
|
-
|
|
258
|
+
let [ k1, ...k2 ] = key.substring(1).split('-')
|
|
259
|
+
k2 = k2.join('-')
|
|
215
260
|
|
|
216
261
|
let label = k2.replace(/_/gi, ' ')
|
|
217
262
|
const column = tableColumns[k1]
|
|
@@ -301,11 +346,8 @@ export default{
|
|
|
301
346
|
},
|
|
302
347
|
|
|
303
348
|
resize1(w){
|
|
304
|
-
if(
|
|
305
|
-
this.config.
|
|
306
|
-
|
|
307
|
-
if(this.config.sidebarWidth + w >= 270 && this.config.sidebarWidth + w <= 600){
|
|
308
|
-
this.config.sidebarWidth += w
|
|
349
|
+
if(this.config.sidebar.width + w >= 270 && this.config.sidebar.width + w <= 600){
|
|
350
|
+
this.config.sidebar.width += w
|
|
309
351
|
}
|
|
310
352
|
},
|
|
311
353
|
|
|
@@ -314,15 +356,7 @@ export default{
|
|
|
314
356
|
this.config.presetIdx = idx
|
|
315
357
|
this.load()
|
|
316
358
|
this.$refs.presetSelector.close()
|
|
317
|
-
|
|
318
|
-
},
|
|
319
|
-
|
|
320
|
-
setDefaultPresetView(){
|
|
321
|
-
if(window.innerWidth < 768){
|
|
322
|
-
this.preset.view = 'grid'
|
|
323
|
-
}
|
|
324
|
-
else if(!this.preset.view){
|
|
325
|
-
this.preset.view = window.innerWidth < 768 ? 'grid' : 'table'
|
|
359
|
+
this.$refs.contextMenu.close()
|
|
326
360
|
}
|
|
327
361
|
},
|
|
328
362
|
|
|
@@ -342,10 +376,7 @@ export default{
|
|
|
342
376
|
break
|
|
343
377
|
|
|
344
378
|
case 'sidebar':
|
|
345
|
-
this
|
|
346
|
-
...this.$route,
|
|
347
|
-
hash: this.$route.hash.replace(this.editHash, '') + this.editHash
|
|
348
|
-
})
|
|
379
|
+
this.sidebar.open = true
|
|
349
380
|
break
|
|
350
381
|
|
|
351
382
|
default:
|
|
@@ -355,11 +386,17 @@ export default{
|
|
|
355
386
|
}
|
|
356
387
|
},
|
|
357
388
|
|
|
358
|
-
|
|
359
|
-
this
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
389
|
+
togglePreset(){
|
|
390
|
+
switch(this.computedPresetMode){
|
|
391
|
+
|
|
392
|
+
case 'sidebar':
|
|
393
|
+
this.sidebar.open = !this.sidebar.open
|
|
394
|
+
break
|
|
395
|
+
|
|
396
|
+
case 'popup':
|
|
397
|
+
this.$refs.presetSelector.open()
|
|
398
|
+
break
|
|
399
|
+
}
|
|
363
400
|
},
|
|
364
401
|
|
|
365
402
|
onSignal(event, items){
|
|
@@ -391,6 +428,29 @@ export default{
|
|
|
391
428
|
resize(){
|
|
392
429
|
this.$refs.table ? this.$refs.table.resize() : null
|
|
393
430
|
this.$refs.grid ? this.$refs.grid.resize() : null
|
|
431
|
+
},
|
|
432
|
+
|
|
433
|
+
onKeyDown(e){
|
|
434
|
+
|
|
435
|
+
if(e.altKey){
|
|
436
|
+
|
|
437
|
+
switch(e.code){
|
|
438
|
+
|
|
439
|
+
case 'Backquote':
|
|
440
|
+
this.$refs.contextMenu.open(this.$refs.title)
|
|
441
|
+
break
|
|
442
|
+
|
|
443
|
+
default:
|
|
444
|
+
if(e.code.startsWith('Digit')){
|
|
445
|
+
const idx = parseInt(e.code.substring(5)) - 1
|
|
446
|
+
if(this.config.presets[idx]) {
|
|
447
|
+
this.selectPreset(idx)
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
}
|
|
394
454
|
}
|
|
395
455
|
|
|
396
456
|
},
|
|
@@ -406,7 +466,6 @@ export default{
|
|
|
406
466
|
|
|
407
467
|
this.loadPreset()
|
|
408
468
|
.then(() => {
|
|
409
|
-
this.setDefaultPresetView()
|
|
410
469
|
this.readyState = 1
|
|
411
470
|
this.load()
|
|
412
471
|
})
|
|
@@ -415,13 +474,13 @@ export default{
|
|
|
415
474
|
this.socket.send('user.subscribe', { name:this.subscribeKey })
|
|
416
475
|
this.socket.on(this.subscribeKey, this.onSignal)
|
|
417
476
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
477
|
+
|
|
478
|
+
window.addEventListener('keydown', this.onKeyDown)
|
|
421
479
|
},
|
|
422
480
|
|
|
423
481
|
unmounted() {
|
|
424
482
|
this.$removeResizeListener(this.$el)
|
|
483
|
+
window.removeEventListener('keydown', this.onKeyDown)
|
|
425
484
|
|
|
426
485
|
if(this.subscribeKey) {
|
|
427
486
|
this.socket.send('user.unsubscribe', {name: this.subscribeKey})
|
|
@@ -439,6 +498,23 @@ export default{
|
|
|
439
498
|
const columns = []
|
|
440
499
|
|
|
441
500
|
for(let row of this.preset.pivot.rows){
|
|
501
|
+
if(!tableColumns[row.key][0].defaultFormat)
|
|
502
|
+
tableColumns[row.key][0].defaultFormat = tableColumns[row.key][0].format
|
|
503
|
+
|
|
504
|
+
switch(row.aggregrate){
|
|
505
|
+
case 'year':
|
|
506
|
+
tableColumns[row.key][0].format = 'YYYY'
|
|
507
|
+
break
|
|
508
|
+
|
|
509
|
+
case 'month':
|
|
510
|
+
tableColumns[row.key][0].format = 'MMM YYYY'
|
|
511
|
+
break
|
|
512
|
+
|
|
513
|
+
case 'date':
|
|
514
|
+
tableColumns[row.key][0].format = 'D MMM YYYY'
|
|
515
|
+
break
|
|
516
|
+
}
|
|
517
|
+
|
|
442
518
|
columns.push(tableColumns[row.key][0])
|
|
443
519
|
}
|
|
444
520
|
|
|
@@ -453,7 +529,15 @@ export default{
|
|
|
453
529
|
|
|
454
530
|
return columns
|
|
455
531
|
}
|
|
456
|
-
|
|
532
|
+
|
|
533
|
+
for(let idx in this.preset.columns){
|
|
534
|
+
if(this.preset.columns[idx].defaultFormat){
|
|
535
|
+
this.preset.columns[idx].format = this.preset.columns[idx].defaultFormat
|
|
536
|
+
delete this.preset.columns[idx].defaultFormat
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return this.preset.columns
|
|
457
541
|
},
|
|
458
542
|
|
|
459
543
|
contentSlots(){
|
|
@@ -503,13 +587,19 @@ export default{
|
|
|
503
587
|
(this.view ?? this.preset.view)
|
|
504
588
|
},
|
|
505
589
|
|
|
506
|
-
|
|
507
|
-
|
|
590
|
+
sidebar(){
|
|
591
|
+
if(!this.config.sidebar || !('open' in this.config.sidebar))
|
|
592
|
+
this.config.sidebar = {
|
|
593
|
+
open: false,
|
|
594
|
+
width: 270
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return this.config.sidebar
|
|
508
598
|
},
|
|
509
599
|
|
|
510
|
-
|
|
600
|
+
sidebarStyle(){
|
|
511
601
|
return {
|
|
512
|
-
width:
|
|
602
|
+
width: !this.sidebar.open ? 0 : this.sidebar.width + 'px'
|
|
513
603
|
}
|
|
514
604
|
},
|
|
515
605
|
|
|
@@ -535,12 +625,6 @@ export default{
|
|
|
535
625
|
}
|
|
536
626
|
},
|
|
537
627
|
|
|
538
|
-
preset(to){
|
|
539
|
-
if(!to.view){
|
|
540
|
-
this.setDefaultPresetView()
|
|
541
|
-
}
|
|
542
|
-
},
|
|
543
|
-
|
|
544
628
|
},
|
|
545
629
|
|
|
546
630
|
}
|
|
@@ -553,8 +637,4 @@ export default{
|
|
|
553
637
|
@apply w-[3px] cursor-ew-resize absolute top-0 right-0 bottom-0;
|
|
554
638
|
}
|
|
555
639
|
|
|
556
|
-
.headerSelected{
|
|
557
|
-
@apply border-primary;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
640
|
</style>
|
package/src/components/Modal.vue
CHANGED
|
@@ -57,6 +57,19 @@
|
|
|
57
57
|
<Radio :name="value.key" :value="false" v-model="value.value" @change="apply">False</Radio>
|
|
58
58
|
</div>
|
|
59
59
|
|
|
60
|
+
<div v-else-if="type === 'enum'" class="flex flex-row gap-2">
|
|
61
|
+
|
|
62
|
+
<div class="flex flex-col gap-2">
|
|
63
|
+
<Checkbox v-for="param in typeParams"
|
|
64
|
+
v-model="cValue.value"
|
|
65
|
+
:value="param.value"
|
|
66
|
+
@change="apply">
|
|
67
|
+
{{ param.text }}
|
|
68
|
+
</Checkbox>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
</div>
|
|
72
|
+
|
|
60
73
|
<div v-else-if="type === 'component'">
|
|
61
74
|
<component :is="column.component"
|
|
62
75
|
:value="value"
|
|
@@ -99,7 +112,11 @@ export default{
|
|
|
99
112
|
type: Object,
|
|
100
113
|
default: {}
|
|
101
114
|
},
|
|
115
|
+
|
|
102
116
|
type: String,
|
|
117
|
+
|
|
118
|
+
typeParams: Array,
|
|
119
|
+
|
|
103
120
|
value: Object,
|
|
104
121
|
|
|
105
122
|
},
|
|
@@ -109,6 +126,17 @@ export default{
|
|
|
109
126
|
valueRequired(){
|
|
110
127
|
return (!(['yesterday', 'today', 'thisWeek', 'thisMonth', 'thisYear'].includes(this.value.operator) ||
|
|
111
128
|
this.type === 'boolean'));
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
cValue(){
|
|
132
|
+
if(this.type === 'enum' && (!this.value.operator || !Array.isArray(this.value.value))){
|
|
133
|
+
Object.assign(this.value, {
|
|
134
|
+
operator: 'in',
|
|
135
|
+
value: []
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return this.value
|
|
112
140
|
}
|
|
113
141
|
|
|
114
142
|
},
|
package/src/components/Tabs.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="computedClass">
|
|
3
3
|
<button v-for="(item, index) in filteredItems" :class="tabClass(item)"
|
|
4
|
-
class="
|
|
4
|
+
class="whitespace-nowrap"
|
|
5
5
|
@click="onClick(item)" type="button" >
|
|
6
6
|
<slot name="default" :="{ item, index }">
|
|
7
7
|
<label class="px-1">
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
<td v-for="column in visibleColumns"
|
|
38
38
|
:class="tdClass(item, column)">
|
|
39
39
|
<slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
|
|
40
|
-
<
|
|
40
|
+
<slot v-else-if="$slots.default" name="default" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
|
|
41
|
+
<div v-else :class="columnClass(column)" v-html="formatColumn(item, column)"></div>
|
|
41
42
|
</td>
|
|
42
43
|
<td :class="$style.spacer"></td>
|
|
43
44
|
</tr>
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
<tr>
|
|
64
65
|
<td v-for="column in columns" :style="thStyle(column)">
|
|
65
66
|
<slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="items[0]"></slot>
|
|
67
|
+
<slot v-else-if="$slots.default" name="default" :column="column" :item="items[0]"></slot>
|
|
66
68
|
<div v-else :class="columnClass(column)" v-html="formatColumn(items[0] ?? {}, column)"></div>
|
|
67
69
|
</td>
|
|
68
70
|
<td :class="$style.spacer"></td>
|
|
@@ -89,6 +91,8 @@ export default{
|
|
|
89
91
|
props:{
|
|
90
92
|
columns: Array,
|
|
91
93
|
|
|
94
|
+
itemClass: String,
|
|
95
|
+
|
|
92
96
|
items: Array,
|
|
93
97
|
|
|
94
98
|
pinned: Function,
|
|
@@ -218,9 +222,9 @@ export default{
|
|
|
218
222
|
},
|
|
219
223
|
|
|
220
224
|
tdClass(item, column){
|
|
221
|
-
if(Array.isArray(item._highlight) && item._highlight.includes(column.key))
|
|
222
|
-
return this.$style.highlight
|
|
223
|
-
|
|
225
|
+
if(Array.isArray(item._highlight) && item._highlight.includes(column.key))
|
|
226
|
+
return this.$style.highlight + (this.itemClass ? ' ' + this.itemClass : '')
|
|
227
|
+
return this.itemClass ?? ''
|
|
224
228
|
},
|
|
225
229
|
|
|
226
230
|
select(item, index){
|
|
@@ -60,6 +60,7 @@ const plugin = Plugin(function({ addBase, addUtilities, config, theme }) {
|
|
|
60
60
|
'--facebook-100': '205, 215, 231',
|
|
61
61
|
'--facebook-500': '8, 102, 255',
|
|
62
62
|
|
|
63
|
+
'--panel-none': 'transparent',
|
|
63
64
|
'--panel-300': 'rgb(235, 237, 240)',
|
|
64
65
|
'--panel-400': 'rgb(245, 247, 250)',
|
|
65
66
|
'--panel-500': 'rgb(255, 255, 255)',
|
|
@@ -234,6 +235,27 @@ const plugin = Plugin(function({ addBase, addUtilities, config, theme }) {
|
|
|
234
235
|
transform: 'scale(.9)'
|
|
235
236
|
},
|
|
236
237
|
|
|
238
|
+
'.openltr-move, .openltr-enter-active, .openltr-leave-active': {
|
|
239
|
+
transition: 'all 200ms cubic-bezier(0.25, 1, 0.5, 1)'
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
'.openltr-enter-from, .openltr-leave-to': {
|
|
243
|
+
opacity: 0,
|
|
244
|
+
transform: 'translateX(30px)'
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
'.openltr-leave-active': {
|
|
248
|
+
position: 'absolute',
|
|
249
|
+
right: 0,
|
|
250
|
+
width: '100%'
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
'.panel-none': {
|
|
254
|
+
'--webkit-backdrop-filter': 'var(--panel-none-backdrop-filter)',
|
|
255
|
+
'backdrop-filter': 'var(--panel-none-backdrop-filter)',
|
|
256
|
+
'background-color': 'var(--panel-none)',
|
|
257
|
+
},
|
|
258
|
+
|
|
237
259
|
'.panel-300': {
|
|
238
260
|
'--webkit-backdrop-filter': 'var(--panel-300-backdrop-filter)',
|
|
239
261
|
'backdrop-filter': 'var(--panel-300-backdrop-filter)',
|
|
@@ -452,7 +452,7 @@ const afterItemToSequelizeWhere = async (order, afterItem) => {
|
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
const searchToSequelizeWhere = async (search, params) => {
|
|
455
|
-
if(!search){
|
|
455
|
+
if(!search && (!Array.isArray(params) || params.length < 1)){
|
|
456
456
|
return {
|
|
457
457
|
where: {},
|
|
458
458
|
replacements: []
|
|
@@ -657,7 +657,6 @@ const chartToSequelizeWhere = async (chart, opt) => {
|
|
|
657
657
|
const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
658
658
|
|
|
659
659
|
const { model, sorts = [] } = opt
|
|
660
|
-
//console.log(sorts)
|
|
661
660
|
|
|
662
661
|
const attributes = []
|
|
663
662
|
const group = []
|
|
@@ -665,7 +664,6 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
665
664
|
const sortExists = sorts.length > 0
|
|
666
665
|
|
|
667
666
|
const groupedSorts = groupBy(sorts, 'key')
|
|
668
|
-
//console.log(util.inspect(pivot, false, null, true /* enable colors */))
|
|
669
667
|
|
|
670
668
|
for(let row of pivot.rows){
|
|
671
669
|
|
|
@@ -674,15 +672,15 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
674
672
|
switch(row.aggregrate){
|
|
675
673
|
|
|
676
674
|
case 'date':
|
|
677
|
-
attributes.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%
|
|
678
|
-
group.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%
|
|
679
|
-
if(!sortExists) order.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%
|
|
675
|
+
attributes.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%m-%d'), row.key ])
|
|
676
|
+
group.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%m-%d'), row.key ])
|
|
677
|
+
if(!sortExists) order.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%m-%d'), 'asc' ])
|
|
680
678
|
break
|
|
681
679
|
|
|
682
680
|
case 'month':
|
|
683
|
-
attributes.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%
|
|
684
|
-
group.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%
|
|
685
|
-
if(!sortExists) order.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%
|
|
681
|
+
attributes.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%m'), row.key ])
|
|
682
|
+
group.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%m'), row.key ])
|
|
683
|
+
if(!sortExists) order.push([ fn('DATE_FORMAT', literal(`${model.name}.${field}`), '%Y-%m'), 'asc' ])
|
|
686
684
|
break
|
|
687
685
|
|
|
688
686
|
case 'year':
|
|
@@ -701,6 +699,7 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
701
699
|
|
|
702
700
|
const sortKeyToOrders = {} // Helper to determine group ordering
|
|
703
701
|
for(let value of pivot.values){
|
|
702
|
+
|
|
704
703
|
switch(value.aggregrate){
|
|
705
704
|
|
|
706
705
|
case 'sum':
|
|
@@ -742,21 +741,19 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
742
741
|
}
|
|
743
742
|
|
|
744
743
|
const field = model.rawAttributes[value.key].field
|
|
745
|
-
//console.log(field)
|
|
746
744
|
|
|
747
745
|
groups.forEach(group => {
|
|
748
746
|
if(group[value.key] === null){
|
|
749
|
-
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} is null THEN 1 ELSE 0 END)`), `_${value.key}-null` ])
|
|
747
|
+
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} is null THEN 1 ELSE 0 END)`), `_${value.key}-(null)` ])
|
|
750
748
|
}
|
|
751
749
|
else if(group[value.key] === ''){
|
|
752
|
-
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} = '' THEN 1 ELSE 0 END)`), `_${value.key}-empty` ])
|
|
750
|
+
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} = '' THEN 1 ELSE 0 END)`), `_${value.key}-(empty)` ])
|
|
753
751
|
}
|
|
754
752
|
else{
|
|
755
753
|
const groupValue = (group[value.key] ?? '').toString().replace(/\s/g, '_')
|
|
756
754
|
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} = '${group[value.key]}' THEN 1 ELSE 0 END)`), `_${value.key}-${groupValue}` ])
|
|
757
755
|
}
|
|
758
756
|
})
|
|
759
|
-
//console.log(attributes)
|
|
760
757
|
|
|
761
758
|
break
|
|
762
759
|
}
|
|
@@ -773,9 +770,6 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
773
770
|
}
|
|
774
771
|
}
|
|
775
772
|
|
|
776
|
-
//console.log(util.inspect(attributes, false, null, true /* enable colors */))
|
|
777
|
-
//console.log(util.inspect(group, false, null, true /* enable colors */))
|
|
778
|
-
|
|
779
773
|
return {
|
|
780
774
|
attributes,
|
|
781
775
|
group,
|
|
@@ -887,6 +881,120 @@ const filtersToSequelizeInclude = async(filters, opt, includes) => {
|
|
|
887
881
|
return includes
|
|
888
882
|
}
|
|
889
883
|
|
|
884
|
+
const syntaxSearchToSequelizeOpt = async(search, opt) => {
|
|
885
|
+
|
|
886
|
+
let where = {}
|
|
887
|
+
let replacements = []
|
|
888
|
+
|
|
889
|
+
const { config } = opt
|
|
890
|
+
|
|
891
|
+
let syntaxKey = search[1]
|
|
892
|
+
let syntaxVal = search[2].trim()
|
|
893
|
+
|
|
894
|
+
return {
|
|
895
|
+
where,
|
|
896
|
+
replacements
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
const presetToSequelizeList = async(preset, {
|
|
901
|
+
conn, model, order:initialOrder, config, where:initialWhere
|
|
902
|
+
}) => {
|
|
903
|
+
|
|
904
|
+
if(!initialOrder){
|
|
905
|
+
initialOrder = [
|
|
906
|
+
[ 'updatedAt', 'desc' ],
|
|
907
|
+
[ 'id', 'desc' ],
|
|
908
|
+
]
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const { itemsPerPage = 20, filters = [], sorts, pivot, afterItem, search, id } = preset;
|
|
912
|
+
|
|
913
|
+
let where = {}
|
|
914
|
+
const replacements = []
|
|
915
|
+
const { order } = await sortsToSequelizeWhere(sorts, {
|
|
916
|
+
order: initialOrder
|
|
917
|
+
})
|
|
918
|
+
|
|
919
|
+
if(Array.isArray(id)){
|
|
920
|
+
where = {
|
|
921
|
+
...where,
|
|
922
|
+
id: {
|
|
923
|
+
[Op.in]: id
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
const { where:filterWhere, replacements:filterReplacements } = await filtersToSequelizeWhere(filters, config)
|
|
929
|
+
|
|
930
|
+
let searchWhere = {}, searchReplacements = []
|
|
931
|
+
if(search){
|
|
932
|
+
const syntaxSearch = (search ?? '').match(/^(\w+)\:(.*)/)
|
|
933
|
+
if(syntaxSearch !== null){
|
|
934
|
+
const syntaxSearchOpt = syntaxSearchToSequelizeOpt(syntaxSearch, { config })
|
|
935
|
+
searchWhere = syntaxSearchOpt.where
|
|
936
|
+
searchReplacements = syntaxSearchOpt.replacements
|
|
937
|
+
}
|
|
938
|
+
else{
|
|
939
|
+
const match = (config.columns ?? []).filter(_ => (_.search && _.key)).map(_ => _.key)
|
|
940
|
+
if(match !== null){
|
|
941
|
+
const searchOpt = await searchToSequelizeWhere(search, {
|
|
942
|
+
match
|
|
943
|
+
})
|
|
944
|
+
searchWhere = searchOpt.where
|
|
945
|
+
searchReplacements = searchOpt.replacements
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
if(pivot && pivot.enabled){
|
|
951
|
+
const { attributes, group, order } = await pivotToSequelizeWhere(pivot, {
|
|
952
|
+
model,
|
|
953
|
+
conn
|
|
954
|
+
})
|
|
955
|
+
|
|
956
|
+
return {
|
|
957
|
+
attributes,
|
|
958
|
+
where: {
|
|
959
|
+
[Op.and]: [
|
|
960
|
+
initialWhere ?? {},
|
|
961
|
+
where,
|
|
962
|
+
filterWhere,
|
|
963
|
+
searchWhere
|
|
964
|
+
]
|
|
965
|
+
},
|
|
966
|
+
replacements: [
|
|
967
|
+
...filterReplacements,
|
|
968
|
+
...searchReplacements
|
|
969
|
+
],
|
|
970
|
+
group,
|
|
971
|
+
order
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
else{
|
|
975
|
+
const { where:afterItemWhere } = await afterItemToSequelizeWhere(order, afterItem)
|
|
976
|
+
|
|
977
|
+
return {
|
|
978
|
+
where: {
|
|
979
|
+
[Op.and]: [
|
|
980
|
+
where,
|
|
981
|
+
afterItemWhere,
|
|
982
|
+
filterWhere,
|
|
983
|
+
searchWhere,
|
|
984
|
+
]
|
|
985
|
+
},
|
|
986
|
+
limit: itemsPerPage,
|
|
987
|
+
order,
|
|
988
|
+
replacements: [
|
|
989
|
+
...replacements,
|
|
990
|
+
...filterReplacements,
|
|
991
|
+
...searchReplacements
|
|
992
|
+
]
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
|
|
890
998
|
module.exports = {
|
|
891
999
|
filtersToSequelizeWhere,
|
|
892
1000
|
afterItemToSequelizeWhere,
|
|
@@ -895,4 +1003,6 @@ module.exports = {
|
|
|
895
1003
|
pivotToSequelizeWhere,
|
|
896
1004
|
sortsToSequelizeWhere,
|
|
897
1005
|
filtersToSequelizeInclude,
|
|
1006
|
+
|
|
1007
|
+
presetToSequelizeList
|
|
898
1008
|
}
|
|
@@ -42,6 +42,13 @@ const setupConfig = (config) => {
|
|
|
42
42
|
if(config.presets[idx].columns[0] && typeof config.presets[idx].columns[0] === 'string'){
|
|
43
43
|
config.presets[idx].columns = pickColumns(config.columns ?? [], config.presets[idx].columns)
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
if(!config.presets[idx].view)
|
|
47
|
+
config.presets[idx].view = 'table'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if(!config.presetIdx && config.presets.length > 0){
|
|
51
|
+
config.presetIdx = 0
|
|
45
52
|
}
|
|
46
53
|
}
|
|
47
54
|
|
package/src/utils/wss.mjs
CHANGED
|
@@ -58,7 +58,10 @@ class WSS extends EventEmitter2{
|
|
|
58
58
|
url: '',
|
|
59
59
|
}, opt ?? {})
|
|
60
60
|
|
|
61
|
-
this.connect()
|
|
61
|
+
this.connect()
|
|
62
|
+
.catch(e => {
|
|
63
|
+
this.emit('error', e, [])
|
|
64
|
+
})
|
|
62
65
|
|
|
63
66
|
if(typeof window !== 'undefined'){
|
|
64
67
|
window.addEventListener('visibilitychange', () => {
|
|
@@ -119,7 +122,7 @@ class WSS extends EventEmitter2{
|
|
|
119
122
|
this._pendingSend = []
|
|
120
123
|
}
|
|
121
124
|
else if(_requestId){
|
|
122
|
-
if(this._callbacks[_requestId]){
|
|
125
|
+
if(this._callbacks[_requestId] && this._instance.readyState === 1){
|
|
123
126
|
const { cb, err, path, params, t1 } = this._callbacks[_requestId]
|
|
124
127
|
status === 200 ? cb(data) : err(data)
|
|
125
128
|
delete this._callbacks[_requestId]
|
|
@@ -167,6 +170,10 @@ class WSS extends EventEmitter2{
|
|
|
167
170
|
};
|
|
168
171
|
}
|
|
169
172
|
|
|
173
|
+
async close(){
|
|
174
|
+
this._instance.close()
|
|
175
|
+
}
|
|
176
|
+
|
|
170
177
|
async reconnect(opt){
|
|
171
178
|
if(this._instance){
|
|
172
179
|
this._instance.close()
|
|
@@ -178,7 +185,7 @@ class WSS extends EventEmitter2{
|
|
|
178
185
|
}
|
|
179
186
|
|
|
180
187
|
sendSync(path, params, cb, err, override){
|
|
181
|
-
if(this._instance.readyState > 1){
|
|
188
|
+
if(!this._instance || this._instance.readyState > 1){
|
|
182
189
|
return
|
|
183
190
|
}
|
|
184
191
|
else if(!this._instance.isAuth){
|
|
@@ -212,7 +219,7 @@ class WSS extends EventEmitter2{
|
|
|
212
219
|
}
|
|
213
220
|
|
|
214
221
|
setTimeout(() => {
|
|
215
|
-
if(this._callbacks[_requestId]){
|
|
222
|
+
if(this._callbacks[_requestId] && this._instance.readyState === 1){
|
|
216
223
|
err({ message: 'Timeout' })
|
|
217
224
|
delete this._callbacks[_requestId]
|
|
218
225
|
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
<TransitionGroup name="openltr" tag="div" class="flex-1 flex">
|
|
5
5
|
|
|
6
|
-
<div v-if="
|
|
6
|
+
<div v-if="presetBar.view === 1" key="panel1" class="flex-1 flex flex-col">
|
|
7
7
|
|
|
8
|
-
<div class="flex flex-row items-center gap-2 p-
|
|
8
|
+
<div class="flex flex-row items-center gap-2 p-3">
|
|
9
9
|
<slot name="start"></slot>
|
|
10
10
|
<div class="flex-1">
|
|
11
11
|
<h5 class="px-3">{{ config.name ?? 'Config' }}</h5>
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
class="px-3 p-2 text-left hover:bg-primary-100 flex flex-row gap-2 items-center">
|
|
23
23
|
<Radio v-model="config.presetIdx" :value="idx" @change="apply()" />
|
|
24
24
|
<button type="button" class="flex-1 py-1 text-left overflow-hidden text-ellipsis whitespace-nowrap"
|
|
25
|
-
@click="
|
|
25
|
+
@click="select(idx)">
|
|
26
26
|
{{ _preset.name }}
|
|
27
27
|
</button>
|
|
28
28
|
<button v-if="config.presetIdx === idx"
|
|
@@ -73,14 +73,18 @@
|
|
|
73
73
|
<div v-else key="panel2" class="flex-1 flex flex-col">
|
|
74
74
|
|
|
75
75
|
<div class="flex flex-row gap-2 p-3">
|
|
76
|
-
<button type="button" @click="deselect">
|
|
77
|
-
<svg width="
|
|
76
|
+
<button type="button" @click="deselect" class="p-1">
|
|
77
|
+
<svg width="16" height="16" class="fill-text-300 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="M80 208h-64C7.125 208 0 215.1 0 224v64c0 8.875 7.125 16 16 16h64C88.88 304 96 296.9 96 288V224C96 215.1 88.88 208 80 208zM80 368h-64C7.125 368 0 375.1 0 384v64c0 8.875 7.125 16 16 16h64C88.88 464 96 456.9 96 448v-64C96 375.1 88.88 368 80 368zM80 48h-64C7.125 48 0 55.13 0 64v64c0 8.875 7.125 16 16 16h64C88.88 144 96 136.9 96 128V64C96 55.13 88.88 48 80 48zM488 232H183.1C170.7 232 160 242.7 160 256s10.75 24 23.1 24H488C501.3 280 512 269.3 512 256S501.3 232 488 232zM488 72H183.1C170.7 72 160 82.75 160 95.1S170.7 120 183.1 120H488c13.25 0 24-10.75 24-23.1S501.3 72 488 72zM488 392H183.1C170.7 392 160 402.7 160 416s10.75 24 23.1 24H488c13.25 0 24-10.75 24-24S501.3 392 488 392z"/></svg>
|
|
78
78
|
</button>
|
|
79
|
-
<Textbox v-model="preset.name"
|
|
79
|
+
<Textbox v-model="preset.name"
|
|
80
|
+
class="flex-1 rounded-none border-none bg-transparent font-bold"
|
|
81
|
+
item-class="p-1"
|
|
82
|
+
variant="minimal"
|
|
83
|
+
maxlength="100" />
|
|
80
84
|
<slot name="toolbar" :edit="true"></slot>
|
|
81
85
|
</div>
|
|
82
86
|
|
|
83
|
-
<div class="flex items-center justify-center border-b-[1px] border-text-100">
|
|
87
|
+
<div class="flex items-center justify-center border-b-[1px] border-text-100 px-3">
|
|
84
88
|
<Tabs :items="tabItems[config.type ?? 'list']" v-model="config.presetBarTabIndex" />
|
|
85
89
|
</div>
|
|
86
90
|
|
|
@@ -88,7 +92,7 @@
|
|
|
88
92
|
|
|
89
93
|
<div v-if="config.presetBarTabIndex === 1" class="flex-1 flex flex-col p-5">
|
|
90
94
|
<ListItem :items="presetColumns"
|
|
91
|
-
body-class="divide-y divide-text-50"
|
|
95
|
+
body-class="divide-y divide-text-50 rounded-lg border-[1px] border-text-50 bg-base-300"
|
|
92
96
|
@reorder="(from, to) => { presetColumns.splice(to, 0, presetColumns.splice(from, 1)[0]); }">
|
|
93
97
|
<template v-slot="{ item }">
|
|
94
98
|
<div v-if="!item.key.startsWith('_') || (item.key.startsWith('_') && (preset.pivot && preset.pivot.enabled))" class="flex flex-row items-center gap-3 px-3 p-2 hover:bg-primary-100">
|
|
@@ -136,6 +140,7 @@
|
|
|
136
140
|
<PresetSelectorFilterItem
|
|
137
141
|
class="flex-1"
|
|
138
142
|
:type="typeOf(column(filter.key).type)"
|
|
143
|
+
:typeParams="typeParamsOf(column(filter.key))"
|
|
139
144
|
:value="filterVal"
|
|
140
145
|
@change="apply()" />
|
|
141
146
|
|
|
@@ -169,11 +174,12 @@
|
|
|
169
174
|
|
|
170
175
|
<div v-else-if="config.presetBarTabIndex === 3" class="flex-1 flex flex-col p-5">
|
|
171
176
|
|
|
172
|
-
<ListItem
|
|
177
|
+
<ListItem v-if="Array.isArray(preset.sorts) && preset.sorts.length > 0"
|
|
178
|
+
:items="preset.sorts"
|
|
173
179
|
@reorder="(from, to) => { preset.sorts.splice(to, 0, preset.sorts.splice(from, 1)[0]); apply() }"
|
|
174
|
-
container-class="flex flex-col
|
|
180
|
+
container-class="flex flex-col rounded-lg border-[1px] border-text-50 bg-base-300 divide-y divide-text-50">
|
|
175
181
|
<template v-slot="{ item, index }">
|
|
176
|
-
<div class="flex flex-row items-center gap-3">
|
|
182
|
+
<div class="flex flex-row items-center gap-3 p-1">
|
|
177
183
|
<div data-reorder>
|
|
178
184
|
<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>
|
|
179
185
|
</div>
|
|
@@ -208,13 +214,12 @@
|
|
|
208
214
|
</template>
|
|
209
215
|
</ListItem>
|
|
210
216
|
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
</div>
|
|
217
|
+
<button type="button"
|
|
218
|
+
class="text-primary flex flex-row items-center justify-center p-3"
|
|
219
|
+
@click="addSort({ type:'asc' })">
|
|
220
|
+
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
221
|
+
Add Sort
|
|
222
|
+
</button>
|
|
218
223
|
|
|
219
224
|
</div>
|
|
220
225
|
|
|
@@ -503,6 +508,7 @@
|
|
|
503
508
|
</strong>
|
|
504
509
|
<select v-model="item.aggregrate"
|
|
505
510
|
class="appearance-none bg-transparent outline-none" @change="apply()">
|
|
511
|
+
<option value="">Default</option>
|
|
506
512
|
<option value="count">Count</option>
|
|
507
513
|
<option v-if="[ 'number' ].includes(item.type)" value="sum">Sum</option>
|
|
508
514
|
<option v-if="[ 'number' ].includes(item.type)" value="avg">Average</option>
|
|
@@ -525,12 +531,18 @@
|
|
|
525
531
|
<div v-else-if="config.presetBarTabIndex === 9" class="flex-1 p-6 flex flex-col gap-6">
|
|
526
532
|
|
|
527
533
|
<div>
|
|
528
|
-
<
|
|
534
|
+
<div class="flex flex-row">
|
|
535
|
+
<strong class="flex-1">Preset</strong>
|
|
536
|
+
<button type="button" class="text-primary" @click="log(preset)">console.log</button>
|
|
537
|
+
</div>
|
|
529
538
|
<ObjectTree :value="preset" />
|
|
530
539
|
</div>
|
|
531
540
|
|
|
532
541
|
<div>
|
|
533
|
-
<
|
|
542
|
+
<div class="flex flex-row">
|
|
543
|
+
<strong class="flex-1">Config</strong>
|
|
544
|
+
<button type="button" class="text-primary" @click="log(config)">console.log</button>
|
|
545
|
+
</div>
|
|
534
546
|
<ObjectTree :value="config" />
|
|
535
547
|
</div>
|
|
536
548
|
|
|
@@ -542,6 +554,7 @@
|
|
|
542
554
|
:columns="config.columns" />
|
|
543
555
|
|
|
544
556
|
</div>
|
|
557
|
+
|
|
545
558
|
</TransitionGroup>
|
|
546
559
|
|
|
547
560
|
</div>
|
|
@@ -561,12 +574,7 @@ export default{
|
|
|
561
574
|
|
|
562
575
|
props: {
|
|
563
576
|
|
|
564
|
-
config: Object
|
|
565
|
-
|
|
566
|
-
editHash: {
|
|
567
|
-
type: String,
|
|
568
|
-
default: '#e1a5f'
|
|
569
|
-
}
|
|
577
|
+
config: Object
|
|
570
578
|
|
|
571
579
|
},
|
|
572
580
|
|
|
@@ -652,18 +660,13 @@ export default{
|
|
|
652
660
|
},
|
|
653
661
|
|
|
654
662
|
select(idx){
|
|
655
|
-
this.config.
|
|
656
|
-
this
|
|
657
|
-
|
|
658
|
-
hash: (this.$route.hash.replace(this.editHash, '')) + this.editHash
|
|
659
|
-
})
|
|
663
|
+
this.config.presetIdx = idx
|
|
664
|
+
this.presetBar.view = 2
|
|
665
|
+
this.apply()
|
|
660
666
|
},
|
|
661
667
|
|
|
662
668
|
deselect(){
|
|
663
|
-
this
|
|
664
|
-
...this.$route,
|
|
665
|
-
hash: this.$route.hash.replace(this.editHash, '')
|
|
666
|
-
})
|
|
669
|
+
this.config.presetBar.view = 1
|
|
667
670
|
},
|
|
668
671
|
|
|
669
672
|
filterColumnAdded(column){
|
|
@@ -677,10 +680,18 @@ export default{
|
|
|
677
680
|
return 'date'
|
|
678
681
|
else if([ 'number' ].includes(type))
|
|
679
682
|
return 'number'
|
|
683
|
+
else if([ 'enum' ].includes(type))
|
|
684
|
+
return 'enum'
|
|
680
685
|
else
|
|
681
686
|
return 'text'
|
|
682
687
|
},
|
|
683
688
|
|
|
689
|
+
typeParamsOf(column){
|
|
690
|
+
if([ 'enum' ].includes(column.type))
|
|
691
|
+
return column.typeParams
|
|
692
|
+
return []
|
|
693
|
+
},
|
|
694
|
+
|
|
684
695
|
},
|
|
685
696
|
|
|
686
697
|
computed: {
|
|
@@ -698,7 +709,7 @@ export default{
|
|
|
698
709
|
},
|
|
699
710
|
|
|
700
711
|
preset(){
|
|
701
|
-
return this.config.presets[this.config.
|
|
712
|
+
return this.config.presets[this.config.presetIdx]
|
|
702
713
|
},
|
|
703
714
|
|
|
704
715
|
presetChart(){
|
|
@@ -742,6 +753,15 @@ export default{
|
|
|
742
753
|
return this.chartOpt.yAxis
|
|
743
754
|
},
|
|
744
755
|
|
|
756
|
+
presetBar(){
|
|
757
|
+
if(!this.config.presetBar || !this.config.presetBar.view)
|
|
758
|
+
this.config.presetBar = {
|
|
759
|
+
view: 2
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
return this.config.presetBar
|
|
763
|
+
}
|
|
764
|
+
|
|
745
765
|
},
|
|
746
766
|
|
|
747
767
|
data(){
|