@edgedev/create-edge-app 1.1.23 → 1.1.26

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 (116) hide show
  1. package/.env +1 -0
  2. package/.env.dev +1 -0
  3. package/README.md +55 -20
  4. package/{agent.md → agents.md} +2 -0
  5. package/bin/cli.js +6 -6
  6. package/edge/components/auth/login.vue +384 -0
  7. package/edge/components/auth/register.vue +396 -0
  8. package/edge/components/auth.vue +108 -0
  9. package/edge/components/autoFileUpload.vue +215 -0
  10. package/edge/components/billing.vue +8 -0
  11. package/edge/components/buttonDivider.vue +14 -0
  12. package/edge/components/chip.vue +34 -0
  13. package/edge/components/clipboardButton.vue +42 -0
  14. package/edge/components/cms/block.vue +529 -0
  15. package/edge/components/cms/blockApi.vue +212 -0
  16. package/edge/components/cms/blockEditor.vue +725 -0
  17. package/edge/components/cms/blockInput.vue +66 -0
  18. package/edge/components/cms/blockPicker.vue +486 -0
  19. package/edge/components/cms/blockRender.vue +78 -0
  20. package/edge/components/cms/blockSheetContent.vue +28 -0
  21. package/edge/components/cms/codeEditor.vue +466 -0
  22. package/edge/components/cms/fontUpload.vue +327 -0
  23. package/edge/components/cms/htmlContent.vue +807 -0
  24. package/edge/components/cms/init_blocks/api_with_subarrays.html +17 -0
  25. package/edge/components/cms/init_blocks/array_with_collection.html +7 -0
  26. package/edge/components/cms/init_blocks/array_with_objects.html +7 -0
  27. package/edge/components/cms/init_blocks/carousel.html +103 -0
  28. package/edge/components/cms/init_blocks/contact_us.html +69 -0
  29. package/edge/components/cms/init_blocks/content_with_left_image.html +27 -0
  30. package/edge/components/cms/init_blocks/footer.html +24 -0
  31. package/edge/components/cms/init_blocks/header_divider.html +7 -0
  32. package/edge/components/cms/init_blocks/hero.html +35 -0
  33. package/edge/components/cms/init_blocks/hero_carousel.html +52 -0
  34. package/edge/components/cms/init_blocks/newsletter.html +117 -0
  35. package/edge/components/cms/init_blocks/post_content.html +7 -0
  36. package/edge/components/cms/init_blocks/post_title_header.html +21 -0
  37. package/edge/components/cms/init_blocks/posts_list.html +20 -0
  38. package/edge/components/cms/init_blocks/properties_showcase.html +100 -0
  39. package/edge/components/cms/init_blocks/property_carousel.html +59 -0
  40. package/edge/components/cms/init_blocks/property_detail.html +112 -0
  41. package/edge/components/cms/init_blocks/property_detail_header.html +34 -0
  42. package/edge/components/cms/init_blocks/property_results.html +137 -0
  43. package/edge/components/cms/init_blocks/property_search.html +75 -0
  44. package/edge/components/cms/init_blocks/simple_array.html +7 -0
  45. package/edge/components/cms/mediaCard.vue +116 -0
  46. package/edge/components/cms/mediaManager.vue +386 -0
  47. package/edge/components/cms/menu.vue +1103 -0
  48. package/edge/components/cms/optionsSelect.vue +107 -0
  49. package/edge/components/cms/page.vue +1785 -0
  50. package/edge/components/cms/posts.vue +1083 -0
  51. package/edge/components/cms/site.vue +1298 -0
  52. package/edge/components/cms/themeDefaultMenu.vue +548 -0
  53. package/edge/components/cms/themeEditor.vue +426 -0
  54. package/edge/components/dashboard.vue +776 -0
  55. package/edge/components/editor.vue +671 -0
  56. package/edge/components/fileTree.vue +72 -0
  57. package/edge/components/files.vue +89 -0
  58. package/edge/components/formSubtypes/myOrgs.vue +214 -0
  59. package/edge/components/formSubtypes/users.vue +336 -0
  60. package/edge/components/functionChips.vue +57 -0
  61. package/edge/components/gError.vue +98 -0
  62. package/edge/components/gHelper.vue +67 -0
  63. package/edge/components/gInput.vue +1331 -0
  64. package/edge/components/loggingIn.vue +41 -0
  65. package/edge/components/menu.vue +137 -0
  66. package/edge/components/menuContent.vue +132 -0
  67. package/edge/components/myAccount.vue +317 -0
  68. package/edge/components/myOrganizations.vue +75 -0
  69. package/edge/components/myProfile.vue +122 -0
  70. package/edge/components/orgSwitcher.vue +25 -0
  71. package/edge/components/organizationMembers.vue +522 -0
  72. package/edge/components/organizationSettings.vue +271 -0
  73. package/edge/components/shad/breadcrumbs.vue +35 -0
  74. package/edge/components/shad/button.vue +43 -0
  75. package/edge/components/shad/checkbox.vue +73 -0
  76. package/edge/components/shad/combobox.vue +238 -0
  77. package/edge/components/shad/datepicker.vue +184 -0
  78. package/edge/components/shad/dialog.vue +32 -0
  79. package/edge/components/shad/dropdownMenu.vue +54 -0
  80. package/edge/components/shad/dropdownMenuItem.vue +21 -0
  81. package/edge/components/shad/form.vue +59 -0
  82. package/edge/components/shad/html.vue +877 -0
  83. package/edge/components/shad/input.vue +139 -0
  84. package/edge/components/shad/number.vue +109 -0
  85. package/edge/components/shad/select.vue +151 -0
  86. package/edge/components/shad/selectTags.vue +278 -0
  87. package/edge/components/shad/switch.vue +67 -0
  88. package/edge/components/shad/tags.vue +137 -0
  89. package/edge/components/shad/textarea.vue +102 -0
  90. package/edge/components/shad/typeMoney.vue +167 -0
  91. package/edge/components/sideBar.vue +288 -0
  92. package/edge/components/sideBarContent.vue +268 -0
  93. package/edge/components/sidebarProvider.vue +33 -0
  94. package/edge/components/tooltip.vue +16 -0
  95. package/edge/components/userMenu.vue +148 -0
  96. package/edge/components/v/alert.vue +59 -0
  97. package/edge/components/v/alertTitle.vue +18 -0
  98. package/edge/components/v/card.vue +53 -0
  99. package/edge/components/v/cardActions.vue +18 -0
  100. package/edge/components/v/cardText.vue +18 -0
  101. package/edge/components/v/cardTitle.vue +20 -0
  102. package/edge/components/v/col.vue +56 -0
  103. package/edge/components/v/list.vue +46 -0
  104. package/edge/components/v/listItem.vue +26 -0
  105. package/edge/components/v/listItemTitle.vue +18 -0
  106. package/edge/components/v/row.vue +42 -0
  107. package/edge/components/v/toolbar.vue +24 -0
  108. package/edge/composables/global.ts +519 -0
  109. package/edge-pull.sh +2 -0
  110. package/edge-push.sh +1 -0
  111. package/edge-status.sh +14 -0
  112. package/firebase.json +5 -2
  113. package/firebase_init.sh +21 -6
  114. package/package.json +1 -1
  115. package/plugins/firebase.client.ts +1 -0
  116. package/edge-components-install.sh +0 -1
