@mixd-id/web-scaffold 0.1.230406374 → 0.1.230406377

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.230406374",
4
+ "version": "0.1.230406377",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -20,18 +20,29 @@
20
20
  "require": "./src/utils/helpers.js",
21
21
  "import": "./src/utils/helpers.mjs"
22
22
  },
23
+ "./helpers.js": "./src/utils/helpers.js",
24
+ "./helpers.mjs": "./src/utils/helpers.mjs",
25
+ "./queue": "./src/utils/queue.js",
26
+
23
27
  "./wss": {
24
28
  "require": "./src/utils/wss.js",
25
29
  "import": "./src/utils/wss.mjs"
26
30
  },
31
+ "./wss.js": "./src/utils/wss.js",
32
+ "./wss.mjs": "./src/utils/wss.mjs",
33
+
27
34
  "./importer": "./src/utils/importer.js",
28
35
  "./listpage1": "./src/utils/listpage1.js",
29
36
  "./dashboard": "./src/utils/dashboard.js",
30
37
  "./listview": "./src/utils/listview.js",
38
+
31
39
  "./preset-selector": {
32
40
  "require": "./src/utils/preset-selector.js",
33
41
  "import": "./src/utils/preset-selector.mjs"
34
42
  },
43
+ "./preset-selector.js": "./src/utils/preset-selector.js",
44
+ "./preset-selector.mjs": "./src/utils/preset-selector.mjs",
45
+
35
46
  "./web": "./src/utils/web.js"
36
47
  },
