mango-cms 0.1.15 → 0.1.17

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 (57) hide show
  1. package/cli.js +1 -1
  2. package/index.js +2 -0
  3. package/package.json +21 -2
  4. package/default/config/automation/index.js +0 -37
  5. package/default/config/collections/examples.js +0 -60
  6. package/default/config/config/.collections.json +0 -1
  7. package/default/config/config/globalFields.js +0 -15
  8. package/default/config/config/settings.json +0 -23
  9. package/default/config/config/statuses.js +0 -0
  10. package/default/config/config/users.js +0 -35
  11. package/default/config/endpoints/index.js +0 -19
  12. package/default/config/fields/vimeo.js +0 -36
  13. package/default/config/hooks/test.js +0 -5
  14. package/default/config/plugins/.gitkeep +0 -0
  15. package/default/front/README.md +0 -8
  16. package/default/front/dist/_redirects +0 -1
  17. package/default/front/dist/assets/index.00922bd5.js +0 -99
  18. package/default/front/dist/assets/index.1781f175.css +0 -1
  19. package/default/front/dist/favicon.png +0 -0
  20. package/default/front/dist/index.html +0 -53
  21. package/default/front/dist/index.js +0 -66
  22. package/default/front/index.html +0 -25
  23. package/default/front/index.js +0 -197
  24. package/default/front/package.json +0 -40
  25. package/default/front/postcss.config.js +0 -6
  26. package/default/front/public/_redirects +0 -1
  27. package/default/front/public/favicon.png +0 -0
  28. package/default/front/public/index.js +0 -66
  29. package/default/front/src/App.vue +0 -27
  30. package/default/front/src/components/layout/login.vue +0 -212
  31. package/default/front/src/components/layout/modal.vue +0 -113
  32. package/default/front/src/components/layout/spinner.vue +0 -17
  33. package/default/front/src/components/pages/404.vue +0 -28
  34. package/default/front/src/components/pages/home.vue +0 -74
  35. package/default/front/src/components/partials/button.vue +0 -31
  36. package/default/front/src/helpers/Mango.vue +0 -455
  37. package/default/front/src/helpers/breakpoints.js +0 -34
  38. package/default/front/src/helpers/darkMode.js +0 -38
  39. package/default/front/src/helpers/email.js +0 -32
  40. package/default/front/src/helpers/formatPhone.js +0 -18
  41. package/default/front/src/helpers/localDB.js +0 -315
  42. package/default/front/src/helpers/mango.js +0 -341
  43. package/default/front/src/helpers/model.js +0 -9
  44. package/default/front/src/helpers/multiSelect.vue +0 -252
  45. package/default/front/src/helpers/pills.vue +0 -75
  46. package/default/front/src/helpers/reconnecting-websocket.js +0 -357
  47. package/default/front/src/helpers/uploadFile.vue +0 -157
  48. package/default/front/src/helpers/uploadFiles.vue +0 -100
  49. package/default/front/src/helpers/uploadImages.vue +0 -89
  50. package/default/front/src/helpers/user.js +0 -40
  51. package/default/front/src/index.css +0 -281
  52. package/default/front/src/main.js +0 -145
  53. package/default/front/tailwind.config.js +0 -46
  54. package/default/front/vite.config.js +0 -10
  55. package/default/front/yarn.lock +0 -3380
  56. package/default/package.json +0 -8
  57. package/webpack.config.js +0 -56