@@ -0,0 +1,519 @@
1
+ // DO NOT EDIT
2
+
3
+ const route = useRoute()
4
+
5
+ const edgeState = reactive({
6
+ currentOrganization: '',
7
+ organizationDocPath: '',
8
+ organizations: [],
9
+ changeTracker: {},
10
+ user: null,
11
+ userRoles: [],
12
+ lastPaginatedDoc: null,
13
+ subscribedStatus: null,
14
+ showLeftPanel: {} as Record<string, boolean>,
15
+ menuItems: [],
16
+ isAdminCollections: [] as string[],
17
+ redirectRoute: '',
18
+ isEmulator: false,
19
+ blockEditorTheme: '',
20
+ blockEditorSite: '',
21
+ cmsPageWithUnsavedChanges: null,
22
+ devOverride: false,
23
+ })
24
+
25
+ const setOrganization = async (organization: string, edgeFirebase: any) => {
26
+ if (organization) {
27
+ edgeState.changeTracker = {}
28
+ localStorage.setItem('organizationID', organization)
29
+ edgeState.currentOrganization = organization
30
+ await edgeFirebase.startUsersSnapshot(`organizations/${organization}`)
31
+ edgeState.organizationDocPath = `organizations/${organization}`
32
+ if (import.meta.env.VITE_FIREBASE_EMULATOR_FIRESTORE) {
33
+ edgeState.isEmulator = true
34
+ }
35
+ }
36
+ }
37
+
38
+ const showLeftPanel = (show: boolean) => {
39
+ edgeState.showLeftPanel[route.path] = show
40
+ }
41
+
42
+ const getSubscribedStatus = (org: any) => {
43
+ let isSubscribed = true
44
+ let status = ''
45
+ let description = ''
46
+ let color = ''
47
+ let icon = ''
48
+
49
+ if (!org || !org.stripeSubscription) {
50
+ isSubscribed = false
51
+ status = 'Not Subscribed'
52
+ description = 'No subscription found.'
53
+ color = 'bg-red-900'
54
+ icon = 'AlertCircle'
55
+ }
56
+ else {
57
+ const subscription = org.stripeSubscription
58
+
59
+ if (!subscription || subscription === 'canceled') {
60
+ isSubscribed = false
61
+ status = 'Canceled'
62
+ description = 'The subscription has been canceled.'
63
+ color = 'bg-red-600'
64
+ icon = 'X'
65
+ }
66
+ else {
67
+ switch (subscription) {
68
+ case 'trialing':
69
+ status = 'Trial'
70
+ description = 'The subscription is currently in a trial period.'
71
+ color = 'bg-green-600'
72
+ icon = 'Check'
73
+ break
74
+ case 'active':
75
+ status = 'Active'
76
+ description = 'The subscription is in good standing.'
77
+ color = 'bg-green-600'
78
+ icon = 'Check'
79
+ break
80
+ case 'incomplete':
81
+ status = 'Incomplete'
82
+ description = 'A successful payment needs to be made within 23 hours to activate the subscription.'
83
+ color = 'bg-amber-500'
84
+ icon = 'Hourglass'
85
+ break
86
+ case 'incomplete_expired':
87
+ status = 'Incomplete Expired'
88
+ description = 'The initial payment on the subscription failed and no successful payment was made within 23 hours of creating the subscription.'
89
+ color = 'bg-red-600'
90
+ icon = 'AlertCircle'
91
+ break
92
+ case 'past_due':
93
+ status = 'Past Due'
94
+ description = 'Payment on the latest finalized invoice either failed or wasn’t attempted.'
95
+ color = 'bg-red-600'
96
+ icon = 'AlertCircle'
97
+ break
98
+ case 'unpaid':
99
+ status = 'Unpaid'
100
+ description = 'The latest invoice hasn’t been paid but the subscription remains in place.'
101
+ color = 'bg-red-600'
102
+ icon = 'AlertCircle'
103
+ break
104
+ case 'paused':
105
+ status = 'Paused'
106
+ description = 'The subscription has ended its trial period without a default payment method.'
107
+ color = 'bg-amber-500'
108
+ icon = 'PauseCircle'
109
+ break
110
+ default:
111
+ status = 'Unknown'
112
+ description = 'The subscription status is unknown.'
113
+ color = 'bg-red-600'
114
+ icon = 'AlertCircle'
115
+ break
116
+ }
117
+ }
118
+ }
119
+
120
+ return {
121
+ isSubscribed,
122
+ status,
123
+ description,
124
+ color,
125
+ icon,
126
+ }
127
+ }
128
+
129
+ const isDarkMode = () => {
130
+ if (window.matchMedia) {
131
+ const darkMode = window.matchMedia('(prefers-color-scheme: dark)')
132
+ return darkMode.matches
133
+ }
134
+ return false
135
+ }
136
+
137
+ const generateShortId = () => {
138
+ return Math.random().toString(36).substr(2, 6)
139
+ }
140
+
141
+ const objHas = (obj: any, key: string): boolean => {
142
+ if (obj === null || obj === undefined) {
143
+ return false
144
+ }
145
+ return Object.prototype.hasOwnProperty.call(obj, key)
146
+ }
147
+
148
+ const getOrganizations = async (edgeFirebase: any) => {
149
+ console.log('getOrganizations')
150
+ const orgs: any = []
151
+ if (edgeFirebase.user.loggedIn) {
152
+ for (const role of edgeFirebase.user.roles) {
153
+ const segments = role.collectionPath.split('-')
154
+ if (segments[0] === 'organizations') {
155
+ await edgeFirebase.startDocumentSnapshot('organizations', segments[1])
156
+ let org = await edgeFirebase.getDocData('organizations', segments[1])
157
+ if (!org?.name) {
158
+ org = { name: 'Organization', docId: segments[1] }
159
+ }
160
+ if (!orgs.some((o: { docId: string }) => o.docId === org.docId)) {
161
+ orgs.push(org)
162
+ }
163
+ }
164
+ }
165
+ }
166
+ edgeState.organizations = orgs
167
+ console.log('Organizations:', edgeState.organizations)
168
+ }
169
+
170
+ const dupObject = (obj: any): any => {
171
+ // console.log('Duplicating object:', obj)
172
+ return JSON.parse(JSON.stringify(obj))
173
+ }
174
+
175
+ const currentOrganizationObject = computed(() => {
176
+ const edgeFirebase: any = inject('edgeFirebase')
177
+ if (edgeState.organizations.length > 0) {
178
+ if (edgeState.currentOrganization && edgeFirebase?.data[`organizations/${edgeState.currentOrganization}`]) {
179
+ return edgeFirebase?.data[`organizations/${edgeState.currentOrganization}`]
180
+ }
181
+ }
182
+ return ''
183
+ })
184
+
185
+ const edgeRules = {
186
+ forms: (value: any) => {
187
+ if (!value.length) {
188
+ return 'You must setup at least one form.'
189
+ }
190
+ return true
191
+ },
192
+ submits: (value: any) => {
193
+ if (!value.length) {
194
+ return 'You must setup at least one submit.'
195
+ }
196
+ return true
197
+ },
198
+ gptFunctionName: (value: string) => {
199
+ const pattern = /^[a-zA-Z0-9_-]{1,64}$/
200
+ return pattern.test(value) || 'The function name must be 1-64 characters and can only contain letters, numbers, underscores, and dashes.'
201
+ },
202
+ endpoint: (value: string) => {
203
+ const urlPattern = /^https?:\/\/(?!:\/\/)([a-zA-Z0-9]+\.)?[a-zA-Z0-9][a-zA-Z0-9-]+(\.[a-zA-Z]{2,6})?(:\d{1,5})?(\/[^\s]*)?$/i
204
+ if (!urlPattern.test(value)) {
205
+ return `"${value}" is not a valid URL. The URL must include the protocol (http or https) and the path.`
206
+ }
207
+ return true
208
+ },
209
+ domains: (value: string) => {
210
+ const domainPattern = /^https?:\/\/(?!:\/\/)([a-zA-Z0-9]+\.)?[a-zA-Z0-9][a-zA-Z0-9-]+(\.[a-zA-Z]{2,6})?(:\d{1,5})?$/i
211
+ const localhostPattern = /^https?:\/\/localhost(:\d{1,5})?$/i
212
+ const ipAddressPattern = /^https?:\/\/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(:\d{1,5})?$/
213
+ const domains = value.split(',')
214
+ for (const domain of domains) {
215
+ if (
216
+ !domainPattern.test(domain)
217
+ && !localhostPattern.test(domain)
218
+ && !ipAddressPattern.test(domain)
219
+ ) {
220
+ return `"${domain}" is not a valid domain or IP address. The domain or IP address must include the protocol (http or https).`
221
+ }
222
+ }
223
+ return true
224
+ },
225
+ required: (value: any) => {
226
+ if (typeof value === 'string' && !value) {
227
+ return 'This field is required.'
228
+ }
229
+ else if (Array.isArray(value) && value.length === 0) {
230
+ return 'This field is required.'
231
+ }
232
+ else if (typeof value === 'object' && value !== null && Object.keys(value).length === 0) {
233
+ return 'This field is required.'
234
+ }
235
+ else if (typeof value === 'boolean' && !value) {
236
+ return 'This field is required.'
237
+ }
238
+ return true
239
+ },
240
+ email: (value: string) => {
241
+ const pattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
242
+ return pattern.test(value) || 'Invalid e-mail.'
243
+ },
244
+ emailOrField: (value: string) => {
245
+ const pattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
246
+ return pattern.test(value) || (value.startsWith('{{') && value.endsWith('}}')) || `Invalid e-mail or field. If you want to use a field, it must be wrapped in double curly braces, e.g. {{${value}}}`
247
+ },
248
+ toEmails: (value: string) => {
249
+ const pattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
250
+ const emails = value.split(',')
251
+ for (const email of emails) {
252
+ if (!pattern.test(email)) {
253
+ return `"${email}" is not a valid email address`
254
+ }
255
+ }
256
+ return true
257
+ },
258
+ emailsOrFields: (value: string) => {
259
+ const pattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
260
+ const emails = value.split(',')
261
+ for (const email of emails) {
262
+ if (!pattern.test(email) && !(email.startsWith('{{') && email.endsWith('}}'))) {
263
+ return `"${email}" is not a valid email address or field. If you want to use a field, it must be wrapped in double curly braces, e.g. {{${email}}}`
264
+ }
265
+ }
266
+ return true
267
+ },
268
+ password: (value: string) => {
269
+ const pattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
270
+ return pattern.test(value) || 'Password must have at least 8 characters, including uppercase and lowercase letters, numbers, and a special character'
271
+ },
272
+ }
273
+
274
+ const edgeLogOut = async (edgeFirebase: any) => {
275
+ edgeState.currentOrganization = ''
276
+ edgeState.organizationDocPath = ''
277
+ edgeState.organizations = []
278
+ edgeState.changeTracker = {}
279
+ edgeState.user = null
280
+ nextTick(async () => {
281
+ await edgeFirebase.logOut()
282
+ window.location.reload()
283
+ })
284
+ }
285
+
286
+ const orgUserRoles = (orgId: string) => {
287
+ orgId = orgId.replaceAll('/', '-')
288
+ const orgPath = `organizations-${orgId}`
289
+ const newData = JSON.parse(JSON.stringify(edgeState.userRoles))
290
+
291
+ for (let i = 0; i < newData.length; i++) {
292
+ const roles = newData[i].roles
293
+ for (let j = 0; j < roles.length; j++) {
294
+ const role = roles[j]
295
+ role.collectionPath = role.collectionPath.replace(/organizationDocPath/g, orgPath)
296
+ }
297
+ }
298
+
299
+ return newData
300
+ }
301
+
302
+ interface UserRoleType {
303
+ name: string
304
+ roles: { collectionPath: string; role: string }[]
305
+ }
306
+
307
+ interface RoleType {
308
+ collectionPath: string
309
+ role: string
310
+ }
311
+
312
+ const getRoleName = (roles: RoleType[], orgId: string) => {
313
+ const userRoles: UserRoleType[] = orgUserRoles(orgId)
314
+ for (const user of userRoles) {
315
+ let match = true
316
+ for (const userRole of user.roles) {
317
+ if (!roles.some(role => role.collectionPath === userRole.collectionPath && role.role === userRole.role)) {
318
+ match = false
319
+ break
320
+ }
321
+ }
322
+ if (match) {
323
+ return user.name
324
+ }
325
+ }
326
+ return 'Unknown'
327
+ }
328
+
329
+ const isAdminGlobal = (edgeFirebase: any) => computed(() => {
330
+ const roleCompares = dupObject(edgeState.isAdminCollections)
331
+ roleCompares.push(`organizations-${edgeState.currentOrganization}`)
332
+ console.log('roles compare')
333
+ console.log(roleCompares)
334
+ for (const compare of roleCompares) {
335
+ const orgRole = edgeFirebase?.user?.roles.find((role: any) =>
336
+ role.collectionPath === compare.replaceAll('/', '-'),
337
+ )
338
+ if (orgRole && orgRole.role === 'admin') {
339
+ return true
340
+ }
341
+ }
342
+ return false
343
+ })
344
+
345
+ interface MenuItem {
346
+ to: string
347
+ icon?: string
348
+ submenu?: SubMenuItem[]
349
+ }
350
+
351
+ interface SubMenuItem {
352
+ to: string
353
+ icon?: string
354
+ }
355
+
356
+ interface BestMatch {
357
+ icon: string
358
+ len: number
359
+ }
360
+
361
+ const iconFromMenu = (route: { path: string }): string => {
362
+ const normalize = (p: string): string => {
363
+ if (!p)
364
+ return '/'
365
+ const cleaned = p.replace(/\/+$/, '')
366
+ return cleaned.length ? cleaned : '/'
367
+ }
368
+
369
+ const current = normalize(route.path)
370
+ let best: BestMatch = { icon: 'LayoutDashboard', len: -1 }
371
+
372
+ for (const item of (edgeState.menuItems || []) as MenuItem[]) {
373
+ const parentTo = normalize(item.to)
374
+
375
+ // 1) Exact submenu match first (wins even if sub.to === item.to)
376
+ if (Array.isArray(item.submenu)) {
377
+ for (const sub of item.submenu) {
378
+ const subTo = normalize(sub.to)
379
+ if (subTo === current) {
380
+ return sub.icon || item.icon || 'LayoutDashboard'
381
+ }
382
+ // Track most specific submenu prefix match
383
+ if (current.startsWith(subTo) && subTo.length > best.len) {
384
+ best = { icon: sub.icon || item.icon || 'LayoutDashboard', len: subTo.length }
385
+ }
386
+ }
387
+ }
388
+
389
+ // 2) Exact parent match (only if no exact submenu already returned)
390
+ if (parentTo === current) {
391
+ return item.icon || 'LayoutDashboard'
392
+ }
393
+
394
+ // 3) Track most specific parent prefix match
395
+ if (current.startsWith(parentTo) && parentTo.length > best.len) {
396
+ best = { icon: item.icon || 'LayoutDashboard', len: parentTo.length }
397
+ }
398
+ }
399
+
400
+ // 4) Fallback
401
+ return best.icon
402
+ }
403
+ const toBool = (v: any): boolean => v === true || v === 'true' || v === 1 || v === '1'
404
+ const DEV_OVERRIDE_KEY = 'edgeDevOverride'
405
+
406
+ const devOverrideEnabled = (): boolean => {
407
+ if (edgeState.devOverride)
408
+ return true
409
+ if (typeof window === 'undefined')
410
+ return edgeState.devOverride
411
+ try {
412
+ return localStorage.getItem(DEV_OVERRIDE_KEY) === '1'
413
+ }
414
+ catch (error) {
415
+ console.warn('dev override read failed', error)
416
+ return false
417
+ }
418
+ }
419
+
420
+ const syncDevOverride = () => {
421
+ if (typeof window === 'undefined')
422
+ return
423
+ edgeState.devOverride = devOverrideEnabled()
424
+ }
425
+
426
+ const allowMenuItem = (item: any, isAdmin: boolean) => {
427
+ // const config = useRuntimeConfig()
428
+ const isDev = process.dev || devOverrideEnabled()
429
+ const adminOnly = toBool(item.adminOnly)
430
+ const devOnly = toBool(item.devOnly)
431
+ console.log('allowMenuItem', { item, isAdmin, isDev, adminOnly, devOnly })
432
+ const override = toBool(item.override)
433
+ if (item.override !== undefined)
434
+ return override
435
+ if (adminOnly && !isAdmin)
436
+ return false
437
+ if (devOnly && !isDev)
438
+ return false
439
+ return true
440
+ }
441
+
442
+ const cmsCollectionData = async (edgeFirebase: any, value: any, meta: any, currentSite: any = '') => {
443
+ for (const key in meta) {
444
+ if (meta[key]?.collection) {
445
+ const staticSearch = new edgeFirebase.SearchStaticData()
446
+
447
+ const currentQuery = meta[key].collection.query || []
448
+ for (const queryKey in meta[key].queryItems || {}) {
449
+ console.log('key', queryKey)
450
+ if (meta[key].queryItems[queryKey]) {
451
+ const findIndex = currentQuery.findIndex((q: any) => q.field === queryKey)
452
+ const queryOption = meta[key]?.queryOptions?.find((o: any) => o.field === queryKey)
453
+ const operator = queryOption?.operator || '=='
454
+ const newQuery = { field: queryKey, operator, value: meta[key].queryItems[queryKey] }
455
+ if (findIndex > -1) {
456
+ currentQuery[findIndex] = newQuery
457
+ }
458
+ else {
459
+ currentQuery.push(newQuery)
460
+ }
461
+ }
462
+ else {
463
+ const findIndex = currentQuery.findIndex((q: any) => q.field === queryKey)
464
+ if (findIndex > -1) {
465
+ currentQuery.splice(findIndex, 1)
466
+ }
467
+ }
468
+ }
469
+ let collectionPath = `${edgeState.organizationDocPath}/${meta[key].collection.path}`
470
+ if (meta[key].collection.path === 'posts' || meta[key].collection.path === 'post') {
471
+ collectionPath = `${edgeState.organizationDocPath}/sites/${currentSite}/published_posts`
472
+ }
473
+ await staticSearch.getData(collectionPath, currentQuery, meta[key].collection.order, meta[key].limit)
474
+
475
+ value[key] = Object.values(staticSearch.results.data)
476
+ }
477
+ }
478
+ return value
479
+ }
480
+
481
+ const getImage = (file: any, type: string) => {
482
+ const variants = Array.isArray(file?.cloudflareImageVariants)
483
+ ? file.cloudflareImageVariants.filter((variant: any) => typeof variant === 'string' && variant.length)
484
+ : []
485
+ if (variants.length) {
486
+ const normalizedType = (type || '').trim().toLowerCase()
487
+ if (normalizedType) {
488
+ const match = variants.find((variant: string) => variant.toLowerCase().endsWith(`/${normalizedType}`))
489
+ if (match) {
490
+ return match
491
+ }
492
+ }
493
+ return variants[0]
494
+ }
495
+ return file?.r2Url || ''
496
+ }
497
+
498
+ export const edgeGlobal = {
499
+ edgeState,
500
+ setOrganization,
501
+ showLeftPanel,
502
+ getSubscribedStatus,
503
+ isDarkMode,
504
+ generateShortId,
505
+ objHas,
506
+ getOrganizations,
507
+ dupObject,
508
+ currentOrganizationObject,
509
+ edgeRules,
510
+ edgeLogOut,
511
+ orgUserRoles,
512
+ getRoleName,
513
+ isAdminGlobal,
514
+ iconFromMenu,
515
+ cmsCollectionData,
516
+ allowMenuItem,
517
+ syncDevOverride,
518
+ getImage,
519
+ }
package/edge-pull.sh ADDED
@@ -0,0 +1,2 @@
1
+ git fetch edge-vue-components
2
+ git subtree pull --prefix=edge edge-vue-components main --squash
package/edge-push.sh ADDED
@@ -0,0 +1 @@
1
+ git subtree push --prefix=edge edge-vue-components main
package/edge-status.sh ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ git fetch edge-vue-components >/dev/null 2>&1
5
+
6
+ UP_TREE="$(git rev-parse edge-vue-components/main^{tree})"
7
+ LOCAL_TREE="$(git rev-parse HEAD:edge)"
8
+
9
+ if [ "$UP_TREE" = "$LOCAL_TREE" ]
10
+ then
11
+ echo "edge is in sync with edge-vue-components/main"
12
+ else
13
+ echo "edge differs from edge-vue-components/main"
14
+ fi
package/firebase.json CHANGED
@@ -25,7 +25,10 @@
25
25
  "rewrites": [
26
26
  {
27
27
  "source": "/api/stripe",
28
- "function": "stripe-webhook"
28
+ "function": {
29
+ "functionId": "stripe-webhook",
30
+ "region": "us-west1"
31
+ }
29
32
  },
30
33
  {
31
34
  "source": "**",
@@ -60,4 +63,4 @@
60
63
  },
61
64
  "singleProjectMode": true
62
65
  }
