@mixd-id/web-scaffold 0.2.240705 → 0.2.250801009

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.
Files changed (220) hide show
  1. package/docs/components/Dashboard.md +56 -0
  2. package/log.txt +7 -0
  3. package/package.json +27 -19
  4. package/src/components/404.vue +61 -0
  5. package/src/components/AccountIcon.vue +19 -0
  6. package/src/components/Ahref.vue +1 -1
  7. package/src/components/Alert.vue +4 -13
  8. package/src/components/ArrayList.vue +49 -0
  9. package/src/components/Article.vue +24 -30
  10. package/src/components/Button.vue +79 -167
  11. package/src/components/Card.vue +235 -0
  12. package/src/components/Carousel.vue +61 -60
  13. package/src/components/Cart.vue +192 -0
  14. package/src/components/CartIcon.vue +89 -0
  15. package/src/components/ChartBar.vue +2 -3
  16. package/src/components/Checkbox.vue +20 -11
  17. package/src/components/Checkout.vue +373 -0
  18. package/src/components/CheckoutDelivery.vue +267 -0
  19. package/src/components/CodeEditor.vue +5 -16
  20. package/src/components/CollapsiblePanel.vue +70 -0
  21. package/src/components/ColorPicker.vue +8 -3
  22. package/src/components/ColorPicker2.vue +41 -19
  23. package/src/components/ColorPicker3.vue +100 -0
  24. package/src/components/Confirm.vue +9 -7
  25. package/src/components/ContextMenu.vue +122 -206
  26. package/src/components/ContextMenuItem.vue +53 -0
  27. package/src/components/Dashboard.vue +243 -0
  28. package/src/components/Dashboard2.vue +118 -0
  29. package/src/components/DashboardComponentSelector.vue +96 -0
  30. package/src/components/DashboardConfigs.vue +202 -0
  31. package/src/components/Datepicker.vue +102 -41
  32. package/src/components/DayTimeRange.vue +3 -2
  33. package/src/components/Dropdown.vue +7 -4
  34. package/src/components/Flex.vue +14 -40
  35. package/src/components/GHeatMaps.vue +2 -2
  36. package/src/components/Grid.vue +6 -6
  37. package/src/components/HTMLEditor.vue +27 -14
  38. package/src/components/Image.vue +62 -108
  39. package/src/components/ImagePreview.vue +14 -4
  40. package/src/components/ImageUploader.vue +114 -0
  41. package/src/components/ImportModal.vue +3 -3
  42. package/src/components/Link.vue +62 -6
  43. package/src/components/List.vue +524 -402
  44. package/src/components/ListContextMenu.vue +88 -0
  45. package/src/components/ListItem.vue +5 -3
  46. package/src/components/ListPage1.vue +14 -15
  47. package/src/components/ListView.vue +5 -6
  48. package/src/components/ListViewSettings.vue +2 -2
  49. package/src/components/LogViewerItem.vue +1 -1
  50. package/src/components/MarkdownEdit.vue +128 -0
  51. package/src/components/MarkdownPreview.vue +102 -0
  52. package/src/components/MenuItem1.vue +36 -0
  53. package/src/components/Modal.vue +95 -43
  54. package/src/components/MultiDropdown.vue +124 -0
  55. package/src/components/MultilineText.vue +1 -4
  56. package/src/components/OTPField.vue +11 -17
  57. package/src/components/ObjectTree.vue +1 -1
  58. package/src/components/PageBuilder.vue +3 -3
  59. package/src/components/Paragraph.vue +1 -2
  60. package/src/components/PresetSelectorFilterItem.vue +107 -95
  61. package/src/components/Radio.vue +1 -1
  62. package/src/components/SearchModal.vue +153 -0
  63. package/src/components/Slider.vue +1 -1
  64. package/src/components/Svg.vue +1 -1
  65. package/src/components/SvgEditor.vue +173 -0
  66. package/src/components/Switch.vue +4 -5
  67. package/src/components/Table.vue +2 -2
  68. package/src/components/TableView.vue +2 -3
  69. package/src/components/TableViewHead.vue +2 -2
  70. package/src/components/Tabs.vue +1 -1
  71. package/src/components/Testimonial.vue +2 -2
  72. package/src/components/Text.vue +7 -22
  73. package/src/components/TextEditor.vue +3 -3
  74. package/src/components/TextWithTag.vue +61 -30
  75. package/src/components/Textarea.vue +11 -16
  76. package/src/components/Textbox.vue +9 -19
  77. package/src/components/Timepicker.vue +25 -15
  78. package/src/components/Toast.vue +5 -3
  79. package/src/components/TreeMenu.vue +122 -0
  80. package/src/components/TreeView.vue +15 -10
  81. package/src/components/TreeView2.vue +38 -0
  82. package/src/components/TreeViewItem.vue +58 -29
  83. package/src/components/TreeViewItem2.vue +55 -0
  84. package/src/components/Uploader.vue +45 -0
  85. package/src/components/Video.vue +119 -0
  86. package/src/components/VirtualGrid.vue +24 -7
  87. package/src/components/VirtualTable.vue +363 -128
  88. package/src/configs/dashboard/data-table.js +9 -0
  89. package/src/configs/web-page-builder.js +118 -0
  90. package/src/directives/intersect.js +26 -0
  91. package/src/hooks/device.js +14 -0
  92. package/src/index.js +62 -107
  93. package/src/mixin/component.js +147 -67
  94. package/src/themes/default/index.js +83 -155
  95. package/src/utils/dashboard.js +22 -962
  96. package/src/utils/helpers.cjs +635 -0
  97. package/src/utils/helpers.js +91 -60
  98. package/src/utils/helpers.mjs +245 -12
  99. package/src/utils/importer.js +22 -3
  100. package/src/utils/list.mjs +1509 -0
  101. package/src/utils/preset-selector.cjs +1455 -0
  102. package/src/utils/preset-selector.js +489 -95
  103. package/src/utils/preset-selector.mjs +59 -20
  104. package/src/utils/queue.js +63 -0
  105. package/src/utils/web.mjs +120 -0
  106. package/src/utils/wss.js +37 -29
  107. package/src/utils/wss.mjs +24 -19
  108. package/src/widgets/AhrefSetting.vue +16 -13
  109. package/src/widgets/ArticleSetting.vue +15 -27
  110. package/src/widgets/BackgroundColorSetting.vue +153 -0
  111. package/src/widgets/BorderColorSetting.vue +57 -0
  112. package/src/widgets/BotEditor/BotEditorActions.vue +3 -2
  113. package/src/widgets/BotEditor/BotEditorSettings.vue +21 -0
  114. package/src/widgets/BotEditor.vue +35 -15
  115. package/src/widgets/ButtonSetting.vue +12 -13
  116. package/src/widgets/CarouselSetting.vue +33 -45
  117. package/src/widgets/CartSetting.vue +46 -0
  118. package/src/widgets/CheckoutSetting.vue +46 -0
  119. package/src/widgets/CollapsiblePanelSetting.vue +46 -0
  120. package/src/widgets/ColumnSelector.vue +29 -5
  121. package/src/widgets/ComponentSetting.vue +1 -1
  122. package/src/widgets/ComponentSetting2.vue +112 -234
  123. package/src/widgets/ComponentSetting3.vue +1 -1
  124. package/src/widgets/ContactForm.vue +3 -3
  125. package/src/widgets/ContactFormSetting.vue +41 -30
  126. package/src/widgets/Dashboard/BarChart.vue +47 -11
  127. package/src/widgets/Dashboard/BarChartSetting.vue +1 -1
  128. package/src/widgets/Dashboard/DataTable.vue +125 -0
  129. package/src/widgets/Dashboard/DataTableSetting.vue +243 -0
  130. package/src/widgets/Dashboard/DatasourceSelector.vue +1 -1
  131. package/src/widgets/Dashboard/Doughnut.vue +49 -7
  132. package/src/widgets/Dashboard/DoughnutSetting.vue +2 -2
  133. package/src/widgets/Dashboard/Metric.vue +78 -19
  134. package/src/widgets/Dashboard/MetricSetting.vue +81 -28
  135. package/src/widgets/Dashboard/Pie.vue +55 -6
  136. package/src/widgets/Dashboard/PieSetting.vue +1 -1
  137. package/src/widgets/Dashboard/PolarArea.vue +49 -7
  138. package/src/widgets/Dashboard/PolarAreaSetting.vue +1 -1
  139. package/src/widgets/Dashboard/SharingModal.vue +4 -5
  140. package/src/widgets/Dashboard/ViewSelector.vue +2 -2
  141. package/src/widgets/Dashboard/VirtualTableSetting.vue +121 -184
  142. package/src/widgets/{Dashboard.vue → Dashboard0.vue} +426 -343
  143. package/src/widgets/EmbeddedVideoSetting.vue +7 -5
  144. package/src/widgets/FAQ.vue +16 -3
  145. package/src/widgets/FAQSetting.vue +53 -47
  146. package/src/widgets/FeatureList.vue +3 -0
  147. package/src/widgets/FeatureListSetting.vue +112 -102
  148. package/src/widgets/FlexSetting.vue +83 -106
  149. package/src/widgets/GridSetting.vue +71 -196
  150. package/src/widgets/Header2.vue +34 -71
  151. package/src/widgets/Header2Setting.vue +95 -179
  152. package/src/widgets/HeaderSetting.vue +16 -18
  153. package/src/widgets/IconListSetting.vue +69 -65
  154. package/src/widgets/ImageSetting.vue +33 -60
  155. package/src/widgets/LinkSetting.vue +60 -37
  156. package/src/widgets/LinkSettingModal.vue +173 -0
  157. package/src/widgets/LogViewer.vue +1 -1
  158. package/src/widgets/MarginSetting.vue +2 -2
  159. package/src/widgets/MenuEditor.vue +1 -1
  160. package/src/widgets/MenuItem1Setting.vue +78 -0
  161. package/src/widgets/ModalSetting.vue +42 -44
  162. package/src/widgets/MultiValueSetting.vue +2 -2
  163. package/src/widgets/MultiValueSetting2.vue +78 -45
  164. package/src/widgets/OGSettingModal.vue +103 -0
  165. package/src/widgets/PaddingSetting.vue +2 -2
  166. package/src/widgets/ParagraphSetting.vue +16 -13
  167. package/src/widgets/PositionSetting.vue +209 -0
  168. package/src/widgets/PresetBar.vue +359 -210
  169. package/src/widgets/PresetBarPivot.vue +31 -19
  170. package/src/widgets/PresetSelector.vue +29 -17
  171. package/src/widgets/SearchModalSetting.vue +70 -0
  172. package/src/widgets/Share.vue +1 -2
  173. package/src/widgets/ShareSetting.vue +67 -60
  174. package/src/widgets/StyleSetting.vue +227 -116
  175. package/src/widgets/TestimonialSetting.vue +97 -88
  176. package/src/widgets/TextBlockSetting.vue +16 -13
  177. package/src/widgets/UserActionBuilder/UserActionConsole.vue +30 -10
  178. package/src/widgets/UserActionBuilder/UserActionOutput.vue +2 -2
  179. package/src/widgets/UserActionBuilder/UserActionOutputReply.vue +64 -87
  180. package/src/widgets/UserActionBuilder/UserActionProps.vue +3 -3
  181. package/src/widgets/UserActionBuilder.vue +4 -16
  182. package/src/widgets/WebComponentSelector.vue +15 -11
  183. package/src/widgets/WebLayoutSelector.vue +41 -270
  184. package/src/widgets/WebPageBuilder.vue +693 -704
  185. package/src/widgets/WebPageBuilder2.vue +7 -7
  186. package/src/widgets/WebPageBuilder4/ButtonSetting.vue +0 -8
  187. package/src/widgets/WebPageBuilder4/CarouselSetting.vue +63 -7
  188. package/src/widgets/WebPageBuilder4/FlexAlignSetting.vue +3 -3
  189. package/src/widgets/WebPageBuilder4/FlexSetting.vue +1 -10
  190. package/src/widgets/WebPageBuilder4/MultiValueSetting.vue +2 -2
  191. package/src/widgets/WebPageBuilder4/PropertySetting.vue +0 -7
  192. package/src/widgets/WebPageBuilder4/WebPageComponentSelector.vue +1 -7
  193. package/src/widgets/WebPageBuilder4.vue +289 -575
  194. package/src/widgets/WebPageSelector.vue +1 -1
  195. package/src/widgets/YoutubeVideoSetting.vue +16 -13
  196. package/tailwind.config.js +3 -35
  197. package/docs/schema/user-action.json +0 -266
  198. package/src/App.vue +0 -25
  199. package/src/components/SearchButton.vue +0 -57
  200. package/src/entry-client.js +0 -27
  201. package/src/entry-server.js +0 -73
  202. package/src/events/event.js +0 -2
  203. package/src/main.js +0 -29
  204. package/src/mixin/website.js +0 -121
  205. package/src/router.js +0 -57
  206. package/src/widgets/MobileMenu.vue +0 -182
  207. package/src/widgets/WebPageBuilder4/ActionSetting.vue +0 -158
  208. package/src/widgets/WebPageBuilder4/ColorSetting.vue +0 -63
  209. package/src/widgets/WebPageBuilder4/DataSetting.vue +0 -92
  210. package/src/widgets/WebPageBuilder4/FontSizeSetting.vue +0 -76
  211. package/src/widgets/WebPageBuilder4/LinkSetting.vue +0 -68
  212. package/src/widgets/WebPageBuilder4/MobileMenuSetting.vue +0 -106
  213. package/src/widgets/WebPageBuilder4/Setting.vue +0 -73
  214. package/src/widgets/WebPageBuilder4/StyleSetting.vue +0 -77
  215. package/src/widgets/WebPageBuilder4/SvgSetting.vue +0 -207
  216. package/src/widgets/WebPageBuilder4/TextTransformSetting.vue +0 -70
  217. package/src/widgets/WebPageBuilder4/WebPageDataEdit.vue +0 -121
  218. package/test.json +0 -22
  219. /package/src/widgets/{Header1.vue → Header0.vue} +0 -0
  220. /package/src/widgets/{Header1Setting.vue → Header0Setting.vue} +0 -0
