@mixd-id/web-scaffold 0.2.240706 → 0.2.250801010
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/components/Dashboard.md +56 -0
- package/log.txt +7 -0
- package/package.json +27 -19
- package/src/components/404.vue +61 -0
- package/src/components/AccountIcon.vue +19 -0
- package/src/components/Ahref.vue +1 -1
- package/src/components/Alert.vue +4 -13
- package/src/components/ArrayList.vue +49 -0
- package/src/components/Article.vue +24 -30
- package/src/components/Button.vue +83 -169
- package/src/components/Card.vue +257 -0
- package/src/components/Carousel.vue +61 -60
- package/src/components/Cart.vue +192 -0
- package/src/components/CartIcon.vue +89 -0
- package/src/components/ChartBar.vue +2 -3
- package/src/components/Checkbox.vue +20 -11
- package/src/components/Checkout.vue +373 -0
- package/src/components/CheckoutDelivery.vue +267 -0
- package/src/components/CodeEditor.vue +5 -16
- package/src/components/CollapsiblePanel.vue +70 -0
- package/src/components/ColorPicker.vue +12 -5
- package/src/components/ColorPicker2.vue +41 -19
- package/src/components/ColorPicker3.vue +100 -0
- package/src/components/Confirm.vue +9 -7
- package/src/components/ContextMenu.vue +122 -206
- package/src/components/ContextMenuItem.vue +53 -0
- package/src/components/Dashboard.vue +243 -0
- package/src/components/Dashboard2.vue +118 -0
- package/src/components/DashboardComponentSelector.vue +96 -0
- package/src/components/DashboardConfigs.vue +202 -0
- package/src/components/Datepicker.vue +102 -41
- package/src/components/DayTimeRange.vue +3 -2
- package/src/components/Dropdown.vue +7 -4
- package/src/components/Flex.vue +14 -40
- package/src/components/GHeatMaps.vue +2 -2
- package/src/components/Grid.vue +6 -6
- package/src/components/HTMLEditor.vue +27 -14
- package/src/components/Image.vue +62 -108
- package/src/components/ImagePreview.vue +14 -4
- package/src/components/ImageUploader.vue +114 -0
- package/src/components/ImportModal.vue +3 -3
- package/src/components/Link.vue +62 -6
- package/src/components/List.vue +528 -403
- package/src/components/ListContextMenu.vue +88 -0
- package/src/components/ListItem.vue +6 -4
- package/src/components/ListPage1.vue +14 -15
- package/src/components/ListView.vue +5 -6
- package/src/components/ListViewSettings.vue +2 -2
- package/src/components/LogViewerItem.vue +1 -1
- package/src/components/MarkdownEdit.vue +128 -0
- package/src/components/MarkdownPreview.vue +102 -0
- package/src/components/MenuItem1.vue +36 -0
- package/src/components/Modal.vue +95 -43
- package/src/components/MultiDropdown.vue +124 -0
- package/src/components/MultilineText.vue +1 -4
- package/src/components/OTPField.vue +40 -26
- package/src/components/ObjectTree.vue +1 -1
- package/src/components/PageBuilder.vue +3 -3
- package/src/components/Paragraph.vue +1 -2
- package/src/components/PresetSelectorFilterItem.vue +107 -95
- package/src/components/Radio.vue +1 -1
- package/src/components/SearchModal.vue +153 -0
- package/src/components/Slider.vue +1 -1
- package/src/components/Svg.vue +1 -1
- package/src/components/SvgEditor.vue +173 -0
- package/src/components/Switch.vue +4 -5
- package/src/components/Table.vue +2 -2
- package/src/components/TableView.vue +2 -3
- package/src/components/TableViewHead.vue +2 -2
- package/src/components/Tabs.vue +1 -1
- package/src/components/Testimonial.vue +2 -2
- package/src/components/Text.vue +7 -22
- package/src/components/TextEditor.vue +3 -3
- package/src/components/TextWithTag.vue +61 -30
- package/src/components/Textarea.vue +16 -22
- package/src/components/Textbox.vue +9 -19
- package/src/components/Timepicker.vue +25 -15
- package/src/components/Toast.vue +5 -3
- package/src/components/TreeMenu.vue +122 -0
- package/src/components/TreeView.vue +15 -10
- package/src/components/TreeView2.vue +38 -0
- package/src/components/TreeViewItem.vue +58 -29
- package/src/components/TreeViewItem2.vue +55 -0
- package/src/components/Uploader.vue +45 -0
- package/src/components/Video.vue +119 -0
- package/src/components/VirtualGrid.vue +24 -7
- package/src/components/VirtualTable.vue +363 -128
- package/src/configs/dashboard/data-table.js +9 -0
- package/src/configs/web-page-builder.js +118 -0
- package/src/directives/intersect.js +26 -0
- package/src/hooks/device.js +14 -0
- package/src/index.js +62 -107
- package/src/mixin/component.js +151 -67
- package/src/themes/default/index.js +118 -159
- package/src/utils/dashboard.js +22 -962
- package/src/utils/helpers.cjs +635 -0
- package/src/utils/helpers.js +91 -60
- package/src/utils/helpers.mjs +245 -12
- package/src/utils/importer.js +22 -3
- package/src/utils/list.mjs +1509 -0
- package/src/utils/preset-selector.cjs +1455 -0
- package/src/utils/preset-selector.js +489 -95
- package/src/utils/preset-selector.mjs +59 -20
- package/src/utils/queue.js +63 -0
- package/src/utils/web.mjs +120 -0
- package/src/utils/wss.js +38 -36
- package/src/utils/wss.mjs +24 -19
- package/src/widgets/AhrefSetting.vue +16 -13
- package/src/widgets/ArticleSetting.vue +15 -27
- package/src/widgets/BackgroundColorSetting.vue +153 -0
- package/src/widgets/BorderColorSetting.vue +57 -0
- package/src/widgets/BotEditor/BotEditorActions.vue +3 -2
- package/src/widgets/BotEditor/BotEditorSettings.vue +21 -0
- package/src/widgets/BotEditor.vue +35 -15
- package/src/widgets/ButtonSetting.vue +12 -13
- package/src/widgets/CarouselSetting.vue +33 -45
- package/src/widgets/CartSetting.vue +46 -0
- package/src/widgets/CheckoutSetting.vue +46 -0
- package/src/widgets/CollapsiblePanelSetting.vue +46 -0
- package/src/widgets/ColumnSelector.vue +29 -5
- package/src/widgets/ComponentSetting.vue +1 -1
- package/src/widgets/ComponentSetting2.vue +145 -236
- package/src/widgets/ComponentSetting3.vue +1 -1
- package/src/widgets/ContactForm.vue +3 -3
- package/src/widgets/ContactFormSetting.vue +41 -30
- package/src/widgets/Dashboard/BarChart.vue +47 -11
- package/src/widgets/Dashboard/BarChartSetting.vue +1 -1
- package/src/widgets/Dashboard/DataTable.vue +125 -0
- package/src/widgets/Dashboard/DataTableSetting.vue +243 -0
- package/src/widgets/Dashboard/DatasourceSelector.vue +1 -1
- package/src/widgets/Dashboard/Doughnut.vue +49 -7
- package/src/widgets/Dashboard/DoughnutSetting.vue +2 -2
- package/src/widgets/Dashboard/Metric.vue +78 -19
- package/src/widgets/Dashboard/MetricSetting.vue +81 -28
- package/src/widgets/Dashboard/Pie.vue +55 -6
- package/src/widgets/Dashboard/PieSetting.vue +1 -1
- package/src/widgets/Dashboard/PolarArea.vue +49 -7
- package/src/widgets/Dashboard/PolarAreaSetting.vue +1 -1
- package/src/widgets/Dashboard/SharingModal.vue +4 -5
- package/src/widgets/Dashboard/ViewSelector.vue +2 -2
- package/src/widgets/Dashboard/VirtualTableSetting.vue +121 -184
- package/src/widgets/{Dashboard.vue → Dashboard0.vue} +426 -343
- package/src/widgets/EmbeddedVideoSetting.vue +7 -5
- package/src/widgets/FAQ.vue +16 -3
- package/src/widgets/FAQSetting.vue +53 -47
- package/src/widgets/FeatureList.vue +3 -0
- package/src/widgets/FeatureListSetting.vue +112 -102
- package/src/widgets/FlexSetting.vue +83 -106
- package/src/widgets/GridSetting.vue +71 -196
- package/src/widgets/Header2.vue +34 -71
- package/src/widgets/Header2Setting.vue +95 -179
- package/src/widgets/HeaderSetting.vue +16 -18
- package/src/widgets/IconListSetting.vue +69 -65
- package/src/widgets/ImageSetting.vue +33 -60
- package/src/widgets/LinkSetting.vue +60 -37
- package/src/widgets/LinkSettingModal.vue +173 -0
- package/src/widgets/LogViewer.vue +1 -1
- package/src/widgets/MarginSetting.vue +2 -2
- package/src/widgets/MenuEditor.vue +1 -1
- package/src/widgets/MenuItem1Setting.vue +78 -0
- package/src/widgets/ModalSetting.vue +42 -44
- package/src/widgets/MultiValueSetting.vue +2 -2
- package/src/widgets/MultiValueSetting2.vue +78 -45
- package/src/widgets/OGSettingModal.vue +103 -0
- package/src/widgets/PaddingSetting.vue +2 -2
- package/src/widgets/ParagraphSetting.vue +16 -13
- package/src/widgets/PositionSetting.vue +209 -0
- package/src/widgets/PresetBar.vue +359 -210
- package/src/widgets/PresetBarPivot.vue +31 -19
- package/src/widgets/PresetSelector.vue +29 -17
- package/src/widgets/SearchModalSetting.vue +70 -0
- package/src/widgets/Share.vue +1 -2
- package/src/widgets/ShareSetting.vue +67 -60
- package/src/widgets/StyleSetting.vue +365 -150
- package/src/widgets/TestimonialSetting.vue +97 -88
- package/src/widgets/TextBlockSetting.vue +16 -13
- package/src/widgets/UserActionBuilder/UserActionConsole.vue +30 -10
- package/src/widgets/UserActionBuilder/UserActionOutput.vue +2 -2
- package/src/widgets/UserActionBuilder/UserActionOutputReply.vue +64 -87
- package/src/widgets/UserActionBuilder/UserActionProps.vue +3 -3
- package/src/widgets/UserActionBuilder.vue +4 -16
- package/src/widgets/WebComponentSelector.vue +15 -11
- package/src/widgets/WebLayoutSelector.vue +41 -270
- package/src/widgets/WebPageBuilder.vue +1019 -707
- package/src/widgets/WebPageBuilder2.vue +7 -7
- package/src/widgets/WebPageBuilder4/ButtonSetting.vue +0 -8
- package/src/widgets/WebPageBuilder4/CarouselSetting.vue +63 -7
- package/src/widgets/WebPageBuilder4/FlexAlignSetting.vue +3 -3
- package/src/widgets/WebPageBuilder4/FlexSetting.vue +1 -10
- package/src/widgets/WebPageBuilder4/MultiValueSetting.vue +2 -2
- package/src/widgets/WebPageBuilder4/PropertySetting.vue +0 -7
- package/src/widgets/WebPageBuilder4/WebPageComponentSelector.vue +1 -7
- package/src/widgets/WebPageBuilder4.vue +289 -575
- package/src/widgets/WebPageSelector.vue +1 -1
- package/src/widgets/YoutubeVideoSetting.vue +16 -13
- package/tailwind.config.js +3 -35
- package/docs/schema/user-action.json +0 -266
- package/src/App.vue +0 -25
- package/src/components/SearchButton.vue +0 -57
- package/src/entry-client.js +0 -27
- package/src/entry-server.js +0 -73
- package/src/events/event.js +0 -2
- package/src/main.js +0 -29
- package/src/mixin/website.js +0 -121
- package/src/router.js +0 -57
- package/src/widgets/MobileMenu.vue +0 -182
- package/src/widgets/WebPageBuilder4/ActionSetting.vue +0 -158
- package/src/widgets/WebPageBuilder4/ColorSetting.vue +0 -63
- package/src/widgets/WebPageBuilder4/DataSetting.vue +0 -92
- package/src/widgets/WebPageBuilder4/FontSizeSetting.vue +0 -76
- package/src/widgets/WebPageBuilder4/LinkSetting.vue +0 -68
- package/src/widgets/WebPageBuilder4/MobileMenuSetting.vue +0 -106
- package/src/widgets/WebPageBuilder4/Setting.vue +0 -73
- package/src/widgets/WebPageBuilder4/StyleSetting.vue +0 -77
- package/src/widgets/WebPageBuilder4/SvgSetting.vue +0 -207
- package/src/widgets/WebPageBuilder4/TextTransformSetting.vue +0 -70
- package/src/widgets/WebPageBuilder4/WebPageDataEdit.vue +0 -121
- package/test.json +0 -22
- /package/src/widgets/{Header1.vue → Header0.vue} +0 -0
- /package/src/widgets/{Header1Setting.vue → Header0Setting.vue} +0 -0
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
const ceil = (num, precision = 0) => {
|
|
2
|
+
var p = Math.pow(10, precision)
|
|
3
|
+
var n = (num * p) * (1 + Number.EPSILON)
|
|
4
|
+
return Math.ceil(n) / p
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const floor = (num, precision = 0) => {
|
|
8
|
+
var p = Math.pow(10, precision)
|
|
9
|
+
var n = (num * p) * (1 + Number.EPSILON)
|
|
10
|
+
return Math.floor(n) / p
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ftWildcard = (key) => {
|
|
14
|
+
if(key.indexOf('/') >= 0) return key
|
|
15
|
+
|
|
16
|
+
const term = key.replace(/[\-\+\*\<\>\@\(\)\~]/, ' ', 'gi')
|
|
17
|
+
|
|
18
|
+
const searchTerms = []
|
|
19
|
+
term.split(' ').forEach((txt) => {
|
|
20
|
+
if(txt.length >= 3){
|
|
21
|
+
searchTerms.push(`+${txt}*`)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
return searchTerms.join(' ')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const moveFile = function(oldPath, newPath, callback) {
|
|
28
|
+
const fs = require("fs");
|
|
29
|
+
|
|
30
|
+
fs.rename(oldPath, newPath, function (err) {
|
|
31
|
+
if (err) {
|
|
32
|
+
if (err.code === 'EXDEV') {
|
|
33
|
+
copy();
|
|
34
|
+
} else {
|
|
35
|
+
callback(err);
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
callback();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
function copy() {
|
|
43
|
+
const fs = require("fs");
|
|
44
|
+
|
|
45
|
+
var readStream = fs.createReadStream(oldPath);
|
|
46
|
+
var writeStream = fs.createWriteStream(newPath);
|
|
47
|
+
|
|
48
|
+
readStream.on('error', callback);
|
|
49
|
+
writeStream.on('error', callback);
|
|
50
|
+
|
|
51
|
+
readStream.on('close', function () {
|
|
52
|
+
fs.unlink(oldPath, callback);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
readStream.pipe(writeStream);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const round = (num, precision = 0) => {
|
|
60
|
+
var p = Math.pow(10, precision)
|
|
61
|
+
var n = (num * p) * (1 + Number.EPSILON)
|
|
62
|
+
return Math.round(n) / p
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const sanitizeMobileNumber = (mobileNumber) => {
|
|
66
|
+
if(typeof mobileNumber !== 'string') return mobileNumber
|
|
67
|
+
|
|
68
|
+
if(mobileNumber.length > 0){
|
|
69
|
+
mobileNumber = mobileNumber.replace(/[\- ]/g, '')
|
|
70
|
+
if(mobileNumber.substring(0, 1) === '0') mobileNumber = '+62' + mobileNumber.substring(1)
|
|
71
|
+
if(mobileNumber.substring(0, 1) !== '+'){
|
|
72
|
+
if(mobileNumber.substring(0, 2) === '62')
|
|
73
|
+
mobileNumber = '+' + mobileNumber
|
|
74
|
+
else
|
|
75
|
+
mobileNumber = '+62' + mobileNumber
|
|
76
|
+
}
|
|
77
|
+
if(mobileNumber.length > 0){
|
|
78
|
+
mobileNumber = mobileNumber[0] + mobileNumber.slice(1).replace(/\D/g, '')
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return mobileNumber
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const saveBase64 = async(data, dir = '/storage/files/images') => {
|
|
86
|
+
if(data.indexOf(',') >= 0){
|
|
87
|
+
data = data.substring(data.indexOf(',') + 1)
|
|
88
|
+
}
|
|
89
|
+
const buffer = Buffer.from(data, 'base64');
|
|
90
|
+
return await saveBuffer(buffer, dir)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const saveBuffer = async(buffer, dir = '/storage/files/images') => {
|
|
94
|
+
|
|
95
|
+
const fs = require("fs");
|
|
96
|
+
const md5 = require('md5')
|
|
97
|
+
|
|
98
|
+
const { fileTypeFromBuffer } = await import('file-type')
|
|
99
|
+
|
|
100
|
+
const type = await fileTypeFromBuffer(buffer)
|
|
101
|
+
|
|
102
|
+
const storagePath = process.env.ROOT_PATH + dir
|
|
103
|
+
const ext = type && type.ext ? '.' + type.ext : ''
|
|
104
|
+
const filename = md5(buffer) + ext
|
|
105
|
+
const to = storagePath + '/' + filename
|
|
106
|
+
|
|
107
|
+
fs.writeFileSync(to, buffer)
|
|
108
|
+
|
|
109
|
+
return filename
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const saveFromUrl = async(url, dir = '/storage/files/images') => {
|
|
113
|
+
const axios = require('axios')
|
|
114
|
+
|
|
115
|
+
const res = await axios({
|
|
116
|
+
method: 'GET',
|
|
117
|
+
url,
|
|
118
|
+
responseType: 'arraybuffer',
|
|
119
|
+
})
|
|
120
|
+
const buffer = Buffer.from(res.data)
|
|
121
|
+
return await saveBuffer(buffer, dir)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const sleep = ms => new Promise(r => setTimeout(r, ms))
|
|
125
|
+
|
|
126
|
+
const strSlug = (title, separator) => {
|
|
127
|
+
if (typeof separator == 'undefined') separator = '-';
|
|
128
|
+
|
|
129
|
+
// Convert all dashes/underscores into separator
|
|
130
|
+
var flip = separator === '-' ? '_' : '-';
|
|
131
|
+
title = title.replace(flip, separator);
|
|
132
|
+
|
|
133
|
+
// Remove all characters that are not the separator, letters, numbers, or whitespace.
|
|
134
|
+
title = title.toLowerCase()
|
|
135
|
+
.replace(new RegExp('[^a-z0-9' + separator + '\\s]', 'g'), '');
|
|
136
|
+
|
|
137
|
+
// Replace all separator characters and whitespace by a single separator
|
|
138
|
+
title = title.replace(new RegExp('[' + separator + '\\s]+', 'g'), separator);
|
|
139
|
+
|
|
140
|
+
return title.replace(new RegExp('^[' + separator + '\\s]+|[' + separator + '\\s]+$', 'g'),'');
|
|
141
|
+
}
|
|
142
|
+
|
|
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
|
+
})
|
|
150
|
+
|
|
151
|
+
return text
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const writeStorage = (path, content, append = false) => {
|
|
155
|
+
|
|
156
|
+
const fs = require("fs");
|
|
157
|
+
|
|
158
|
+
if(path.startsWith('/')) path = path.substring(1)
|
|
159
|
+
|
|
160
|
+
if(append){
|
|
161
|
+
fs.appendFileSync(process.env.ROOT_PATH + `/storage/${path}`, content)
|
|
162
|
+
}
|
|
163
|
+
else{
|
|
164
|
+
fs.writeFileSync(process.env.ROOT_PATH + `/storage/${path}`, content)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const bufferToStream = (buffer) => {
|
|
169
|
+
const { Duplex } = require('stream')
|
|
170
|
+
let stream = new Duplex()
|
|
171
|
+
stream.push(buffer)
|
|
172
|
+
stream.push(null)
|
|
173
|
+
return stream
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const sequelizeChunk = async (model, opt, callback, chunkSize = 5000) => {
|
|
177
|
+
|
|
178
|
+
let offset = 0
|
|
179
|
+
let iter = 0
|
|
180
|
+
while(true){
|
|
181
|
+
const items = await model.findAll({
|
|
182
|
+
...opt,
|
|
183
|
+
offset,
|
|
184
|
+
limit: chunkSize
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
if(items.length > 0){
|
|
188
|
+
await callback(items, iter)
|
|
189
|
+
offset += chunkSize
|
|
190
|
+
iter++
|
|
191
|
+
}
|
|
192
|
+
else{
|
|
193
|
+
break
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const getPresetSortWhereParams = (order, afterItem) => {
|
|
199
|
+
|
|
200
|
+
const { Op } = require('sequelize')
|
|
201
|
+
|
|
202
|
+
if(order.filter((_) => _[0] === 'id').length <= 0){
|
|
203
|
+
order.push([ 'id', 'desc' ])
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const opOr = []
|
|
207
|
+
for(let i = 0 ; i < order.length ; i++){
|
|
208
|
+
|
|
209
|
+
const obj = order[i]
|
|
210
|
+
|
|
211
|
+
if(obj.length !== 2) continue
|
|
212
|
+
|
|
213
|
+
const exp = {}
|
|
214
|
+
for(let j = 0 ; j < i ; j++){
|
|
215
|
+
exp[order[j][0]] = afterItem[order[j][0]]
|
|
216
|
+
}
|
|
217
|
+
exp[obj[0]] = obj[1] === 'desc' ? { [Op.lt]:afterItem[obj[0]] } : { [Op.gt]:afterItem[obj[0]] }
|
|
218
|
+
|
|
219
|
+
if(Object.keys(exp).length === 1){
|
|
220
|
+
opOr.push(exp)
|
|
221
|
+
}
|
|
222
|
+
else{
|
|
223
|
+
opOr.push({
|
|
224
|
+
[Op.and]: exp
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
let sortWhere = {}
|
|
230
|
+
if(opOr.length > 0){
|
|
231
|
+
sortWhere = {
|
|
232
|
+
[Op.or]: opOr
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return sortWhere
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const unflatten = (flatObject) => {
|
|
239
|
+
const nestedObject = {};
|
|
240
|
+
|
|
241
|
+
for (const key in flatObject) {
|
|
242
|
+
if (Object.prototype.hasOwnProperty.call(flatObject, key)) {
|
|
243
|
+
const value = flatObject[key];
|
|
244
|
+
const keys = key.split('.');
|
|
245
|
+
|
|
246
|
+
let currentObj = nestedObject;
|
|
247
|
+
for (let i = 0; i < keys.length; i++) {
|
|
248
|
+
const currentKey = keys[i];
|
|
249
|
+
|
|
250
|
+
if (!currentObj[currentKey]) {
|
|
251
|
+
currentObj[currentKey] = {};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (i === keys.length - 1) {
|
|
255
|
+
currentObj[currentKey] = value;
|
|
256
|
+
} else {
|
|
257
|
+
currentObj = currentObj[currentKey];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return nestedObject;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const accessNestedObject = function(obj, path) {
|
|
267
|
+
if(!obj || typeof path !== 'string') return undefined
|
|
268
|
+
|
|
269
|
+
const keys = path.split('.');
|
|
270
|
+
let nestedObj = obj;
|
|
271
|
+
|
|
272
|
+
for (let key of keys) {
|
|
273
|
+
if (nestedObj && nestedObj.hasOwnProperty(key)) {
|
|
274
|
+
nestedObj = nestedObj[key];
|
|
275
|
+
} else {
|
|
276
|
+
// Return undefined if any key in the path is missing
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return nestedObj;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const createObjectFromPath = (obj, path, value) => {
|
|
285
|
+
const keys = path.split('.');
|
|
286
|
+
|
|
287
|
+
let current = obj;
|
|
288
|
+
for (let i = 0; i < keys.length; i++) {
|
|
289
|
+
const key = keys[i];
|
|
290
|
+
const indexMatch = key.match(/^(\d+)$/);
|
|
291
|
+
const isArrayIndex = indexMatch !== null;
|
|
292
|
+
|
|
293
|
+
const nextIsArrayIndex = !!(keys[i + 1] ?? '').match(/^(\d+)$/);
|
|
294
|
+
const isLast = i === keys.length - 1
|
|
295
|
+
|
|
296
|
+
if(isArrayIndex) {
|
|
297
|
+
const index = parseInt(indexMatch[1], 10);
|
|
298
|
+
if (!Array.isArray(current)) {
|
|
299
|
+
current = [];
|
|
300
|
+
}
|
|
301
|
+
if (typeof current[index] === 'undefined') {
|
|
302
|
+
current[index] = isLast ? value : nextIsArrayIndex ? [] : {};
|
|
303
|
+
}
|
|
304
|
+
current = current[index]
|
|
305
|
+
}
|
|
306
|
+
else{
|
|
307
|
+
if(typeof current[key] !== 'object' || current[key] === null) {
|
|
308
|
+
current[key] = isLast ? value : nextIsArrayIndex ? [] : {};
|
|
309
|
+
}
|
|
310
|
+
current = current[key];
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return obj;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const cssDict = {
|
|
318
|
+
'Global': '*',
|
|
319
|
+
'Font': 'font-family',
|
|
320
|
+
'Impact': "'Impact', 'Arial Black', 'Arial Bold', Gadget, sans-serif",
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const generateStylesheet = (styleObj) => {
|
|
324
|
+
|
|
325
|
+
return `*{ font-family: Impact; }`
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const hexToRgb = (hex) => {
|
|
330
|
+
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
331
|
+
return result ? {
|
|
332
|
+
r: parseInt(result[1], 16),
|
|
333
|
+
g: parseInt(result[2], 16),
|
|
334
|
+
b: parseInt(result[3], 16)
|
|
335
|
+
} : null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const compClasses = [
|
|
339
|
+
'aspectRatio',
|
|
340
|
+
'bdSize', 'bdColor', 'bdRadius', 'bdStyle',
|
|
341
|
+
'bgColors', 'bgSize', 'bgPosition', 'bgRepeat',
|
|
342
|
+
'gap',
|
|
343
|
+
'padding', 'margin',
|
|
344
|
+
'direction', 'columns', 'display',
|
|
345
|
+
'width', 'minWidth', 'maxWidth',
|
|
346
|
+
'height', 'minHeight', 'maxHeight',
|
|
347
|
+
'fontFamily', 'fontSize', 'fontWeight', 'textColor', 'lineHeight', 'overflow',
|
|
348
|
+
'boxShadow', 'opacity',
|
|
349
|
+
'colSpan'
|
|
350
|
+
]
|
|
351
|
+
|
|
352
|
+
const containerClasses = [
|
|
353
|
+
'containerVariant', 'containerGridColumn', 'containerGap'
|
|
354
|
+
]
|
|
355
|
+
|
|
356
|
+
const itemClasses = [
|
|
357
|
+
'itemMinWidth', 'itemRatio', 'itemVariant'
|
|
358
|
+
]
|
|
359
|
+
|
|
360
|
+
const createComponentInstance = function(component){
|
|
361
|
+
|
|
362
|
+
if(!component.instance)
|
|
363
|
+
component.instance = {}
|
|
364
|
+
|
|
365
|
+
const compUid = '_' + component.uid.substring(0, 4) + ' '
|
|
366
|
+
|
|
367
|
+
Object.assign(component.instance, {
|
|
368
|
+
type: component.type,
|
|
369
|
+
uid: component.uid,
|
|
370
|
+
|
|
371
|
+
class: compUid + compClasses.map(key => {
|
|
372
|
+
return Array.isArray(component.props[key]) ? component.props[key].join(' ') : ''
|
|
373
|
+
})
|
|
374
|
+
.filter(_ => _)
|
|
375
|
+
.join(' '),
|
|
376
|
+
|
|
377
|
+
containerClass: containerClasses.map(key => {
|
|
378
|
+
return Array.isArray(component.props[key]) ? component.props[key].join(' ') : ''
|
|
379
|
+
})
|
|
380
|
+
.filter(_ => _)
|
|
381
|
+
.join(' '),
|
|
382
|
+
|
|
383
|
+
itemClass: itemClasses.map(key => {
|
|
384
|
+
return Array.isArray(component.props[key]) ? component.props[key].join(' ') : ''
|
|
385
|
+
})
|
|
386
|
+
.filter(_ => _)
|
|
387
|
+
.join(' ')
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
for(let key in component.props){
|
|
391
|
+
if(!compClasses.includes(key) && ![ 'enabled' ].includes(key)){
|
|
392
|
+
component.instance[key] = component.props[key]
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if(Array.isArray(component.items)){
|
|
397
|
+
component.instance.items = component.items.map((_) => createComponentInstance(_))
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if(component.props && Array.isArray(component.props.items)){
|
|
401
|
+
component.instance.items = component.props.items
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return component
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const deepObjectContainsObject = (outerObject, innerObject) => {
|
|
408
|
+
for (const key in innerObject) {
|
|
409
|
+
if (innerObject.hasOwnProperty(key)) {
|
|
410
|
+
if (typeof innerObject[key] === 'object' && typeof outerObject[key] === 'object') {
|
|
411
|
+
// If both properties are objects, recursively check them
|
|
412
|
+
if (!deepObjectContainsObject(outerObject[key], innerObject[key])) {
|
|
413
|
+
return false; // Nested objects do not match
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
if (outerObject[key] !== innerObject[key]) {
|
|
417
|
+
return false; // Property in innerObject doesn't exist in outerObject or values don't match
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return true; // All properties and values in innerObject exist in outerObject
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const removeStyleFromTag = (html) => {
|
|
426
|
+
const regex = /<[^>]+style="[^"]*"[^>]*>/g;
|
|
427
|
+
|
|
428
|
+
return html.replace(regex, (match) => {
|
|
429
|
+
return match.replace(/style="[^"]*"/, '');
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const datasourceGet = async ({ Models }) => {
|
|
434
|
+
|
|
435
|
+
const models = []
|
|
436
|
+
for(let key in Models){
|
|
437
|
+
|
|
438
|
+
const columns = []
|
|
439
|
+
const attributes = Models[key].getAttributes()
|
|
440
|
+
for(let key in attributes){
|
|
441
|
+
|
|
442
|
+
let type
|
|
443
|
+
const fieldType = attributes[key].type.toString()
|
|
444
|
+
|
|
445
|
+
if(fieldType.startsWith('VARCHAR')){
|
|
446
|
+
type = 'string'
|
|
447
|
+
}
|
|
448
|
+
else if(fieldType.startsWith('INTEGER') || fieldType.startsWith('TINYINT')){
|
|
449
|
+
type = 'number'
|
|
450
|
+
}
|
|
451
|
+
else if(fieldType.startsWith('DATETIME')){
|
|
452
|
+
type = 'date'
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if(type){
|
|
456
|
+
columns.push({
|
|
457
|
+
name: attributes[key].fieldName,
|
|
458
|
+
type,
|
|
459
|
+
})
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
models.push({
|
|
464
|
+
name: key,
|
|
465
|
+
columns
|
|
466
|
+
})
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return {
|
|
470
|
+
models
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const datasourceLoad = async ({ datasource, Models }) => {
|
|
476
|
+
|
|
477
|
+
const obj = {}
|
|
478
|
+
|
|
479
|
+
if(Array.isArray(datasource)){
|
|
480
|
+
for(let _datasource of datasource){
|
|
481
|
+
|
|
482
|
+
const Model = Models[_datasource.model]
|
|
483
|
+
|
|
484
|
+
const where = {}
|
|
485
|
+
if(Array.isArray(_datasource.filters)){
|
|
486
|
+
for(let filter of _datasource.filters){
|
|
487
|
+
|
|
488
|
+
switch(filter.operator){
|
|
489
|
+
|
|
490
|
+
case '=':
|
|
491
|
+
where[filter.key] = filter.value
|
|
492
|
+
break
|
|
493
|
+
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const rows = await Model.findAll({
|
|
499
|
+
where,
|
|
500
|
+
limit: 20
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
obj[_datasource.key] = rows.length === 1 ? rows[0].toJSON() :
|
|
504
|
+
(rows.length === 0 ? {} : rows.map(_ => _.toJSON()))
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return obj
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const dayTimeRange = (params, value) => {
|
|
512
|
+
const dayjs = require('dayjs')
|
|
513
|
+
|
|
514
|
+
/*params = {
|
|
515
|
+
'*': [ [ '08:00', '12:00' ], [ '13:00', '18:00' ] ],
|
|
516
|
+
'sat': [ [ '08:00', '12:00' ], [ '13:00', '14:00' ] ],
|
|
517
|
+
}
|
|
518
|
+
value = '2023-02-06 17:59:00'*/
|
|
519
|
+
|
|
520
|
+
if(!value)
|
|
521
|
+
value = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
522
|
+
|
|
523
|
+
const curDay = dayjs(value).format('ddd').toLowerCase()
|
|
524
|
+
const curTime = dayjs(value).format('HH:mm')
|
|
525
|
+
const ranges = params[curDay] ?? params['*']
|
|
526
|
+
|
|
527
|
+
return (ranges ?? []).some((range) => {
|
|
528
|
+
return curTime >= range[0] && curTime <= range[1]
|
|
529
|
+
})
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function capitalize(str) {
|
|
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
|
+
}, {});
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
module.exports = {
|
|
602
|
+
capitalize,
|
|
603
|
+
ceil,
|
|
604
|
+
floor,
|
|
605
|
+
ftWildcard,
|
|
606
|
+
moveFile,
|
|
607
|
+
round,
|
|
608
|
+
sanitizeMobileNumber,
|
|
609
|
+
saveBase64,
|
|
610
|
+
saveBuffer,
|
|
611
|
+
saveFromUrl,
|
|
612
|
+
sleep,
|
|
613
|
+
strSlug,
|
|
614
|
+
strVars,
|
|
615
|
+
writeStorage,
|
|
616
|
+
bufferToStream,
|
|
617
|
+
sequelizeChunk,
|
|
618
|
+
getPresetSortWhereParams,
|
|
619
|
+
unflatten,
|
|
620
|
+
accessNestedObject,
|
|
621
|
+
createObjectFromPath,
|
|
622
|
+
generateStylesheet,
|
|
623
|
+
hexToRgb,
|
|
624
|
+
createComponentInstance,
|
|
625
|
+
deepObjectContainsObject,
|
|
626
|
+
removeStyleFromTag,
|
|
627
|
+
datasourceGet,
|
|
628
|
+
datasourceLoad,
|
|
629
|
+
dayTimeRange,
|
|
630
|
+
removeUnderscoredKey,
|
|
631
|
+
hashMake,
|
|
632
|
+
hashCheck,
|
|
633
|
+
transactionWithRetry,
|
|
634
|
+
groupBy
|
|
635
|
+
}
|