63
- }
66
+ }
package/firebase_init.sh CHANGED
@@ -1,19 +1,32 @@
1
1
  # Prompt for the Firebase configuration values
2
2
  echo "Please enter your Firebase project ID:"
3
3
  read project_id
4
+
4
5
  echo "Please enter your Firebase API key:"
5
6
  read api_key
7
+
6
8
  echo "Please enter your Firebase Auth domain:"
7
9
  read auth_domain
10
+
8
11
  echo "Please enter your Firebase storage bucket:"
9
12
  read storage_bucket
13
+
10
14
  echo "Please enter your Firebase messaging sender ID:"
11
15
  read messaging_sender_id
16
+
12
17
  echo "Please enter your Firebase app ID:"
13
18
  read app_id
19
+
14
20
  echo "Please enter your Firebase measurement ID:"
15
21
  read measurement_id
16
22
 
23
+ echo "Please enter your Firebase Functions region (default: us-west1):"
24
+ read functions_region
25
+
26
+ if [ -z "$functions_region" ]; then
27
+ functions_region="us-west1"
28
+ fi
29
+
17
30
  # Check if project_id is empty
18
31
  if [ -z "$project_id" ]; then
19
32
  echo "Error: Firebase project ID cannot be empty."
@@ -26,26 +39,26 @@ if ! command -v firebase &> /dev/null; then
26
39
  exit 1
