@mixd-id/web-scaffold 0.1.230406366 → 0.1.230406368

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.230406366",
4
+ "version": "0.1.230406368",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -41,7 +41,7 @@ export default{
41
41
 
42
42
  mixins: [ componentMixin ],
43
43
 
44
- emits: [ 'change' ],
44
+ emits: [ 'click', 'change' ],
45
45
 
46
46
  props:{
47
47
 
@@ -256,10 +256,12 @@ export default{
256
256
  }
257
257
  },
258
258
 
259
- onClick(){
259
+ onClick(e){
260
260
  if(!this.moved && this.target){
261
261
  this.$router.push(this.target)
262
262
  }
263
+
264
+ this.$emit('click', e, this)
263
265
  },
264
266
 
265
267
  onMouseDown(){
@@ -1,21 +1,23 @@
1
1
  <template>
2
- <div :class="$style.comp">
3
-
4
- <div class="flex flex-row items-start">
5
- <span contenteditable="true" spellcheck="false"
6
- ref="html"
7
- v-html="html"
8
- :class="`${$style.content}${itemClass ? ' ' + itemClass : ''}`"
9
- @blur="saveSelection($refs.html)"
10
- @paste="onPaste"
11
- @input="onInput"></span>
12
-
13
- <button v-if="variant === 'minimal'" type="button" class="p-3" @click="$refs.modal.open()">
14
- <svg width="14" height="14" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M328 256c0 39.8-32.2 72-72 72s-72-32.2-72-72 32.2-72 72-72 72 32.2 72 72zm104-72c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72zm-352 0c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72z"/></svg>
15
- </button>
2
+ <div :class="$style.comp">
3
+
4
+ <div class="flex flex-row items-start">
5
+ <span :contenteditable="!readonly" spellcheck="false"
6
+ ref="html"
7
+ v-html="html"
8
+ :class="`${$style.content}${itemClass ? ' ' + itemClass : ''}`"
9
+ @blur="onBlur"
10
+ @paste="onPaste"
11
+ @input="onInput"></span>
12
+
13
+ <slot name="end" :comp="this">
14
+ <button v-if="variant === 'minimal' && !readonly" type="button" class="p-3" @click="$refs.modal.open()">
15
+ <svg width="14" height="14" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M328 256c0 39.8-32.2 72-72 72s-72-32.2-72-72 32.2-72 72-72 72 32.2 72 72zm104-72c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72zm-352 0c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72z"/></svg>
16
+ </button>
17
+ </slot>
16
18
  </div>
17
19
 
18
- <div v-if="variant !== 'minimal'" class="flex flex-row bg-base-300" @dblclick.alt="log(JSON.stringify(modelValue))">
20
+ <div v-if="variant !== 'minimal' && !readonly" class="flex flex-row bg-base-300" @dblclick.alt="log(JSON.stringify(modelValue))">
19
21
  <div class="flex-1 flex flex-row gap-2 overflow-x-auto p-1" :class="$style.noScrollbar">
20
22
  <button type="button" v-for="item in viewedItems" :class="$style.tag2" class="text-xs" @click="add(item)">{{ item.text ?? item.value }}</button>
21
23
  </div>
@@ -57,7 +59,7 @@
57
59
 
58
60
  </div>
59
61
  </Modal>
60
- </div>
62
+ </div>
61
63
  </template>
62
64
 
63
65
  <script>
@@ -66,7 +68,7 @@ import {restoreSelection, saveSelection} from "../utils/selection";
66
68
 
67
69
  export default{
68
70
 
69
- emits: [ 'update:modelValue' ],
71
+ emits: [ 'blur', 'update:modelValue' ],
70
72
 
71
73
  props:{
72
74
 
@@ -78,6 +80,8 @@ export default{
78
80
 
79
81
  items: Array,
80
82
 
83
+ readonly: Boolean,
84
+
81
85
  variant: String,
82
86
 
83
87
  itemClass: String,
@@ -118,7 +122,7 @@ export default{
118
122
 
119
123
  let range = selection.getRangeAt(0);
120
124
  if(range.commonAncestorContainer.parentNode !== this.$refs.html &&
121
- range.commonAncestorContainer !== this.$refs.html) return
125
+ range.commonAncestorContainer !== this.$refs.html) return
122
126
 
123
127
  let currentNode = range.startContainer;
124
128
 
@@ -146,6 +150,10 @@ export default{
146
150
 
147
151
  this.insertElement(el)
148
152
  this.onInput()
153
+
154
+ const itemExists = this.items.find(_ => _.value === item.value)
155
+ if(!itemExists)
156
+ this.items.push(item)
149
157
  },
150
158
 
151
159
  add(item){
@@ -174,6 +182,11 @@ export default{
174
182
  e.target.parentNode.removeChild(e.target)
175
183
  },
176
184
 
185
+ onBlur(e){
186
+ this.saveSelection(this.$refs.html)
187
+ this.$emit('blur')
188
+ },
189
+
177
190
  onPaste(e){
178
191
  e.preventDefault()
179
192
  const text = e.clipboardData.getData('text/plain')
@@ -205,8 +218,8 @@ export default{
205
218
 
206
219
  modelValue: {
207
220
  immediate: true,
208
- handler(val){
209
- if(this.isInternal){
221
+ handler(val) {
222
+ if (this.isInternal) {
210
223
  this.isInternal = false
211
224
  return
212
225
  }
@@ -214,7 +227,7 @@ export default{
214
227
  let html = val ?? ''
215
228
 
216
229
  let customItems = []
217
- if(typeof this.itemFn === 'function'){
230
+ if (typeof this.itemFn === 'function') {
218
231
  customItems = this.itemFn(html)
219
232
  }
220
233
 
@@ -223,7 +236,7 @@ export default{
223
236
  ...customItems
224
237
  ]
225
238
 
226
- for(let item of items){
239
+ for (let item of items) {
227
240
  html = html.replaceAll(item.value, `<span title="${item.value.replaceAll('"', '')}" class="${this.$style.tag}" contenteditable="false" data-value="${item.value}">${item.text ?? item.value}</span>`, 'gi')
228
241
  }
229
242
 
@@ -239,28 +252,28 @@ export default{
239
252
 
240
253
  <style module>
241
254
 
242
- .comp{
255
+ .comp {
243
256
  @apply border-[1px] border-text-200 bg-base-50 rounded-lg min-w-[100px];
244
257
  @apply flex flex-col gap-2;
245
258
  @apply overflow-hidden;
246
259
  @apply divide-y divide-text-100;
247
260
  }
248
261
 
249
- .content{
262
+ .content {
250
263
  @apply flex-1 whitespace-pre-line outline-none p-2;
251
264
  }
252
265
 
253
- .comp .tag{
266
+ .comp .tag {
254
267
  @apply bg-text-100 p-1 rounded-lg whitespace-nowrap relative top-[-1px];
255
268
  @apply font-mono text-sm;
256
269
  }
257
270
 
258
- .tag2{
271
+ .tag2 {
259
272
  @apply bg-text-50 p-1 rounded-lg px-2 cursor-pointer whitespace-nowrap;
260
273
  @apply hover:bg-text-100 hover:text-white;
261
274
  }
262
275
 
263
- .noScrollbar::-webkit-scrollbar{
276
+ .noScrollbar::-webkit-scrollbar {
264
277
  display: none;
265
278
  }
266
279
 
@@ -0,0 +1,9 @@
1
+ export const component = {
2
+
3
+ type:"DataTable",
4
+
5
+ props:{
6
+ height:[ "h-[50vh]", "md:h-[50vh]", "", "" ]
7
+ }
8
+
9
+ }
package/src/index.js CHANGED
@@ -679,6 +679,7 @@ export default{
679
679
  app.component('PolarArea', defineAsyncComponent(() => import("./widgets/Dashboard/PolarArea.vue")))
680
680
  app.component('Metric', defineAsyncComponent(() => import("./widgets/Dashboard/Metric.vue")))
681
681
  app.component('BarChart', defineAsyncComponent(() => import("./widgets/Dashboard/BarChart.vue")))
682
+ app.component('DataTable', defineAsyncComponent(() => import("./widgets/Dashboard/DataTable.vue")))
682
683
 
683
684
  app.component('BotEditor', defineAsyncComponent(() => import("./widgets/BotEditor.vue")))
684
685
  }
@@ -85,6 +85,7 @@ const getDatasourceItems = async (datasource, opt) => {
85
85
  }
86
86
 
87
87
  const getSequelizeColumns = async (columns, opt) => {
88
+ if(!columns) columns = []
88
89
 
89
90
  const { DataTypes } = opt.Sequelize
90
91
 
@@ -525,11 +525,9 @@ const dayTimeRange = (params, value) => {
525
525
  }
526
526
 
527
527
  function capitalize(str) {
528
- return (str ?? '')
529
- .toString()
530
- .split(' ')
531
- .map(_ => _.charAt(0).toUpperCase() + _.slice(1).toLowerCase())
532
- .join(' ')
528
+ return (str ?? '').toLowerCase().replace(/\b\w/g, function(char) {
529
+ return char.toUpperCase();
530
+ });
533
531
  }
534
532
 
535
533
  module.exports = {
@@ -361,7 +361,7 @@ function applyDatasourceReplacer(value, datasource){
361
361
  }
362
362
 
363
363
  function capitalize(str) {
364
- return str.replace(/\b\w/g, function(char) {
364
+ return (str ?? '').toLowerCase().replace(/\b\w/g, function(char) {
365
365
  return char.toUpperCase();
366
366
  });
367
367
  }
@@ -24,13 +24,34 @@ const sortsFn = function(a, b, sorts, index){
24
24
  const pickColumns = function(columns, keys){
25
25
  if(!Array.isArray(columns)) return []
26
26
 
27
- const picked = JSON.parse(JSON.stringify(columns))
27
+ columns = JSON.parse(JSON.stringify(columns))
28
28
 
29
- for(let idx in picked){
30
- picked[idx].visible = keys.includes(picked[idx].key)
29
+ columns = columns.reduce((cur, obj) => {
30
+ cur[obj.key] = obj
31
+ return cur
32
+ }, {})
33
+
34
+ const res = []
35
+
36
+ for(let key of keys){
37
+ if(typeof key === 'string'){
38
+ if(columns[key]){
39
+ columns[key].visible = true
40
+ res.push(columns[key])
41
+ delete columns[key]
42
+ }
43
+ }
44
+ else if(typeof key === 'object' && key !== null && key.key){
45
+ if(columns[key.key]){
46
+ res.push(Object.assign(columns[key.key], key, { visible:true }))
47
+ delete columns[key.key]
48
+ }
49
+ }
31
50
  }
32
51
 
33
- return picked
52
+ res.push(...Object.values(columns))
53
+
54
+ return res
34
55
  }
35
56
 
36
57
  const setupConfig = (config) => {
package/src/utils/wss.js CHANGED
@@ -247,7 +247,6 @@ class WSS extends EventEmitter2{
247
247
  socket.close(1002, 'ping timeout')
248
248
  if(subscriber){
249
249
  subscriber.disconnect()
250
- console.log('CLOSE SOCKET', token.substring(0, 10) + '...')
251
250
  }
252
251
  else{
253
252
  console.log('CLOSE SOCKET#2', token.substring(0, 10) + '...')
@@ -74,7 +74,7 @@ import {Bar} from 'vue-chartjs'
74
74
  import Chart from 'chart.js/auto'
75
75
  import { color } from 'chart.js/helpers'
76
76
  import {strVars} from "../../utils/helpers.mjs";
77
- import {readyStateMixin} from "../../mixin/ready-state";
77
+ import {useEmitter} from "../../utils/event-bus";
78
78
 
79
79
  export default{
80
80
 
@@ -225,14 +225,43 @@ export default{
225
225
  ],
226
226
 
227
227
  height: '',
228
- datasets: null
228
+ datasets: null,
229
+ readyState: 1,
230
+ value: null
229
231
  }
230
232
  },
231
233
 
232
- inject: [ 'selectPreset' ],
234
+ inject: [ 'getSrc', 'getViewedPreset', 'getQueryFilters', 'selectPreset', 'socket' ],
233
235
 
234
236
  methods: {
235
237
 
238
+ load(){
239
+ const preset = this.getViewedPreset()
240
+ const {name, datasource} = preset
241
+
242
+ this.readyState = 2
243
+ this.socket.send(this.getSrc(), {
244
+ name,
245
+ views: [{
246
+ ...this.$props,
247
+ type: 'BarChart'
248
+ }],
249
+ datasource: datasource.map(_datasource => {
250
+ return {
251
+ ..._datasource,
252
+ filters: [
253
+ ...(_datasource.filters ?? []),
254
+ ...(this.getQueryFilters()[_datasource.uid] ?? [])
255
+ ]
256
+ }
257
+ })
258
+ })
259
+ .then(_ => {
260
+ this.value = _[this.uid]
261
+ })
262
+ .finally(_ => this.readyState = 1)
263
+ },
264
+
236
265
  onClick(e, segments){
237
266
 
238
267
  const clickInteractions = (this.interactions ?? []).filter(_ => _.event === 'click')
@@ -276,9 +305,17 @@ export default{
276
305
 
277
306
  mounted() {
278
307
  this.height = this.$el.clientHeight + 'px'
279
- },
280
308
 
281
- mixins: [ readyStateMixin ],
309
+ this.load()
310
+
311
+ this.emitter = useEmitter()
312
+ this.emitter.on(`${this.uid}.load`, () => {
313
+ this.load()
314
+ })
315
+ this.emitter.on(`dashboard.load`, () => {
316
+ this.load()
317
+ })
318
+ },
282
319
 
283
320
  props: {
284
321
 
@@ -309,8 +346,6 @@ export default{
309
346
 
310
347
  yAxeOnClick: Array,
311
348
 
312
- value: Object,
313
-
314
349
  interactions: Array,
315
350
 
316
351
  uid: String
@@ -0,0 +1,125 @@
1
+ <template>
2
+ <div :class="$style.comp">
3
+ <VirtualTable class="flex-1"
4
+ :columns="datasourceColumns"
5
+ @scroll-end="loadNext"
6
+ :items="items">
7
+
8
+ </VirtualTable>
9
+ </div>
10
+ </template>
11
+
12
+ <script>
13
+ import {useEmitter} from "../../utils/event-bus";
14
+ import VirtualTable from "../../components/VirtualTable.vue";
15
+
16
+ export default{
17
+ components: {VirtualTable},
18
+
19
+ data(){
20
+ return {
21
+ value: null,
22
+ readyState: 1,
23
+ items: null,
24
+ hasNext: false
25
+ }
26
+ },
27
+
28
+ inject: [ 'getSrc', 'getViewedPreset', 'getQueryFilters', 'socket' ],
29
+
30
+ methods: {
31
+
32
+ load(){
33
+ const preset = this.getViewedPreset()
34
+ const {name, datasource} = preset
35
+
36
+ this.readyState = 2
37
+ this.socket.send(this.getSrc(), {
38
+ name,
39
+ views: [{
40
+ ...this.$props,
41
+ type: 'DataTable'
42
+ }],
43
+ datasource: datasource.map(_datasource => {
44
+ return {
45
+ ..._datasource,
46
+ filters: [
47
+ ...(_datasource.filters ?? []),
48
+ ...(this.getQueryFilters()[_datasource.uid] ?? [])
49
+ ]
50
+ }
51
+ })
52
+ })
53
+ .then(_ => {
54
+ const { items, hasNext } = _[this.uid] ?? {}
55
+ this.items = items
56
+ this.hasNext = hasNext
57
+ })
58
+ .finally(_ => this.readyState = 1)
59
+ },
60
+
61
+ loadNext(){
62
+ if(!this.hasNext) return
63
+
64
+ const preset = this.getViewedPreset()
65
+ const {name, datasource} = preset
66
+ const afterItem = this.items[this.items.length - 1]
67
+
68
+ this.socket.send(this.getSrc(), {
69
+ name,
70
+ views: [{
71
+ ...this.$props,
72
+ type: 'DataTable',
73
+ afterItem
74
+ }],
75
+ datasource: datasource.map(_datasource => {
76
+ return {
77
+ ..._datasource,
78
+ filters: [
79
+ ...(_datasource.filters ?? []),
80
+ ...(this.getQueryFilters()[_datasource.uid] ?? [])
81
+ ]
82
+ }
83
+ })
84
+ })
85
+ .then(_ => {
86
+ const { items, hasNext } = _[this.uid] ?? {}
87
+ this.items.push(...items)
88
+ this.hasNext = hasNext
89
+ })
90
+ }
91
+
92
+ },
93
+
94
+ mounted() {
95
+ this.load()
96
+
97
+ this.emitter = useEmitter()
98
+ this.emitter.on(`${this.uid}.load`, () => {
99
+ this.load()
100
+ })
101
+ this.emitter.on(`dashboard.load`, () => {
102
+ this.load()
103
+ })
104
+ },
105
+
106
+ props: {
107
+
108
+ datasourceColumns: Array,
109
+ datasourceUid: String,
110
+ label: String,
111
+ uid: String,
112
+
113
+ }
114
+
115
+ }
116
+
117
+ </script>
118
+
119
+ <style module>
120
+
121
+ .comp{
122
+ @apply min-h-[50vh] flex flex-col;
123
+ }
124
+
125
+ </style>