37
48
  "dependencies": {
@@ -40,6 +51,8 @@
40
51
  "@tailwindcss/line-clamp": "^0.4.0",
41
52
  "@vueuse/core": "^9.0.2",
42
53
  "adm-zip": "^0.5.10",
54
+ "axios": "^1.7.9",
55
+ "bcrypt": "^5.1.1",
43
56
  "chart.js": "^4.2.1",
44
57
  "compression": "^1.7.4",
45
58
  "cookie-parser": "^1.4.6",
@@ -58,6 +71,7 @@
58
71
  "pinia": "^2.3.0",
59
72
  "prismjs": "^1.28.0",
60
73
  "redis": "^4.6.13",
74
+ "sequelize": "^6.37.5",
61
75
  "serve-static": "^1.15.0",
62
76
  "tailwindcss": "^3.2.4",
63
77
  "vue": "^3.2.25",
@@ -70,6 +70,7 @@
70
70
  <div class="grid grid-cols-7 gap-2 mt-2">
71
71
  <div v-for="i in 7">{{ getDayOfWeekLabel(i) }}</div>
72
72
  <button type="button" :class="buttonStyle(d.value)"
73
+ :disabled="allowedDates && !allowedDates.includes(d.value)"
73
74
  v-for="d in contextMenuDates" @click="setValue(d.value)">
74
75
  {{ d.date }}
75
76
  </button>
@@ -140,6 +141,8 @@ export default{
140
141
 
141
142
  readonly: undefined,
142
143
 
144
+ allowedDates: Array,
145
+
143
146
  },
144
147
 
145
148
  computed:{
@@ -181,17 +184,22 @@ export default{
181
184
  for(let i = 1 ; i <= 42 ; i++){
182
185
  if(startDayOfMonth > 0){
183
186
  startDayOfMonth--
187
+ const value = dayjsInput.subtract(1, 'month')
188
+ .format(`YYYY-MM-${(endDateOfLastMonth - startDayOfMonth).toString().padStart(2, '0')}`)
189
+
184
190
  dates.push({
185
191
  date: endDateOfLastMonth - startDayOfMonth,
186
- value: year + '-' + month.toString().padStart(2, '0') + '-' + (endDateOfLastMonth - startDayOfMonth).toString().padStart(2, '0'),
187
- type: -1
192
+ value,
193
+ type: -1
188
194
  })
189
195
  }
190
196
  else if(currentDate > endDateOfMonth){
191
- dates.push({
197
+ const value = dayjsInput.add(1, 'month').format(`YYYY-MM-${nextDate.toString().padStart(2, '0')}`)
198
+
199
+ dates.push({
192
200
  date: nextDate,
193
- value: year + '-' + (month + 2).toString().padStart(2, '0') + '-' + nextDate.toString().padStart(2, '0'),
194
- type: 1
201
+ value,
202
+ type: 1
195
203
  })
196
204
  nextDate++
197
205
  }
@@ -283,21 +291,27 @@ export default{
283
291
  }
284
292
  .datepicker input[type=radio]{
285
293
  @apply hidden;
286
- }
294
+ }K
287
295
  .datepicker input[type=radio]:checked + label{
288
296
  }
289
297
 
290
298
  .button{
291
299
  @apply rounded-full aspect-square;
292
300
  }
293
- .button:hover{
301
+ .button:not(:disabled){
302
+ @apply cursor-default;
303
+ }
304
+ .button:disabled{
305
+ @apply text-text-300;
306
+ }
307
+ .button:not(:disabled):hover{
294
308
  @apply bg-primary-200;
295
309
  }
296
310
  .button.selected{
297
311
  @apply bg-primary text-white;
298
312
  }
299
- .button.otherMonth{
300
- @apply text-text-300;
313
+ .button:not(:disabled).otherMonth{
314
+ @apply text-text-400;
301
315
  }
302
316
 
303
317
  .arrow{
@@ -270,8 +270,9 @@ import VirtualGrid from "./VirtualGrid.vue";
270
270
  import throttle from "lodash/throttle";
271
271
  import PresetSelector from "../widgets/PresetSelector.vue";
272
272
  import groupBy from "lodash/groupBy";
273
- import { generatePivotColumns, generateTotalColumns, sortsFn } from "../utils/preset-selector.mjs";
273
+ import {generatePivotColumns, generateTotalColumns, sortsFn} from "../utils/preset-selector.mjs";
274
274
  import PresetBar from "../widgets/PresetBar.vue";
275
+ import {queueForLater} from "../utils/helpers.mjs";
275
276
 
276
277
  export default{
277
278
 
@@ -315,7 +316,9 @@ export default{
315
316
  toolbar: {
316
317
  type: [ String, Boolean ],
317
318
  default: true
318
- }
319
+ },
320
+
321
+ sorts: Array
319
322
  },
320
323
 
321
324
  methods: {
@@ -394,23 +397,15 @@ export default{
394
397
  ((this.data ?? {}).hasNext !== false) &&
395
398
  !(this.preset.pivot ?? {}).enabled) {
396
399
 
397
- const afterItem = this.data.items[this.data.items.length - 1]
398
- console.log('#next', afterItem.id, afterItem.lastMessageAt)
400
+ const afterItem = this.dataItems[this.dataItems.length - 1]
399
401
 
400
402
  this.readyState = 4
401
403
  this.socket.send(this.src, {
402
404
  ...this.preset,
403
405
  itemsPerPage: this.data.itemsPerPage,
404
- afterItem: this.data.items[this.data.items.length - 1],
406
+ afterItem,
405
407
  })
406
408
  .then(data => {
407
- const firstItem = data.items[0]
408
- const lastItem = data.items[data.items.length - 1]
409
- console.log('#loaded',
410
- firstItem?.id, firstItem?.lastMessageAt,
411
- lastItem?.id, lastItem?.lastMessageAt,
412
- data.items.length)
413
-
414
409
  this.data.items.push(...data.items)
415
410
  this.loadEnums(data.items)
416
411
  })
@@ -595,6 +590,21 @@ export default{
595
590
  }
596
591
  },
597
592
 
593
+ loadQueued(items){
594
+ const key = items[0] && items[0].uid ? 'uid' : 'id'
595
+
596
+ this.socket.send(this.src, {
597
+ ...this.preset,
598
+ [key]: items.map(item => item[key])
599
+ })
600
+ .then(({ items:nextItems }) => {
601
+ nextItems.forEach(item => this.$util.unshift(this.data.items, item, { highlight: true }))
602
+
603
+ const destroyedItems = items.filter(_ => !nextItems.find(i => i[key] === _[key]))
604
+ this.$util.remove(this.data.items, destroyedItems)
605
+ })
606
+ },
607
+
598
608
  onSignal(event, items){
599
609
  if(this.pivotEnabled) return
600
610
  if(!Array.isArray(items) || items.length < 1) return
@@ -606,18 +616,7 @@ export default{
606
616
  break
607
617
 
608
618
  default:
609
- const key = items[0] && items[0].uid ? 'uid' : 'id'
610
-
611
- this.socket.send(this.src, {
612
- ...this.preset,
613
- [key]: items.map(item => item[key])
614
- })
615
- .then(({ items:nextItems }) => {
616
- nextItems.forEach(item => this.$util.unshift(this.data.items, item, { highlight: true }))
617
-
618
- const destroyedItems = items.filter(_ => !nextItems.find(i => i[key] === _[key]))
619
- this.$util.remove(this.data.items, destroyedItems)
620
- })
619
+ this.queue(items)
621
620
  break
622
621
  }
623
622
 
@@ -816,6 +815,10 @@ export default{
816
815
  }
817
816
 
818
817
  window.addEventListener('keydown', this.onKeyDown)
818
+
819
+ this.queue = queueForLater({
820
+ pop: this.loadQueued
821
+ })
819
822
  },
820
823
 
821
824
  unmounted() {
@@ -910,7 +913,13 @@ export default{
910
913
  },
911
914
 
912
915
  dataItems(){
913
- if((this.preset.sorts ?? []).length > 0){
916
+
917
+ if((this.sorts ?? []).length > 0){
918
+ return (this.data.items ?? []).sort((a, b) => {
919
+ return sortsFn(a, b, this.sorts, 0)
920
+ })
921
+ }
922
+ else if((this.preset.sorts ?? []).length > 0){
914
923
  return (this.data.items ?? []).sort((a, b) => {
915
924
  return sortsFn(a, b, this.preset.sorts, 0)
916
925
  })
@@ -978,6 +987,7 @@ export default{
978
987
  enumCache: {},
979
988
  extItems: null,
980
989
  lastEnumItems: null,
990
+ queue: null,
981
991
  }
982
992
  },
983
993
 
@@ -6,7 +6,7 @@
6
6
  <div class="flex-1 flex flex-row gap-2">
7
7
  <Dropdown v-model="value.operator"
8
8
  :readonly="readonly"
9
- :class="![ 'yesterday', 'today', 'thisWeek', 'thisMonth', 'lastMonth', 'thisYear' ].includes(value.operator) ? 'w-[100px]' : 'w-full'"
9
+ :class="![ 'yesterday', 'today', 'thisWeek', 'thisMonth', 'lastMonth', 'thisYear', 'null' ].includes(value.operator) ? 'w-[100px]' : 'w-full'"
10
10
  @change="apply">
11
11
  <option value="=">=</option>
12
12
  <option value=">">&gt;</option>
@@ -20,8 +20,9 @@
20
20
  <option value="thisMonth">This Month</option>
21
21
  <option value="lastMonth">Last Month</option>
22
22
  <option value="thisYear">This Year</option>
23
+ <option value="null">No Value</option>
23
24
  </Dropdown>
24
- <div v-if="![ 'yesterday', 'today', 'thisWeek', 'thisMonth', 'lastMonth', 'thisYear' ].includes(value.operator)"
25
+ <div v-if="![ 'yesterday', 'today', 'thisWeek', 'thisMonth', 'lastMonth', 'thisYear', 'null' ].includes(value.operator)"
25
26
  class="flex-1 flex flex-row gap-2">
26
27
  <Datepicker class="flex-1"
27
28
  mode="popup"
package/src/index.js CHANGED
@@ -393,6 +393,7 @@ export default{
393
393
 
394
394
  const privateVars = {}
395
395
 
396
+ app.config.globalProperties.$t = t => t
396
397
  app.config.globalProperties.uniqid = uniqid
397
398
  app.config.globalProperties.formatDate = formatDate
398
399
  app.config.globalProperties.$download = download
@@ -1,10 +1,3 @@
1
- const md5 = require("md5");
2
- const fs = require("fs");
3
- const { Op } = require('sequelize')
4
- const axios = require('axios')
5
- const dayjs = require('dayjs')
6
-
7
-
8
1
  const ceil = (num, precision = 0) => {
9
2
  var p = Math.pow(10, precision)
10
3
  var n = (num * p) * (1 + Number.EPSILON)
@@ -32,6 +25,7 @@ const ftWildcard = (key) => {
32
25
  }
33
26
 
34
27
  const moveFile = function(oldPath, newPath, callback) {
28
+ const fs = require("fs");
35
29
 
36
30
  fs.rename(oldPath, newPath, function (err) {
37
31
  if (err) {
@@ -46,6 +40,8 @@ const moveFile = function(oldPath, newPath, callback) {
46
40
  });
47
41
 
48
42
  function copy() {
43
+ const fs = require("fs");
44
+
49
45
  var readStream = fs.createReadStream(oldPath);
50
46
  var writeStream = fs.createWriteStream(newPath);
51
47
 
@@ -96,6 +92,9 @@ const saveBase64 = async(data, dir = '/storage/files/images') => {
96
92
 
97
93
  const saveBuffer = async(buffer, dir = '/storage/files/images') => {
98
94
 
95
+ const fs = require("fs");
96
+ const md5 = require('md5')
97
+
99
98
  const { fileTypeFromBuffer } = await import('file-type')
100
99
 
101
100
  const type = await fileTypeFromBuffer(buffer)
@@ -111,6 +110,7 @@ const saveBuffer = async(buffer, dir = '/storage/files/images') => {
111
110
  }
112
111
 
113
112
  const saveFromUrl = async(url, dir = '/storage/files/images') => {
113
+ const axios = require('axios')
114
114
 
115
115
  const res = await axios({
116
116
  method: 'GET',
@@ -153,6 +153,8 @@ const strVars = (text, vars, opt = { emptyUndefined:true }) => {
153
153
 
154
154
  const writeStorage = (path, content, append = false) => {
155
155
 
156
+ const fs = require("fs");
157
+
156
158
  if(path.startsWith('/')) path = path.substring(1)
157
159
 
158
160
  if(append){
@@ -195,6 +197,8 @@ const sequelizeChunk = async (model, opt, callback, chunkSize = 5000) => {
195
197
 
196
198
  const getPresetSortWhereParams = (order, afterItem) => {
197
199
 
200
+ const { Op } = require('sequelize')
201
+
198
202
  if(order.filter((_) => _[0] === 'id').length <= 0){
199
203
  order.push([ 'id', 'desc' ])
200
204
  }
@@ -505,6 +509,7 @@ const datasourceLoad = async ({ datasource, Models }) => {
505
509
  }
506
510
 
507
511
  const dayTimeRange = (params, value) => {
512
+ const dayjs = require('dayjs')
508
513
 
509
514
  /*params = {
510
515
  '*': [ [ '08:00', '12:00' ], [ '13:00', '18:00' ] ],
@@ -543,6 +548,18 @@ const removeUnderscoredKey = (obj) => {
543
548
  }
544
549
  }
545
550
 
551
+ const hashMake = async (text) => {
552
+ const bcrypt = require('bcrypt')
553
+
554
+ return bcrypt.hash(text + (process.env.APP_KEY ?? ''), 10)
555
+ }
556
+
557
+ const hashCheck = (text, hash) => {
558
+ const bcrypt = require('bcrypt')
559
+
560
+ return bcrypt.compare(text + (process.env.APP_KEY ?? ''), hash)
561
+ }
562
+
546
563
  module.exports = {
547
564
  capitalize,
548
565
  ceil,
@@ -572,5 +589,7 @@ module.exports = {
572
589
  datasourceGet,
573
590
  datasourceLoad,
574
591
  dayTimeRange,
575
- removeUnderscoredKey
592
+ removeUnderscoredKey,
593
+ hashMake,
594
+ hashCheck
576
595
  }
@@ -390,6 +390,35 @@ const invokeAfterIdle = (callback, delay = 1300) => {
390
390
  }
391
391
  }
392
392
 
393
+ const queueForLater = (params) => {
394
+
395
+ const instance = {
396
+ delay: 1500,
397
+ ...params,
398
+
399
+ items: [],
400
+ timeoutId: null,
401
+
402
+ run: () => {
403
+ const items = instance.items.splice(0, instance.items.length);
404
+ typeof instance.pop === 'function' ? instance.pop(items) : null;
405
+ instance.timeoutId = null
406
+ },
407
+
408
+ queue(item) {
409
+ if(Array.isArray(item))
410
+ instance.items.push(...item)
411
+ else
412
+ instance.items.push(item)
413
+
414
+ if(!instance.timeoutId)
415
+ instance.timeoutId = window.setTimeout(instance.run, instance.delay);
416
+ }
417
+ }
418
+
419
+ return instance.queue
420
+ }
421
+
393
422
 
394
423
  export {
395
424
  capitalize,
@@ -416,7 +445,8 @@ export {
416
445
  unslugAndCapitalize,
417
446
  applyDatasourceReplacer,
418
447
  strVars,
419
- invokeAfterIdle
448
+ invokeAfterIdle,
449
+ queueForLater
420
450
  }
421
451
 
422
452
  function observeInit(){
@@ -113,6 +113,16 @@ const getValue = (filter, opt) => {
113
113
  }
114
114
  break
115
115
 
116
+ case 'null':
117
+ withoutKey ?
118
+ whereObj = {
119
+ [Op.eq]: null
120
+ } :
121
+ whereObj[key] = {
122
+ [Op.eq]: null
123
+ }
124
+ break
125
+
116
126
  case 'between':
117
127
  withoutKey ?
118
128
  whereObj = {
@@ -472,6 +482,12 @@ const filtersToSequelizeWhere = async(filters, opt) => {
472
482
  }
473
483
  break
474
484
 
485
+ case 'null':
486
+ whereObj = {
487
+ [key]: null
488
+ }
489
+ break
490
+
475
491
  case 'between':
476
492
  whereObj = {
477
493
  [key]:{
@@ -0,0 +1,63 @@
1
+ const redis = require('redis');
2
+ const client = redis.createClient();
3
+ client.connect()
4
+ .then(() => console.log('Connected to Redis'))
5
+ .catch((err) => console.error('Redis connection error:', err));
6
+
7
+ const queues = {}
8
+
9
+ const sleep = ms => new Promise(r => setTimeout(r, ms))
10
+
11
+ const processQueue = async(key) => {
12
+ const queue = queues[key]
13
+ if(queue.processing) return
14
+ queue.processing = true
15
+
16
+ const result = await client.hGetAll(key);
17
+ const keys = Object.keys(result ?? {})
18
+ if(keys.length < 1){
19
+ queue.processing = false
20
+ return
21
+ }
22
+
23
+ const itemKeys = keys.splice(0, queue.concurrency)
24
+ if(itemKeys.length > 0){
25
+ await Promise.all(itemKeys.map(async itemKey => {
26
+ try{
27
+ const obj = JSON.parse(await client.hGet(key, itemKey))
28
+ await queue.pop(obj)
29
+ }
30
+ finally{
31
+ await client.hDel(key, itemKey)
32
+ }
33
+ }))
34
+
35
+ await sleep(queue.interval ?? 0)
36
+ }
37
+ queue.processing = false
38
+
39
+ await processQueue(key)
40
+ }
41
+
42
+ const queueItem = async(obj, opt) => {
43
+ if(!queues[opt.key]){
44
+ queues[opt.key] = {
45
+ interval: 16,
46
+ concurrency: 1,
47
+
48
+ ...opt
49
+ }
50
+
51
+ await client.del(opt.key)
52
+ }
53
+
54
+ const { key } = opt
55
+ const subKey = `${key}-${new Date().getTime() + Math.random()}`
56
+ await client.hSet(key, subKey, JSON.stringify(obj));
57
+
58
+ processQueue(key).then()
59
+ }
60
+
61
+ module.exports = {
62
+ queueItem
63
+ }
package/src/utils/wss.js CHANGED
@@ -222,7 +222,14 @@ class WSS extends EventEmitter2{
222
222
 
223
223
  const token = req.headers['sec-websocket-protocol'];
224
224
  try{
225
- await this._opt.auth(token, socket)
225
+ if(this._opt.auth){
226
+ await this._opt.auth(token, socket)
227
+ }
228
+
229
+ for(let fn of this._authFn) {
230
+ await fn(token, socket)
231
+ }
232
+
226
233
  socket.isAuth = true
227
234
  socket.send(await this.toBinaryData({ auth:true }))
228
235
 
@@ -230,7 +237,7 @@ class WSS extends EventEmitter2{
230
237
  await subscriber.connect()
231
238
  }
232
239
  catch(e){
233
- return socket.close(1002, e.message);
240
+ return socket.close(1002, (e.message ?? '').substring(0, 123));
234
241
  }
235
242
 
236
243
  if(this._opt.ping !== false){
@@ -271,6 +278,10 @@ class WSS extends EventEmitter2{
271
278
  this._reqFn.push(fn)
272
279
  }
273
280
 
281
+ use(fn){
282
+ this.req.apply(this, arguments)
283
+ }
284
+
274
285
  async broadcast(channels, { model, event, items }){
275
286
 
276
287
  if(!Array.isArray(channels))
package/src/utils/wss.mjs CHANGED
@@ -69,7 +69,6 @@ class WSS extends EventEmitter2{
69
69
  this.emit('visibilitychange', this._instance.readyState, [])
70
70
 
71
71
  this.ping().catch(e => {
72
- console.log('ping error', e)
73
72
  this.reconnect().then()
74
73
  })
75
74
  }
@@ -128,8 +127,8 @@ class WSS extends EventEmitter2{
128
127
 
129
128
  if(this._opt.debug){
130
129
  status === 200 ?
131
- console.log(`${new Date().getTime() - t1}ms`, `l:${JSON.stringify(data ?? '').length}`, path, params, data) :
132
- console.error(`${new Date().getTime() - t1}ms`, `l:${JSON.stringify(data ?? '').length}`, path, params, data)
130
+ console.log(`${path} (${new Date().getTime() - t1}ms)`, params, data, `l:${JSON.stringify(data ?? '').length}`) :
131
+ console.error(`${path} (${new Date().getTime() - t1}ms)`, params, data, `l:${JSON.stringify(data ?? '').length}`)
133
132
  }
134
133
  }
135
134
  }
@@ -185,6 +184,7 @@ class WSS extends EventEmitter2{
185
184
 
186
185
  sendSync(path, params, cb, err, override){
187
186
  if(!this._instance || this._instance.readyState > 1){
187
+ this._pendingSend.push({ path, params, cb, err })
188
188
  return
189
189
  }
190
190
  else if(!this._instance.isAuth){