27
40
  fi
28
41
 
29
- # Check if firebase.json exists and make a backup
42
+ # Backup firebase.json if it exists
30
43
  if [ -f ./firebase.json ]; then
31
44
  cp ./firebase.json ./firebase.json.temp
32
45
  fi
33
46
 
34
- # Check if firestore.rules exists and make a backup
47
+ # Backup firestore.rules if it exists
35
48
  if [ -f ./firestore.rules ]; then
36
49
  cp ./firestore.rules ./firestore.rules.temp
37
50
  fi
38
51
 
39
52
  # Initialize Firebase
40
- firebase use --add $project_id --alias default
53
+ firebase use --add "$project_id" --alias default
41
54
  firebase init firestore functions hosting storage emulators --project default
42
55
 
43
- # Restore firebase.json from backup
56
+ # Restore firebase.json
44
57
  if [ -f ./firebase.json.temp ]; then
45
58
  mv ./firebase.json.temp ./firebase.json
46
59
  fi
47
60
 
48
- # Restore firestore.rules from backup
61
+ # Restore firestore.rules
49
62
  if [ -f ./firestore.rules.temp ]; then
50
63
  mv ./firestore.rules.temp ./firestore.rules
51
64
  fi
@@ -58,6 +71,7 @@ echo "VITE_FIREBASE_STORAGE_BUCKET=$storage_bucket" >> .env
58
71
  echo "VITE_FIREBASE_MESSAGING_SENDER_ID=$messaging_sender_id" >> .env