@@ -1,11 +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
- const { camelCase } = require('lodash')
7
-
8
-
9
1
  const ceil = (num, precision = 0) => {
10
2
  var p = Math.pow(10, precision)
11
3
  var n = (num * p) * (1 + Number.EPSILON)
@@ -33,6 +25,7 @@ const ftWildcard = (key) => {
33
25
  }
34
26
 
35
27
  const moveFile = function(oldPath, newPath, callback) {
28
+ const fs = require("fs");
36
29
 
37
30
  fs.rename(oldPath, newPath, function (err) {
38
31
  if (err) {
@@ -47,6 +40,8 @@ const moveFile = function(oldPath, newPath, callback) {
47
40
  });
48
41
 
49
42
  function copy() {
43
+ const fs = require("fs");
44
+
50
45
  var readStream = fs.createReadStream(oldPath);
51
46
  var writeStream = fs.createWriteStream(newPath);
52
47
 
@@ -97,6 +92,9 @@ const saveBase64 = async(data, dir = '/storage/files/images') => {
97
92
 
98
93
  const saveBuffer = async(buffer, dir = '/storage/files/images') => {
99
94
 
95
+ const fs = require("fs");
96
+ const md5 = require('md5')
97
+
100
98
  const { fileTypeFromBuffer } = await import('file-type')
101
99
 
102
100
  const type = await fileTypeFromBuffer(buffer)
@@ -112,6 +110,7 @@ const saveBuffer = async(buffer, dir = '/storage/files/images') => {
112
110
  }
113
111
 
114
112
  const saveFromUrl = async(url, dir = '/storage/files/images') => {
113
+ const axios = require('axios')
115
114
 
116
115
  const res = await axios({
117
116
  method: 'GET',
@@ -141,20 +140,21 @@ const strSlug = (title, separator) => {
141
140
  return title.replace(new RegExp('^[' + separator + '\\s]+|[' + separator + '\\s]+$', 'g'),'');
142
141
  }
143
142
 
144
- const strVars = (text, vars = {}, opt = { emptyUndefined:true }) => {
145
- if(text){
146
- (text.match(/\{.*?(?=\})\}/gi) ?? []).forEach((match) => {
147
- const key = match.substring(1, match.length - 1)
148
- const value = vars[key] ?? (opt?.emptyUndefined ? '' : `{${key}}`)
149
- text = text.replace(match, value)
150
- })
151
- }
143
+ const strVars = (text, vars, opt = { emptyUndefined:true }) => {
144
+
145
+ (text.match(/\{.*?(?=\})\}/gi) ?? []).forEach((match) => {
146
+ const key = match.substring(1, match.length - 1)
147
+ const value = vars[key] ?? (opt?.emptyUndefined ? '' : `{${key}}`)
148
+ text = text.replace(match, value)
149
+ })
152
150
 
153
151
  return text
154
152
  }
155
153
 
156
154
  const writeStorage = (path, content, append = false) => {
157
155
 
156
+ const fs = require("fs");
157
+
158
158
  if(path.startsWith('/')) path = path.substring(1)
159
159
 
160
160
  if(append){
@@ -197,6 +197,8 @@ const sequelizeChunk = async (model, opt, callback, chunkSize = 5000) => {
197
197
 
198
198
  const getPresetSortWhereParams = (order, afterItem) => {
199
199
 
200
+ const { Op } = require('sequelize')
201
+
200
202
  if(order.filter((_) => _[0] === 'id').length <= 0){
201
203
  order.push([ 'id', 'desc' ])
202
204
  }
@@ -262,7 +264,7 @@ const unflatten = (flatObject) => {
262
264
  }
263
265
 
264
266
  const accessNestedObject = function(obj, path) {
265
- if(!obj || typeof path !== 'string') return
267
+ if(!obj || typeof path !== 'string') return undefined
266
268
 
267
269
  const keys = path.split('.');
268
270
  let nestedObj = obj;
@@ -279,43 +281,6 @@ const accessNestedObject = function(obj, path) {
279
281
  return nestedObj;
280
282
  }
281
283
 
282
- const accessNestedSequelize = async(obj, path, opt = { defaultValue:'' }) => {
283
- if(!obj || typeof path !== 'string') return
284
-
285
- const keys = path.split('.');
286
- let value = obj;
287
-
288
- for (let i in keys) {
289
- const key = keys[i]
290
- const hasNext = i < keys.length - 1
291
-
292
- if(hasNext){
293
-
294
- if(!value[key]){
295
- try{
296
- value = await value[camelCase(`get-${key}`)]()
297
- }
298
- catch(e){}
299
- }
300
- else{
301
- value = value[key]
302
- }
303
-
304
- if(!value){
305
- return
306
- }
307
- }
308
-
309
- else{
310
- value = key in value.dataValues ?
311
- value[key] :
312
- opt.defaultValue
313
- }
314
- }
315
-
316
- return value;
317
- }
318
-
319
284
  const createObjectFromPath = (obj, path, value) => {
320
285
  const keys = path.split('.');
321
286
 
@@ -544,6 +509,7 @@ const datasourceLoad = async ({ datasource, Models }) => {
544
509
  }
545
510
 
546
511
  const dayTimeRange = (params, value) => {
512
+ const dayjs = require('dayjs')
547
513
 
548
514
  /*params = {
549
515
  '*': [ [ '08:00', '12:00' ], [ '13:00', '18:00' ] ],
@@ -564,11 +530,72 @@ const dayTimeRange = (params, value) => {
564
530
  }
565
531
 
566
532
  function capitalize(str) {
567
- return (str ?? '')
568
- .toString()
569
- .split(' ')
570
- .map(_ => _.charAt(0).toUpperCase() + _.slice(1).toLowerCase())
571
- .join(' ')
533
+ return (str ?? '').toLowerCase().replace(/\b\w/g, function(char) {
534
+ return char.toUpperCase();
535
+ });
536
+ }
537
+
538
+ const removeUnderscoredKey = (obj) => {
539
+ if (Array.isArray(obj)) {
540
+ return obj.map(removeUnderscoredKey);
541
+ }
542
+ else if (obj !== null && typeof obj === 'object') {
543
+ for(let key in obj){
544
+ if(key.startsWith('_')){
545
+ delete obj[key]
546
+ }
547
+ else if(Array.isArray(obj[key]) || (obj[key] !== null && typeof obj[key] === 'object')){
548
+ removeUnderscoredKey(obj[key])
549
+ }
550
+ }
551
+ }
552
+ return obj;
553
+ }
554
+
555
+ const hashMake = async (text) => {
556
+ const bcrypt = require('bcrypt')
557
+
558
+ return bcrypt.hash(text + (process.env.APP_KEY ?? ''), 10)
559
+ }
560
+
561
+ const hashCheck = (text, hash) => {
562
+ const bcrypt = require('bcrypt')
563
+
564
+ return bcrypt.compare(text + (process.env.APP_KEY ?? ''), hash)
565
+ }
566
+
567
+ const transactionWithRetry = async (sequelize, callback, opt = {}) => {
568
+ const { maxRetries = 99, delay = 1000 } = opt
569
+
570
+ let retries = 0
571
+ while(retries < maxRetries){
572
+ try{
573
+ return await sequelize.transaction(callback)
574
+ }
575
+ catch(e){
576
+ if(e.name === 'SequelizeConnectionAcquireTimeoutError' ||
577
+ (e.name === 'SequelizeDatabaseError' && [ 'ER_LOCK_DEADLOCK', '40001' ].includes(e.original.code))){
578
+ retries++
579
+
580
+ if(retries >= maxRetries){
581
+ throw e
582
+ }
583
+
584
+ await new Promise((resolve) => setTimeout(resolve, delay))
585
+ }
586
+
587
+ else{
588
+ throw e
589
+ }
590
+ }
591
+ }
592
+ }
593
+
594
+ const groupBy = (arr, key) => {
595
+ return arr.reduce((acc, item) => {
596
+ (acc[item[key]] = acc[item[key]] || []).push(item);
597
+ return acc;
598
+ }, {});
572
599
  }
573
600
 
574
601
  module.exports = {
@@ -591,7 +618,6 @@ module.exports = {
591
618
  getPresetSortWhereParams,
592
619
  unflatten,
593
620
  accessNestedObject,
594
- accessNestedSequelize,
595
621
  createObjectFromPath,
596
622
  generateStylesheet,
597
623
  hexToRgb,
@@ -601,4 +627,9 @@ module.exports = {
601
627
  datasourceGet,
602
628
  datasourceLoad,
603
629
  dayTimeRange,
630
+ removeUnderscoredKey,
631
+ hashMake,
632
+ hashCheck,
633
+ transactionWithRetry,
634
+ groupBy
604
635
  }
@@ -80,8 +80,7 @@ const downsizeImage = async (url, targetWidth, imageType, quality, opt = {}) =>
80
80
  }
81
81
 
82
82
  const parseBoolean = function(exp){
83
- return [ 'true', 1, true ].includes(typeof exp === 'string' ?
84
- exp.toLowerCase() : exp)
83
+ return [ 'true', '1' ].includes(`${(exp ?? '')}`.toLowerCase())
85
84
  }
86
85
 
87
86
  const strVars = function(text, vars, opt = { emptyUndefined:true }){
@@ -319,6 +318,17 @@ function unslugAndCapitalize(slug) {
319
318
  .join(' ');
320
319
  }
321
320
 
321
+ function slugify(text, separator = '-') {
322
+ return text
323
+ .toString() // Ensure the input is a string
324
+ .normalize('NFD') // Normalize to decompose diacritic marks
325
+ .replace(/[\u0300-\u036f]/g, '') // Remove diacritic marks
326
+ .replace(/[^a-zA-Z0-9\s-]/g, '') // Remove special characters
327
+ .trim() // Trim leading/trailing spaces
328
+ .replace(/\s+/g, separator) // Replace spaces with dashes
329
+ .toLowerCase(); // Convert to lowercase
330
+ }
331
+
322
332
  const hexToRgb = (hex) => {
323
333
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
324
334
  return result ? {
@@ -361,7 +371,7 @@ function applyDatasourceReplacer(value, datasource){
361
371
  }
362
372
 
363
373
  function capitalize(str) {
364
- return str.replace(/\b\w/g, function(char) {
374
+ return (str ?? '').toLowerCase().replace(/\b\w/g, function(char) {
365
375
  return char.toUpperCase();
366
376
  });
367
377
  }
@@ -372,24 +382,237 @@ const round = (num, precision = 0) => {
372
382
  return Math.round(n) / p
373
383
  }
374
384
 
375
- let invokeAfterIdleStore = []
376
- const invokeAfterIdle = (callback, delay = 1300) => {
385
+ const invokeAfterIdle = (callback, opt) => {
386
+
377
387
  let timeoutId
388
+ const { delay = 500 } = opt ?? {}
378
389
 
379
390
  return function(){
380
- if(invokeAfterIdleStore.includes(callback))
381
- return
382
-
383
- invokeAfterIdleStore.push(callback)
384
-
385
391
  window.clearTimeout(timeoutId)
386
392
  timeoutId = window.setTimeout(() => {
387
393
  callback.apply(this, arguments)
388
- invokeAfterIdleStore.splice(invokeAfterIdleStore.indexOf(callback), 1)
389
394
  }, delay)
390
395
  }
391
396
  }
392
397
 
398
+ const queueForLater = (params) => {
399
+
400
+ const instance = {
401
+ delay: 1200,
402
+ ...params,
403
+
404
+ items: [],
405
+ timeoutId: null,
406
+
407
+ run: () => {
408
+ const items = instance.items.splice(0, instance.items.length);
409
+ typeof instance.pop === 'function' ? instance.pop(items) : null;
410
+ instance.timeoutId = null
411
+ },
412
+
413
+ queue(item) {
414
+ if(Array.isArray(item))
415
+ instance.items.push(...item)
416
+ else
417
+ instance.items.push(item)
418
+
419
+ if(!instance.timeoutId)
420
+ instance.timeoutId = window.setTimeout(instance.run, instance.delay);
421
+ }
422
+ }
423
+
424
+ return instance.queue
425
+ }
426
+
427
+ const queueForLaterWithKey = (params) => {
428
+
429
+ const instance = {
430
+ delay: 1200,
431
+ ...params,
432
+
433
+ items: {},
434
+ timeoutId: {},
435
+
436
+ run: (key) => {
437
+ const items = instance.items[key].splice(0, instance.items[key].length);
438
+ //console.log('run', key, items)
439
+ typeof instance.pop === 'function' ? instance.pop(items) : null;
440
+ instance.timeoutId[key] = false
441
+ },
442
+
443
+ queue(key, item) {
444
+ if(!instance.items[key]){
445
+ instance.items[key] = []
446
+ }
447
+
448
+ if(Array.isArray(item))
449
+ instance.items[key].push(...item)
450
+ else
451
+ instance.items[key].push(item)
452
+
453
+ //console.log('queue', key, item, instance.items[key])
454
+
455
+ if(!instance.timeoutId[key])
456
+ instance.timeoutId[key] = window.setTimeout(() => instance.run(key), instance.delay);
457
+ }
458
+ }
459
+
460
+ return instance.queue
461
+ }
462
+
463
+ const transactionWithRetry = async (sequelize, callback, opt = {}) => {
464
+ const { maxRetries = 99, delay = 1000, rollback = false } = opt
465
+
466
+ let retries = 0
467
+ while(retries < maxRetries){
468
+ try{
469
+ const transaction = await sequelize.transaction()
470
+ const res = await callback(transaction)
471
+
472
+ if(rollback)
473
+ await transaction.rollback()
474
+ else
475
+ await transaction.commit()
476
+
477
+ return res
478
+ }
479
+ catch(e){
480
+ if(e.name === 'SequelizeConnectionAcquireTimeoutError' ||
481
+ (e.name === 'SequelizeDatabaseError' && [ 'ER_LOCK_DEADLOCK', '40001' ].includes(e.original.code))){
482
+ retries++
483
+
484
+ if(retries >= maxRetries){
485
+ throw e
486
+ }
487
+
488
+ await new Promise((resolve) => setTimeout(resolve, delay))
489
+ }
490
+
491
+ else{
492
+ throw e
493
+ }
494
+ }
495
+ }
496
+ }
497
+
498
+ const groupBy = (arr, key) => {
499
+ return arr.reduce((acc, item) => {
500
+ (acc[item[key]] = acc[item[key]] || []).push(item);
501
+ return acc;
502
+ }, {});
503
+ }
504
+
505
+ const arrayPush = (arr, items, opt = { update:true }) => {
506
+ if(!Array.isArray(arr)) return
507
+ if(!Array.isArray(items)) items = [ items ]
508
+ if(!opt.key){
509
+ opt.key = items[0] && items[0].uid ? 'uid' : 'id'
510
+ }
511
+
512
+ if(!Array.isArray(opt.key)){
513
+ opt.key = [ opt.key ]
514
+ }
515
+
516
+ for(let item of items){
517
+ if(!item) continue
518
+
519
+ const index = arr.findIndex((_) => {
520
+ for(let key of opt.key){
521
+ if(_[key] !== item[key]){
522
+ return false
523
+ }
524
+ }
525
+ return true
526
+ })
527
+
528
+ if(index >= 0){
529
+ if(opt.update !== false){
530
+ Object.assign(arr[index], item)
531
+ }
532
+ }
533
+ else{
534
+ arr.push(item)
535
+ }
536
+ }
537
+ }
538
+
539
+ const arrayRemove = (arr, items, opt = {}) => {
540
+ if(!Array.isArray(arr)) return
541
+ if(!Array.isArray(items)) items = [ items ]
542
+ if(!opt.key){
543
+ opt.key = items[0] && items[0].uid ? 'uid' : 'id'
544
+ }
545
+
546
+ items = groupBy(items, opt.key)
547
+
548
+ for(let i = arr.length - 1 ; i >= 0 ; i--){
549
+ if(!arr[i]) continue
550
+
551
+ if(arr[i][opt.key] in items){
552
+ arr.splice(i, 1)
553
+ }
554
+ }
555
+ }
556
+
557
+ const arrayUnshift = (arr, items, opt = { update:true }) => {
558
+ if(!Array.isArray(arr)) return
559
+ if(!Array.isArray(items)) items = [ items ]
560
+ if(!opt.key){
561
+ opt.key = items[0] && items[0].uid ? 'uid' : 'id'
562
+ }
563
+
564
+ if(!Array.isArray(opt.key)){
565
+ opt.key = [ opt.key ]
566
+ }
567
+
568
+ for(let item of items){
569
+ if(!item) continue
570
+
571
+ const index = arr.findIndex((_) => {
572
+ for(let key of opt.key){
573
+ if(_[key] !== item[key]){
574
+ return false
575
+ }
576
+ }
577
+ return true
578
+ })
579
+
580
+ if(index >= 0){
581
+ if(opt.update !== false){
582
+ Object.assign(arr[index], item)
583
+ }
584
+ }
585
+ else{
586
+ arr.unshift(item)
587
+ }
588
+ }
589
+ }
590
+
591
+ function addHash(hash, newHash, prefix = '_'){
592
+ const cleaned = hash.split('#')
593
+ .filter(_=>_).map(_ => `#${_}`)
594
+ .filter(_ => !_.startsWith(prefix))
595
+
596
+ cleaned.push(newHash)
597
+
598
+ return cleaned.join('')
599
+ }
600
+
601
+ const downloadUrl = (url, as) => {
602
+ url = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'nocache=' + new Date().getTime()
603
+
604
+ const downloader = document.createElement('a')
605
+ downloader.setAttribute('href', url)
606
+ downloader.target = '_blank'
607
+ if(as) downloader.download = as
608
+ document.body.appendChild(downloader)
609
+
610
+ downloader.click()
611
+
612
+ window.setTimeout(() => {
613
+ document.body.removeChild(downloader)
614
+ }, 100)
615
+ }
393
616
 
394
617
  export {
395
618
  capitalize,
@@ -414,9 +637,19 @@ export {
414
637
  removeStyleFromTag,
415
638
  createFormData,
416
639
  unslugAndCapitalize,
640
+ slugify,
417
641
  applyDatasourceReplacer,
418
642
  strVars,
419
- invokeAfterIdle
643
+ invokeAfterIdle,
644
+ queueForLater,
645
+ queueForLaterWithKey,
646
+ transactionWithRetry,
647
+ groupBy,
648
+ arrayPush,
649
+ arrayRemove,
650
+ arrayUnshift,
651
+ addHash,
652
+ downloadUrl
420
653
  }
421
654
 
422
655
  function observeInit(){
@@ -5,6 +5,27 @@ const glob = require("glob");
5
5
  const Exceljs = require("exceljs")
6
6
  const { saveBuffer, unflatten } = require('./helpers.js')
7
7
 
8
+ const getCellText = (cell) => {
9
+ if(!cell) return ''
10
+
11
+ let value = ''
12
+ if(cell.formulaType === 1){
13
+ value = cell.result
14
+ }
15
+ else if(cell.value?.error){
16
+ value = '#ERR'
17
+ }
18
+ else if(cell.value?.hyperlink){
19
+ value = cell.value.hyperlink
20
+ }
21
+ else{
22
+ value = cell.value
23
+ }
24
+
25
+ return value
26
+
27
+ }
28
+
8
29
  const analyseRequest = async(req) => {
9
30
 
10
31
  const file = req.files[0]
@@ -161,9 +182,7 @@ const importRequest = async(req) => {
161
182
  const key = keys[idx]
162
183
  if(key.value && columnAddress[key.value]){
163
184
  const cell = row.getCell(columnAddress[key.value])
164
- let value = cell.formulaType === 1 ? cell.result : cell.value
165
- if(value && value.error) value = ''
166
- obj[key.key] = value
185
+ obj[key.key] = getCellText(cell)
167
186
  }
168
187
  }
169
188