@@ -1,315 +0,0 @@
1
- import axios from "axios"
2
- import Mango from "./mango"
3
- import Swal from "sweetalert2"
4
-
5
- // Function for setting cookies
6
- let setCookie = function (cname, cvalue) {
7
- var d = new Date();
8
- d.setTime(d.getTime() + (365 * 24 * 60 * 60 * 1000));
9
- var expires = "expires=" + d.toUTCString();
10
- document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
11
- }
12
-
13
- function timeout(ms) {
14
- return new Promise((resolve, reject) => {
15
- setTimeout(() => {
16
- reject(new Error(`Timeout after ${ms} ms`));
17
- }, ms);
18
- });
19
- }
20
-
21
- async function runWithTimeout(callback, ms) {
22
- try {
23
- let response = await Promise.race([
24
- callback(),
25
- timeout(ms)
26
- ]);
27
- console.log('timeout', response)
28
- return response;
29
- } catch (error) {
30
- console.error(error.message);
31
- }
32
- }
33
-
34
- export default class LocalDB {
35
-
36
- constructor(collection, api) {
37
-
38
- this.collection = collection
39
-
40
- this.getDb()
41
-
42
- this.ready = false
43
- this.db = null
44
- this.loading = false
45
- this.saving = false
46
- this.deleting = false
47
- this.entry = null
48
- this.entries = null
49
-
50
- this.api = api
51
-
52
- }
53
-
54
- async getDb() {
55
-
56
- let request = window.indexedDB.open(this.collection, 1);
57
-
58
- request.onerror = e => {
59
- this.ready = false
60
- console.error('Error opening db', e);
61
- };
62
-
63
- request.onsuccess = e => {
64
- this.db = e.target.result
65
- this.ready = true
66
- };
67
-
68
- request.onupgradeneeded = e => {
69
- console.log('onupgradeneeded');
70
- this.db = e.target.result;
71
- let objectStore = this.db.createObjectStore(this.collection, { autoIncrement: true, keyPath: 'id' });
72
- };
73
-
74
- }
75
-
76
- async save(entry, syncing) {
77
-
78
- if (!this.ready) return
79
-
80
- this.saving = true;
81
-
82
- let entryExists = !!entry.id
83
- let onlyLocal = !isNaN(entry?.id) || !entryExists
84
-
85
- let existingEntry
86
-
87
- if (onlyLocal && entryExists) {
88
- entry.id = Number(entry.id)
89
- existingEntry = await this.get(entry.id)
90
- } else if (entryExists) {
91
- try {
92
- existingEntry = await this.get(entry.id)
93
- } catch {
94
- // console.log('must just be in cloud')
95
- }
96
- }
97
-
98
- return await new Promise(async (resolve, reject) => {
99
-
100
- let trans = this.db.transaction([this.collection], 'readwrite');
101
- let store = trans.objectStore(this.collection);
102
-
103
- if (existingEntry) entry = { ...existingEntry, ...entry }
104
-
105
- // Remove Vue Proxy stuff so indexedDB is happy
106
- let savedImage = entry.image
107
- delete entry.image
108
- entry = JSON.parse(JSON.stringify(entry))
109
- if (!syncing) entry.updatedLocally = new Date()
110
-
111
- // Format Address for offline
112
- // if (!entry.address?.id && entry.address?.formatted) entry.address = entry.address.formatted
113
-
114
- // Handle images
115
- if (savedImage?.type?.includes?.('image')) entry.image = savedImage
116
- if (savedImage?.includes?.('http')) entry.image = savedImage
117
-
118
-
119
- let method = entryExists ? 'put' : 'add'
120
- let request = store[method](entry)
121
-
122
- request.onsuccess = async () => {
123
- this.saving = false
124
- let localId = request.result
125
-
126
- if (window?.offlineMode) return resolve({ ...entry, id: localId })
127
-
128
- // If it only exists in the localDB, remove the ID for Mango
129
- if (onlyLocal) delete entry.id
130
-
131
- try {
132
-
133
- // Try to upload the image
134
- if (entry?.image?.type?.includes?.('image')) {
135
- await runWithTimeout(async () => {
136
- console.log('upload')
137
- const formData = new FormData()
138
- formData.append('file', entry.image)
139
- const response = await axios.post(`${this.api}/upload`, formData)
140
- console.log('upload response:', response)
141
- const path = response?.data?.paths?.[0]
142
- const url = `${this.api}${path}`
143
- entry.image = url
144
- }, 10 * 1000)
145
- }
146
-
147
- // Save to the cloud - this will throw if offline)
148
-
149
- // If the entry is over a day old...
150
- let olderThanOneDay = new Date(entry?.updatedLocally || '1/1/2024') < new Date(new Date().getTime() - 24 * 60 * 60 * 1000)
151
- if (onlyLocal && olderThanOneDay) await this.delete(localId)
152
-
153
- delete entry.updatedLocally
154
-
155
- // Save to Mango (timeout if already created, else no timeout)
156
- let response
157
- if (onlyLocal) {
158
- // Check the internet speed, if too slow, throw and queue for later
159
- let speedTest = await axios.get(`/images/logo.jpg?v=${Date.now()}`, { timeout: 1000 })
160
- let { response: mangoResponse, warnings } = await Mango[this.collection].save(entry, null, true)
161
- if (warnings?.length) Swal.fire('WARNING:', warnings?.join(', '), 'warning')
162
- console.log('mangoResponse', mangoResponse)
163
- response = mangoResponse
164
- }
165
- else response = await runWithTimeout(async () => await Mango[this.collection].save(entry), 5000)
166
-
167
- // If successfull, delete from local queue
168
- if (response?.id) {
169
- await this.delete(localId)
170
- resolve(response);
171
- } else {
172
- console.log('response', response)
173
- // Mango will throw if offline so delete this entry and save it to the failed queue
174
- // await Mango.failedleads.save({ data: { raw: entry }, error: response, user: window.localStorage.getItem('user') })
175
- // await this.delete(localId)
176
-
177
- // Unauthorized
178
- if (typeof response == 'string' && response?.includes?.('not have permission')) {
179
- // Logout if credentials are bad
180
- window.localStorage.removeItem('user')
181
- window.localStorage.removeItem('token')
182
- window.localStorage.removeItem('email')
183
- window.localStorage.removeItem('auth')
184
- setCookie(`Authorization`, ``)
185
- window.location.reload()
186
- }
187
-
188
- // Existing Address
189
- if (typeof response == 'string' && response?.includes?.('already visited this address')) {
190
- await this.delete(localId)
191
- Swal.fire('Existing Address', response, 'warning')
192
- if (window.location.href.includes(`leads/${localId}`)) window.location.href = '/'
193
- resolve({ stop: true });
194
- }
195
-
196
- // Address Lockout
197
- if (typeof response == 'string' && response?.includes?.('asked not to be disturbed')) {
198
- await this.delete(localId)
199
- Swal.fire('Address Lockout', response, 'warning')
200
- if (window.location.href.includes(`leads/${localId}`)) window.location.href = '/'
201
- resolve({ stop: true });
202
- }
203
-
204
- console.log(response, onlyLocal);
205
- resolve({ ...entry, id: localId });
206
- }
207
-
208
- } catch (e) {
209
- console.log(e.message)
210
- resolve({ ...entry, id: localId });
211
- }
212
- };
213
-
214
- request.onerror = (e) => {
215
- this.saving = false
216
- reject(e);
217
- };
218
-
219
- });
220
-
221
- }
222
-
223
- async get(id) {
224
-
225
- if (!this.ready) return
226
-
227
- this.loading = true;
228
-
229
- return await new Promise((resolve, reject) => {
230
- let trans = this.db.transaction([this.collection], 'readonly');
231
- let store = trans.objectStore(this.collection);
232
- let request = store.get(id);
233
-
234
- request.onsuccess = () => {
235
- this.loading = false;
236
- resolve(request.result);
237
- };
238
-
239
- request.onerror = (e) => {
240
- this.loading = false;
241
- reject(e);
242
- };
243
- });
244
-
245
- }
246
-
247
- async getEntries({ pageIndex = 0, pageSize = 1000 } = {}) {
248
-
249
- if (!this.ready) return []
250
-
251
- this.loading = true;
252
-
253
- let response = await new Promise((resolve, reject) => {
254
- let trans = this.db.transaction([this.collection], 'readonly');
255
- let store = trans.objectStore(this.collection);
256
- let cursorRequest = store.openCursor();
257
-
258
- let entries = [];
259
- let skippedEntries = pageIndex * pageSize;
260
-
261
- cursorRequest.onsuccess = (e) => {
262
- let cursor = e.target.result;
263
- if (cursor) {
264
- if (skippedEntries > 0) {
265
- // Skip the entries before the current page
266
- cursor.advance(skippedEntries);
267
- skippedEntries = 0;
268
- } else {
269
- entries.push(cursor.value);
270
- if (entries.length < pageSize) {
271
- cursor.continue();
272
- } else {
273
- resolve(entries);
274
- }
275
- }
276
- } else {
277
- // No more entries to read; resolve with what we have
278
- resolve(entries);
279
- }
280
- };
281
-
282
- cursorRequest.onerror = (e) => {
283
- reject(e);
284
- };
285
- });
286
-
287
- // console.log('response', response);
288
- this.loading = false;
289
- return response;
290
- }
291
-
292
- async delete(id) {
293
-
294
- this.deleting = true;
295
-
296
- return new Promise((resolve, reject) => {
297
-
298
- let trans = this.db.transaction([this.collection], 'readwrite');
299
- let store = trans.objectStore(this.collection);
300
- let request = store.delete(id);
301
-
302
- request.onsuccess = () => {
303
- this.deleting = false
304
- resolve(request.result);
305
- };
306
-
307
- request.onerror = (e) => {
308
- this.deleting = false
309
- reject(e);
310
- };
311
-
312
- });
313
- }
314
-
315
- }
@@ -1,341 +0,0 @@
1
- // import collections from '../../../mango/config/.collections.json'
2
- // import { algoliaAppId, algoliaSearchKey, algoliaIndex, port, domain } from '../../../mango/config/settings'
3
- import collections from '../../../config/config/.collections.json'
4
- import { algoliaAppId, algoliaSearchKey, algoliaIndex, port, domain } from '../../../config/config/settings'
5
- import axios from "axios";
6
- import { ref } from 'vue'
7
- import algoliasearch from 'algoliasearch/lite'
8
-
9
- let endpoints = {
10
- authors: ['get'],
11
- // scripture: { validate: ['post'] }
12
- }
13
-
14
- // console.log('collections', collections)
15
-
16
- const client = algoliasearch(algoliaAppId, algoliaSearchKey);
17
- const algolia = client.initIndex(algoliaIndex);
18
-
19
- let api = `https://${domain}`
20
- let ws = `wss://${domain}/graphql`
21
-
22
- if (process.env.NODE_ENV != 'production') {
23
- api = `http://localhost:${port}`
24
- ws = `ws://localhost:${port}/graphql`
25
- }
26
-
27
- const Mango = collections.reduce((a, c) => {
28
-
29
- let runQuery = ({ limit, page, search, fields, id, sort, depthLimit } = {}) => {
30
-
31
- let fullQuery
32
-
33
-
34
- const params = { limit, page, search, fields, sort, depthLimit }
35
-
36
- if (params.search != undefined) params.search = JSON.stringify(params.search)
37
- if (params.fields != undefined) params.fields = JSON.stringify(params.fields)
38
- if (params.sort != undefined) params.sort = JSON.stringify(params.sort)
39
-
40
- const query = Object.keys(params)
41
- .filter(key => params[key] != undefined)
42
- ?.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
43
- ?.join('&') || ''
44
- // console.log(query)
45
-
46
- fullQuery = `${api}/${c.name}/${id || ''}?${query}`
47
-
48
- let Authorization = window.localStorage.getItem('token')
49
-
50
- return new Promise((resolve, reject) => {
51
- axios.get(fullQuery, { headers: { Authorization } })
52
- .then(response => resolve(response?.data?.response))
53
- .catch(e => reject(e))
54
- })
55
-
56
- }
57
-
58
- let runGraphql = (query) => {
59
-
60
- let Authorization = window.localStorage.getItem('token')
61
- query = { query }
62
- return new Promise((resolve, reject) => {
63
- axios.post(`${api}/graphql`, query, { headers: { Authorization } })
64
- .then(response => resolve(response?.data?.data))
65
- .catch(e => reject(e))
66
- })
67
-
68
- }
69
-
70
- let runAlgolia = (search, query, algoliaFilters) => {
71
-
72
- search = search || ''
73
-
74
- let filters = `collection:${c.name}`
75
- if (algoliaFilters) filters += ` AND ${algoliaFilters}`
76
-
77
- let algoliaQuery = {
78
- page: query?.page || 0,
79
- filters,
80
- hitsPerPage: query?.limit || 10
81
- }
82
-
83
- if (query?.fields) algoliaQuery.attributesToRetrieve = query.fields
84
-
85
- return new Promise((resolve, reject) => {
86
- algolia.search(search, algoliaQuery)
87
- .then(({ hits, nbHits }) => {
88
- hits.forEach(h => h.id = h.objectID)
89
- resolve({ hits, nbHits })
90
- })
91
- })
92
-
93
- }
94
-
95
- let save = (data, options = {}) => {
96
- let { id } = data
97
- let method = id ? 'put' : 'post'
98
-
99
- // // Remove _id and computed fields
100
- delete data.collection
101
- delete data._id
102
- delete data.id
103
-
104
- for (let field of c.fields) {
105
- if (field.computed) delete data[field.name]
106
- if (field.relationship) data[field.name] = Array.isArray(data[field.name]) ? data[field.name].map(r => r?.id || r) : data[field.name]?.id ? data[field.name].id : data[field.name]
107
- }
108
- for (let name in data) {
109
- if (name.includes('__')) delete data[name]
110
- }
111
-
112
- let payload = { ...data }
113
- let Authorization = window.localStorage.getItem('token')
114
- let headers = {
115
- Authorization,
116
- ...options.headers
117
- }
118
-
119
- return new Promise((resolve, reject) => {
120
- axios[method](`${api}/${c.name}/${id || ''}`, payload, { headers })
121
- .then(response => resolve(response?.data?.response))
122
- .catch(e => reject(e))
123
- })
124
- }
125
-
126
- let deleteEntry = (data) => {
127
- let id = data.id || data
128
-
129
- let Authorization = window.localStorage.getItem('token')
130
-
131
- return new Promise((resolve, reject) => {
132
- axios.delete(`${api}/${c.name}/${id || ''}`, { headers: { Authorization } })
133
- .then(response => resolve(response?.data))
134
- .catch(e => reject(e))
135
- })
136
- }
137
-
138
- a[c.name] = runQuery
139
- a[c.name]['save'] = save
140
- a[c.name]['delete'] = deleteEntry
141
- a[c.singular] = (id, query) => runQuery({ id, ...query })
142
-
143
- a[c.name]['search'] = runAlgolia
144
- a[c.name]['search']['init'] = (search, query, algoliaFilters) => {
145
- let loading = ref(true)
146
- let data = ref(null)
147
- let error = ref(null)
148
- let totalResults = ref(null)
149
-
150
- let response = runAlgolia(search, query, algoliaFilters)
151
- .then(response => {
152
- data.value = response.hits
153
- totalResults.value = response.nbHits
154
- loading.value = false
155
- })
156
- .catch(e => {
157
- loading.value = false
158
- error.value = e
159
- })
160
-
161
- return { data, loading, error }
162
- }
163
-
164
- a[c.name]['init'] = ({ limit, page, search, fields, id, sort } = {}) => {
165
-
166
- let loading = ref(true)
167
- let data = ref(null)
168
- let error = ref(null)
169
-
170
- let response = runQuery({ limit, page, search, fields, id, sort })
171
- .then(response => {
172
- data.value = response
173
- loading.value = false
174
- })
175
- .catch(e => {
176
- loading.value = false
177
- error.value = e
178
- })
179
-
180
- return { data, loading, error }
181
-
182
- }
183
-
184
- a[c.singular]['init'] = (id) => a[c.name]['init']({ id })
185
-
186
- a.relationRequest = ({ limit, page, search, fields, id, sort, depthLimit, path } = {}) => {
187
-
188
- let fullQuery
189
-
190
-
191
- const params = { limit, page, search, fields, sort, depthLimit }
192
-
193
- if (params.search != undefined) params.search = JSON.stringify(params.search)
194
- if (params.fields != undefined) params.fields = JSON.stringify(params.fields)
195
- if (params.sort != undefined) params.sort = JSON.stringify(params.sort)
196
-
197
- const query = Object.keys(params)
198
- .filter(key => params[key] != undefined)
199
- ?.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
200
- ?.join('&') || ''
201
- // console.log(query)
202
-
203
- fullQuery = `${api}/${path}?${query}`
204
-
205
- let Authorization = window.localStorage.getItem('token')
206
-
207
- return new Promise((resolve, reject) => {
208
- axios.get(fullQuery, { headers: { Authorization } })
209
- .then(response => resolve(response?.data?.response))
210
- .catch(e => reject(e))
211
- })
212
-
213
- }
214
- a.relationRequest.init = (query) => {
215
-
216
- let loading = ref(true)
217
- let data = ref(null)
218
- let error = ref(null)
219
-
220
- let response = a.relationRequest(query)
221
- .then(response => {
222
- data.value = response
223
- loading.value = false
224
- })
225
- .catch(e => {
226
- loading.value = false
227
- error.value = e
228
- })
229
-
230
- return { data, loading, error }
231
-
232
- }
233
-
234
-
235
- a.graphql = runGraphql
236
- a.graphql.init = (query) => {
237
-
238
- let loading = ref(true)
239
- let data = ref(null)
240
- let error = ref(null)
241
-
242
- let response = runGraphql(query)
243
- .then(response => {
244
- data.value = response
245
- loading.value = false
246
- })
247
- .catch(e => {
248
- loading.value = false
249
- error.value = e
250
- })
251
-
252
- return { data, loading, error }
253
-
254
- }
255
-
256
- return a
257
-
258
- }, {})
259
-
260
- Mango.search = (search, query, algoliaFilters) => {
261
-
262
- search = search || ''
263
-
264
- let filters = ``
265
- if (algoliaFilters) filters += `${algoliaFilters}`
266
-
267
- let algoliaQuery = {
268
- page: query?.page || 0,
269
- filters,
270
- hitsPerPage: query?.limit || 10
271
- }
272
-
273
- if (query?.fields) algoliaQuery.attributesToRetrieve = query.fields
274
-
275
- return new Promise((resolve, reject) => {
276
- algolia.search(search, algoliaQuery)
277
- .then(({ hits }) => {
278
- hits.forEach(h => h.id = h.objectID)
279
- resolve(hits)
280
- })
281
- })
282
-
283
- }
284
-
285
- Mango.login = ({ email, password }) => {
286
- return new Promise((resolve, reject) => {
287
- axios.post(`${api}/endpoints/account/login`, { email, password })
288
- .then(response => {
289
- window.localStorage.setItem('token', response.data.token)
290
- window.localStorage.setItem('user', response.data.memberId)
291
- window.localStorage.setItem('email', email)
292
- resolve(response.data)
293
- })
294
- .catch(e => reject(e))
295
- })
296
- }
297
-
298
- Mango.endpoints = Object.keys(endpoints).reduce((a, c) => {
299
-
300
- a[c] = {}
301
-
302
- for (let method of endpoints[c]) {
303
- a[c][method] = () => {
304
-
305
- return new Promise((resolve, reject) => {
306
- console.log('method', method)
307
- console.log('`${api}/endpoints/${c}`', `${api}/endpoints/${c}`)
308
- axios[method](`${api}/endpoints/${c}`)
309
- .then(response => resolve(response?.data))
310
- .catch(e => reject(e))
311
- })
312
-
313
- }
314
- }
315
-
316
- for (let method of endpoints[c]) {
317
- a[c][method]['init'] = () => {
318
-
319
- let loading = ref(true)
320
- let data = ref(null)
321
- let error = ref(null)
322
-
323
- let response = a[c][method]().then(r => {
324
- data.value = r
325
- loading.value = false
326
- })
327
-
328
- return { data, loading, error }
329
- }
330
- }
331
-
332
- return a
333
-
334
- }, {})
335
-
336
- Mango.collections = collections
337
- Mango.ws = ws
338
-
339
- Mango.online = async () => { try { return (await axios.get(`${api}/endpoints/test`))?.data?.includes('🥭') } catch (e) { return false } }
340
-
341
- export default Mango
@@ -1,9 +0,0 @@
1
-
2
- import { computed } from 'vue'
3
-
4
- export function useModel(props, emit, name = 'modelValue') {
5
- return computed({
6
- get: () => props[name],
7
- set: (value) => emit(`update:${name}`, value)
8
- })
9
- }