59
72
  echo "VITE_FIREBASE_APP_ID=$app_id" >> .env
60
73
  echo "VITE_FIREBASE_MEASUREMENT_ID=$measurement_id" >> .env
74
+ echo "VITE_FIREBASE_FUNCTIONS_REGION=$functions_region" >> .env
61
75
  echo "VITE_FIREBASE_EMULATOR_AUTH=" >> .env
62
76
  echo "VITE_FIREBASE_EMULATOR_FIRESTORE=" >> .env
63
77
  echo "VITE_FIREBASE_EMULATOR_FUNCTIONS=" >> .env
@@ -73,9 +87,10 @@ echo "VITE_FIREBASE_STORAGE_BUCKET=$storage_bucket" >> .env.dev
73
87
  echo "VITE_FIREBASE_MESSAGING_SENDER_ID=$messaging_sender_id" >> .env.dev
74
88
  echo "VITE_FIREBASE_APP_ID=$app_id" >> .env.dev
75
89
  echo "VITE_FIREBASE_MEASUREMENT_ID=$measurement_id" >> .env.dev
90
+ echo "VITE_FIREBASE_FUNCTIONS_REGION=$functions_region" >> .env.dev
76
91
  echo "VITE_FIREBASE_EMULATOR_AUTH=9099" >> .env.dev
77
92
  echo "VITE_FIREBASE_EMULATOR_FIRESTORE=8080" >> .env.dev
78
93
  echo "VITE_FIREBASE_EMULATOR_FUNCTIONS=5001" >> .env.dev
79
94
  echo "VITE_FIREBASE_EMULATOR_STORAGE=9199" >> .env.dev
80
95
  echo "REGISTRATION_CODE=organization-registration-template" >> .env.dev
81
- echo "DEVELOPMENT_MODE=true" >> .env.dev
96
+ echo "DEVELOPMENT_MODE=true" >> .env.dev
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgedev/create-edge-app",
3
- "version": "1.1.23",
3
+ "version": "1.1.26",
4
4
  "description": "Create Edge Starter App",
5
5
  "bin": {
6
6
  "create-edge-app": "./bin/cli.js"
@@ -13,5 +13,6 @@ export default defineNuxtPlugin((nuxtApp) => {
13
13
  emulatorFirestore: import.meta.env.VITE_FIREBASE_EMULATOR_FIRESTORE,
14
14
  emulatorFunctions: import.meta.env.VITE_FIREBASE_EMULATOR_FUNCTIONS,
15
15
  emulatorStorage: import.meta.env.VITE_FIREBASE_EMULATOR_STORAGE,
16
+ functionsRegion: import.meta.env.VITE_FIREBASE_FUNCTIONS_REGION,
16
17
  }, true, true)
17
18
  })
@@ -1 +0,0 @@
1
- git clone https://github.com/Edge-Marketing-and-Design/edge-vue-components.git edge