@edgedev/create-edge-app 1.2.33 → 1.2.34
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/deploy.sh +77 -0
- package/edge/components/cms/block.vue +228 -18
- package/edge/components/cms/blockApi.vue +3 -3
- package/edge/components/cms/blockEditor.vue +374 -85
- package/edge/components/cms/blockPicker.vue +29 -3
- package/edge/components/cms/blockRender.vue +3 -3
- package/edge/components/cms/blocksManager.vue +755 -82
- package/edge/components/cms/codeEditor.vue +15 -6
- package/edge/components/cms/fontUpload.vue +318 -2
- package/edge/components/cms/htmlContent.vue +230 -89
- package/edge/components/cms/menu.vue +5 -4
- package/edge/components/cms/page.vue +750 -21
- package/edge/components/cms/site.vue +624 -84
- package/edge/components/cms/sitesManager.vue +5 -4
- package/edge/components/cms/themeEditor.vue +196 -162
- package/edge/components/editor.vue +5 -1
- package/edge/composables/global.ts +37 -5
- package/edge/composables/useCmsNewDocs.js +100 -0
- package/edge/composables/useEdgeCmsDialogPositionFix.js +19 -0
- package/edge/routes/cms/dashboard/blocks/[block].vue +5 -0
- package/edge/routes/cms/dashboard/blocks/index.vue +12 -1
- package/edge/routes/cms/dashboard/media/index.vue +5 -0
- package/edge/routes/cms/dashboard/sites/[site]/[[page]].vue +4 -0
- package/edge/routes/cms/dashboard/sites/[site].vue +4 -0
- package/edge/routes/cms/dashboard/sites/index.vue +4 -0
- package/edge/routes/cms/dashboard/templates/[page].vue +4 -0
- package/edge/routes/cms/dashboard/templates/index.vue +4 -0
- package/edge/routes/cms/dashboard/themes/[theme].vue +5 -0
- package/edge/routes/cms/dashboard/themes/index.vue +330 -1
- package/firebase.json +4 -0
- package/nuxt.config.ts +1 -1
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="js">
|
|
2
2
|
import { toTypedSchema } from '@vee-validate/zod'
|
|
3
3
|
import * as z from 'zod'
|
|
4
|
-
import { ArrowLeft, CircleAlert, FileCheck, FilePenLine, FileStack, FolderCog, FolderDown, FolderUp, FolderX, Inbox, Loader2, Mail, MailOpen, MoreHorizontal } from 'lucide-vue-next'
|
|
4
|
+
import { ArrowLeft, CircleAlert, FileCheck, FilePenLine, FileStack, FolderCog, FolderDown, FolderUp, FolderX, Inbox, Loader2, Mail, MailOpen, MoreHorizontal, Upload } from 'lucide-vue-next'
|
|
5
5
|
import { useStructuredDataTemplates } from '@/edge/composables/structuredDataTemplates'
|
|
6
6
|
|
|
7
7
|
const props = defineProps({
|
|
@@ -67,6 +67,16 @@ const state = reactive({
|
|
|
67
67
|
userFilter: 'all',
|
|
68
68
|
newDocs: {
|
|
69
69
|
sites: createSiteSettingsNewDocSchema(),
|
|
70
|
+
pages: {
|
|
71
|
+
name: { bindings: { 'field-type': 'text', 'label': 'Name', 'helper': 'Name' }, cols: '12', value: '' },
|
|
72
|
+
content: { value: [] },
|
|
73
|
+
postContent: { value: [] },
|
|
74
|
+
structure: { value: [] },
|
|
75
|
+
postStructure: { value: [] },
|
|
76
|
+
metaTitle: { value: '' },
|
|
77
|
+
metaDescription: { value: '' },
|
|
78
|
+
structuredData: { value: buildPageStructuredData() },
|
|
79
|
+
},
|
|
70
80
|
},
|
|
71
81
|
mounted: false,
|
|
72
82
|
page: {},
|
|
@@ -81,8 +91,19 @@ const state = reactive({
|
|
|
81
91
|
submissionFilter: '',
|
|
82
92
|
selectedSubmissionId: '',
|
|
83
93
|
publishSiteLoading: false,
|
|
94
|
+
importingPages: false,
|
|
95
|
+
importPageDocIdDialogOpen: false,
|
|
96
|
+
importPageDocIdValue: '',
|
|
97
|
+
importPageConflictDialogOpen: false,
|
|
98
|
+
importPageConflictDocId: '',
|
|
99
|
+
importPageErrorDialogOpen: false,
|
|
100
|
+
importPageErrorMessage: '',
|
|
84
101
|
})
|
|
85
102
|
|
|
103
|
+
const pageImportInputRef = ref(null)
|
|
104
|
+
const pageImportDocIdResolver = ref(null)
|
|
105
|
+
const pageImportConflictResolver = ref(null)
|
|
106
|
+
|
|
86
107
|
const pageInit = {
|
|
87
108
|
name: '',
|
|
88
109
|
content: [],
|
|
@@ -154,6 +175,44 @@ const canCreateSite = computed(() => {
|
|
|
154
175
|
return true
|
|
155
176
|
return isOrgAdmin.value
|
|
156
177
|
})
|
|
178
|
+
const cmsMultiOrg = useState('cmsMultiOrg', () => false)
|
|
179
|
+
const canEditSiteSettings = computed(() => {
|
|
180
|
+
if (!cmsMultiOrg.value)
|
|
181
|
+
return true
|
|
182
|
+
return currentOrgRoleName.value === 'admin' || currentOrgRoleName.value === 'site admin'
|
|
183
|
+
})
|
|
184
|
+
const useMenuPublishLabels = computed(() => {
|
|
185
|
+
return cmsMultiOrg.value && !canEditSiteSettings.value
|
|
186
|
+
})
|
|
187
|
+
const cmsSiteTabs = useState('cmsSiteTabs', () => ({
|
|
188
|
+
pages: true,
|
|
189
|
+
posts: true,
|
|
190
|
+
inbox: true,
|
|
191
|
+
}))
|
|
192
|
+
const cmsTabAccess = computed(() => {
|
|
193
|
+
const normalized = {
|
|
194
|
+
pages: cmsSiteTabs.value?.pages !== false,
|
|
195
|
+
posts: cmsSiteTabs.value?.posts !== false,
|
|
196
|
+
inbox: cmsSiteTabs.value?.inbox !== false,
|
|
197
|
+
}
|
|
198
|
+
if (!normalized.pages && !normalized.posts && !normalized.inbox) {
|
|
199
|
+
normalized.inbox = true
|
|
200
|
+
}
|
|
201
|
+
return normalized
|
|
202
|
+
})
|
|
203
|
+
const canViewPagesTab = computed(() => cmsTabAccess.value.pages)
|
|
204
|
+
const canViewPostsTab = computed(() => cmsTabAccess.value.posts)
|
|
205
|
+
const canViewInboxTab = computed(() => cmsTabAccess.value.inbox)
|
|
206
|
+
const hidePublishStatusAndActions = computed(() => cmsMultiOrg.value && !canViewPagesTab.value)
|
|
207
|
+
const defaultViewMode = computed(() => {
|
|
208
|
+
if (canViewPagesTab.value)
|
|
209
|
+
return 'pages'
|
|
210
|
+
if (canViewPostsTab.value)
|
|
211
|
+
return 'posts'
|
|
212
|
+
if (canViewInboxTab.value)
|
|
213
|
+
return 'submissions'
|
|
214
|
+
return 'pages'
|
|
215
|
+
})
|
|
157
216
|
|
|
158
217
|
const siteData = computed(() => {
|
|
159
218
|
return edgeFirebase.data?.[`${edgeGlobal.edgeState.organizationDocPath}/sites`]?.[props.site] || {}
|
|
@@ -854,7 +913,7 @@ const discardSiteSettings = async () => {
|
|
|
854
913
|
brandLogoLight: publishedSite.brandLogoLight || '',
|
|
855
914
|
favicon: publishedSite.favicon || '',
|
|
856
915
|
menuPosition: publishedSite.menuPosition || '',
|
|
857
|
-
forwardApex: publishedSite.forwardApex
|
|
916
|
+
forwardApex: publishedSite.forwardApex !== false,
|
|
858
917
|
contactEmail: publishedSite.contactEmail || '',
|
|
859
918
|
contactPhone: publishedSite.contactPhone || '',
|
|
860
919
|
metaTitle: publishedSite.metaTitle || '',
|
|
@@ -925,6 +984,326 @@ const pageList = computed(() => {
|
|
|
925
984
|
.sort((a, b) => (b.lastUpdated ?? 0) - (a.lastUpdated ?? 0))
|
|
926
985
|
})
|
|
927
986
|
|
|
987
|
+
const INVALID_PAGE_IMPORT_MESSAGE = 'Invalid file. Please import a valid page file.'
|
|
988
|
+
const pageImportCollectionPath = computed(() => `${edgeGlobal.edgeState.organizationDocPath}/sites/${props.site}/pages`)
|
|
989
|
+
|
|
990
|
+
const readTextFile = file => new Promise((resolve, reject) => {
|
|
991
|
+
if (typeof FileReader === 'undefined') {
|
|
992
|
+
reject(new Error('File import is only available in the browser.'))
|
|
993
|
+
return
|
|
994
|
+
}
|
|
995
|
+
const reader = new FileReader()
|
|
996
|
+
reader.onload = () => resolve(String(reader.result || ''))
|
|
997
|
+
reader.onerror = () => reject(new Error('Could not read the selected file.'))
|
|
998
|
+
reader.readAsText(file)
|
|
999
|
+
})
|
|
1000
|
+
|
|
1001
|
+
const isPlainObject = value => !!value && typeof value === 'object' && !Array.isArray(value)
|
|
1002
|
+
|
|
1003
|
+
const normalizeImportedPageDoc = (payload, fallbackDocId = '') => {
|
|
1004
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload))
|
|
1005
|
+
throw new Error(INVALID_PAGE_IMPORT_MESSAGE)
|
|
1006
|
+
|
|
1007
|
+
if (payload.document && typeof payload.document === 'object' && !Array.isArray(payload.document)) {
|
|
1008
|
+
const normalized = { ...payload.document }
|
|
1009
|
+
if (!normalized.docId && payload.docId)
|
|
1010
|
+
normalized.docId = payload.docId
|
|
1011
|
+
if (!normalized.docId && fallbackDocId)
|
|
1012
|
+
normalized.docId = fallbackDocId
|
|
1013
|
+
return normalized
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
const normalized = { ...payload }
|
|
1017
|
+
if (!normalized.docId && fallbackDocId)
|
|
1018
|
+
normalized.docId = fallbackDocId
|
|
1019
|
+
return normalized
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
const cloneSchemaValue = (value) => {
|
|
1023
|
+
if (isPlainObject(value) || Array.isArray(value))
|
|
1024
|
+
return edgeGlobal.dupObject(value)
|
|
1025
|
+
return value
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
const getDocDefaultsFromSchema = (schema = {}) => {
|
|
1029
|
+
const defaults = {}
|
|
1030
|
+
for (const [key, schemaEntry] of Object.entries(schema || {})) {
|
|
1031
|
+
const hasValueProp = isPlainObject(schemaEntry) && Object.prototype.hasOwnProperty.call(schemaEntry, 'value')
|
|
1032
|
+
const baseValue = hasValueProp ? schemaEntry.value : schemaEntry
|
|
1033
|
+
defaults[key] = cloneSchemaValue(baseValue)
|
|
1034
|
+
}
|
|
1035
|
+
return defaults
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
const getPageDocDefaults = () => getDocDefaultsFromSchema(state.newDocs?.pages || {})
|
|
1039
|
+
|
|
1040
|
+
const isBlankString = value => String(value || '').trim() === ''
|
|
1041
|
+
|
|
1042
|
+
const applyImportedPageSeoDefaults = (doc) => {
|
|
1043
|
+
if (!isPlainObject(doc))
|
|
1044
|
+
return doc
|
|
1045
|
+
|
|
1046
|
+
if (isBlankString(doc.structuredData))
|
|
1047
|
+
doc.structuredData = buildPageStructuredData()
|
|
1048
|
+
|
|
1049
|
+
if (doc.post && isBlankString(doc.postStructuredData))
|
|
1050
|
+
doc.postStructuredData = doc.structuredData || buildPageStructuredData()
|
|
1051
|
+
|
|
1052
|
+
return doc
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
const validateImportedPageDoc = (doc) => {
|
|
1056
|
+
if (!isPlainObject(doc))
|
|
1057
|
+
throw new Error(INVALID_PAGE_IMPORT_MESSAGE)
|
|
1058
|
+
|
|
1059
|
+
const requiredKeys = Object.keys(state.newDocs?.pages || {})
|
|
1060
|
+
const missing = requiredKeys.filter(key => !Object.prototype.hasOwnProperty.call(doc, key))
|
|
1061
|
+
if (missing.length)
|
|
1062
|
+
throw new Error(INVALID_PAGE_IMPORT_MESSAGE)
|
|
1063
|
+
|
|
1064
|
+
return doc
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
const normalizeMenusForImport = (menus) => {
|
|
1068
|
+
const normalized = isPlainObject(menus) ? edgeGlobal.dupObject(menus) : {}
|
|
1069
|
+
if (!Array.isArray(normalized['Site Root']))
|
|
1070
|
+
normalized['Site Root'] = []
|
|
1071
|
+
if (!Array.isArray(normalized['Not In Menu']))
|
|
1072
|
+
normalized['Not In Menu'] = []
|
|
1073
|
+
return normalized
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
const walkMenuEntries = (items, callback) => {
|
|
1077
|
+
if (!Array.isArray(items))
|
|
1078
|
+
return
|
|
1079
|
+
for (const entry of items) {
|
|
1080
|
+
if (!entry || typeof entry !== 'object')
|
|
1081
|
+
continue
|
|
1082
|
+
callback(entry)
|
|
1083
|
+
if (isPlainObject(entry.item)) {
|
|
1084
|
+
for (const nested of Object.values(entry.item)) {
|
|
1085
|
+
if (Array.isArray(nested))
|
|
1086
|
+
walkMenuEntries(nested, callback)
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
const menuIncludesDocId = (menus, docId) => {
|
|
1093
|
+
let found = false
|
|
1094
|
+
const checkEntry = (entry) => {
|
|
1095
|
+
if (found)
|
|
1096
|
+
return
|
|
1097
|
+
if (typeof entry?.item === 'string' && entry.item === docId)
|
|
1098
|
+
found = true
|
|
1099
|
+
}
|
|
1100
|
+
for (const menuItems of Object.values(menus || {})) {
|
|
1101
|
+
walkMenuEntries(menuItems, checkEntry)
|
|
1102
|
+
if (found)
|
|
1103
|
+
return true
|
|
1104
|
+
}
|
|
1105
|
+
return false
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
const collectMenuPageNames = (menus) => {
|
|
1109
|
+
const names = new Set()
|
|
1110
|
+
const collectEntry = (entry) => {
|
|
1111
|
+
if (typeof entry?.item !== 'string')
|
|
1112
|
+
return
|
|
1113
|
+
const name = String(entry?.name || '').trim()
|
|
1114
|
+
if (name)
|
|
1115
|
+
names.add(name)
|
|
1116
|
+
}
|
|
1117
|
+
for (const menuItems of Object.values(menus || {}))
|
|
1118
|
+
walkMenuEntries(menuItems, collectEntry)
|
|
1119
|
+
return names
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
const slugifyMenuPageName = (value) => {
|
|
1123
|
+
return String(value || '')
|
|
1124
|
+
.trim()
|
|
1125
|
+
.toLowerCase()
|
|
1126
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
1127
|
+
.replace(/(^-|-$)+/g, '') || 'page'
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
const makeUniqueMenuPageName = (value, existingNames = new Set()) => {
|
|
1131
|
+
const base = slugifyMenuPageName(value)
|
|
1132
|
+
let candidate = base
|
|
1133
|
+
let suffix = 2
|
|
1134
|
+
while (existingNames.has(candidate)) {
|
|
1135
|
+
candidate = `${base}-${suffix}`
|
|
1136
|
+
suffix += 1
|
|
1137
|
+
}
|
|
1138
|
+
return candidate
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
const addImportedPageToSiteMenu = (docId, pageName = '') => {
|
|
1142
|
+
if (isTemplateSite.value)
|
|
1143
|
+
return
|
|
1144
|
+
|
|
1145
|
+
const nextDocId = String(docId || '').trim()
|
|
1146
|
+
if (!nextDocId)
|
|
1147
|
+
return
|
|
1148
|
+
|
|
1149
|
+
const menus = normalizeMenusForImport(siteData.value?.menus || state.menus)
|
|
1150
|
+
if (menuIncludesDocId(menus, nextDocId)) {
|
|
1151
|
+
state.menus = menus
|
|
1152
|
+
return
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
const existingNames = collectMenuPageNames(menus)
|
|
1156
|
+
const menuName = makeUniqueMenuPageName(pageName || nextDocId, existingNames)
|
|
1157
|
+
menus['Site Root'].push({ name: menuName, item: nextDocId })
|
|
1158
|
+
state.menus = menus
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
const makeRandomPageDocId = (docsMap = {}) => {
|
|
1162
|
+
let nextDocId = String(edgeGlobal.generateShortId() || '').trim()
|
|
1163
|
+
while (!nextDocId || docsMap[nextDocId])
|
|
1164
|
+
nextDocId = String(edgeGlobal.generateShortId() || '').trim()
|
|
1165
|
+
return nextDocId
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
const makeImportedPageNameForNew = (baseName, docsMap = {}) => {
|
|
1169
|
+
const normalizedBase = String(baseName || '').trim() || 'page'
|
|
1170
|
+
const existingNames = new Set(
|
|
1171
|
+
Object.values(docsMap || {})
|
|
1172
|
+
.map(doc => String(doc?.name || '').trim().toLowerCase())
|
|
1173
|
+
.filter(Boolean),
|
|
1174
|
+
)
|
|
1175
|
+
|
|
1176
|
+
let suffix = 1
|
|
1177
|
+
let candidate = `${normalizedBase}-${suffix}`
|
|
1178
|
+
while (existingNames.has(candidate.toLowerCase())) {
|
|
1179
|
+
suffix += 1
|
|
1180
|
+
candidate = `${normalizedBase}-${suffix}`
|
|
1181
|
+
}
|
|
1182
|
+
return candidate
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
const requestPageImportDocId = (initialValue = '') => {
|
|
1186
|
+
state.importPageDocIdValue = String(initialValue || '')
|
|
1187
|
+
state.importPageDocIdDialogOpen = true
|
|
1188
|
+
return new Promise((resolve) => {
|
|
1189
|
+
pageImportDocIdResolver.value = resolve
|
|
1190
|
+
})
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
const resolvePageImportDocId = (value = '') => {
|
|
1194
|
+
const resolver = pageImportDocIdResolver.value
|
|
1195
|
+
pageImportDocIdResolver.value = null
|
|
1196
|
+
state.importPageDocIdDialogOpen = false
|
|
1197
|
+
if (resolver)
|
|
1198
|
+
resolver(String(value || '').trim())
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
const requestPageImportConflict = (docId) => {
|
|
1202
|
+
state.importPageConflictDocId = String(docId || '')
|
|
1203
|
+
state.importPageConflictDialogOpen = true
|
|
1204
|
+
return new Promise((resolve) => {
|
|
1205
|
+
pageImportConflictResolver.value = resolve
|
|
1206
|
+
})
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
const resolvePageImportConflict = (action = 'cancel') => {
|
|
1210
|
+
const resolver = pageImportConflictResolver.value
|
|
1211
|
+
pageImportConflictResolver.value = null
|
|
1212
|
+
state.importPageConflictDialogOpen = false
|
|
1213
|
+
if (resolver)
|
|
1214
|
+
resolver(action)
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
const getImportDocId = async (incomingDoc, fallbackDocId = '') => {
|
|
1218
|
+
let nextDocId = String(incomingDoc?.docId || '').trim()
|
|
1219
|
+
if (!nextDocId)
|
|
1220
|
+
nextDocId = await requestPageImportDocId(fallbackDocId)
|
|
1221
|
+
if (!nextDocId)
|
|
1222
|
+
throw new Error('Import canceled. A docId is required.')
|
|
1223
|
+
if (nextDocId.includes('/'))
|
|
1224
|
+
throw new Error('docId cannot include "/".')
|
|
1225
|
+
return nextDocId
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
const openImportErrorDialog = (message) => {
|
|
1229
|
+
state.importPageErrorMessage = String(message || 'Failed to import page.')
|
|
1230
|
+
state.importPageErrorDialogOpen = true
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
const triggerPageImport = () => {
|
|
1234
|
+
pageImportInputRef.value?.click()
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
const importSinglePageFile = async (file, existingPages = {}, fallbackDocId = '') => {
|
|
1238
|
+
const fileText = await readTextFile(file)
|
|
1239
|
+
const parsed = JSON.parse(fileText)
|
|
1240
|
+
const importedDoc = applyImportedPageSeoDefaults(validateImportedPageDoc(normalizeImportedPageDoc(parsed, fallbackDocId)))
|
|
1241
|
+
const incomingDocId = await getImportDocId(importedDoc, fallbackDocId)
|
|
1242
|
+
let targetDocId = incomingDocId
|
|
1243
|
+
let importDecision = 'create'
|
|
1244
|
+
|
|
1245
|
+
if (existingPages[targetDocId]) {
|
|
1246
|
+
const decision = await requestPageImportConflict(targetDocId)
|
|
1247
|
+
if (decision === 'cancel')
|
|
1248
|
+
return
|
|
1249
|
+
if (decision === 'new') {
|
|
1250
|
+
targetDocId = makeRandomPageDocId(existingPages)
|
|
1251
|
+
importedDoc.name = makeImportedPageNameForNew(importedDoc.name || incomingDocId, existingPages)
|
|
1252
|
+
importDecision = 'new'
|
|
1253
|
+
}
|
|
1254
|
+
else {
|
|
1255
|
+
importDecision = 'overwrite'
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
const payload = { ...getPageDocDefaults(), ...importedDoc, docId: targetDocId }
|
|
1260
|
+
await edgeFirebase.storeDoc(pageImportCollectionPath.value, payload, targetDocId)
|
|
1261
|
+
existingPages[targetDocId] = payload
|
|
1262
|
+
addImportedPageToSiteMenu(targetDocId, payload.name)
|
|
1263
|
+
|
|
1264
|
+
if (importDecision === 'overwrite')
|
|
1265
|
+
edgeFirebase?.toast?.success?.(`Overwrote page "${targetDocId}".`)
|
|
1266
|
+
else if (importDecision === 'new')
|
|
1267
|
+
edgeFirebase?.toast?.success?.(`Imported page as new "${targetDocId}".`)
|
|
1268
|
+
else
|
|
1269
|
+
edgeFirebase?.toast?.success?.(`Imported page "${targetDocId}".`)
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
const handlePageImport = async (event) => {
|
|
1273
|
+
const input = event?.target
|
|
1274
|
+
const files = Array.from(input?.files || [])
|
|
1275
|
+
if (!files.length)
|
|
1276
|
+
return
|
|
1277
|
+
|
|
1278
|
+
state.importingPages = true
|
|
1279
|
+
const existingPages = { ...(pages.value || {}) }
|
|
1280
|
+
try {
|
|
1281
|
+
if (!edgeFirebase.data?.[pageImportCollectionPath.value])
|
|
1282
|
+
await edgeFirebase.startSnapshot(pageImportCollectionPath.value)
|
|
1283
|
+
|
|
1284
|
+
for (const file of files) {
|
|
1285
|
+
try {
|
|
1286
|
+
await importSinglePageFile(file, existingPages, '')
|
|
1287
|
+
}
|
|
1288
|
+
catch (error) {
|
|
1289
|
+
console.error('Failed to import page file', error)
|
|
1290
|
+
const message = error?.message || 'Failed to import page file.'
|
|
1291
|
+
if (/^Import canceled\./i.test(message))
|
|
1292
|
+
continue
|
|
1293
|
+
if (error instanceof SyntaxError || message === INVALID_PAGE_IMPORT_MESSAGE)
|
|
1294
|
+
openImportErrorDialog(INVALID_PAGE_IMPORT_MESSAGE)
|
|
1295
|
+
else
|
|
1296
|
+
openImportErrorDialog(message)
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
finally {
|
|
1301
|
+
state.importingPages = false
|
|
1302
|
+
if (input)
|
|
1303
|
+
input.value = ''
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
|
|
928
1307
|
const formatTimestamp = (input) => {
|
|
929
1308
|
if (!input)
|
|
930
1309
|
return 'Not yet saved'
|
|
@@ -978,10 +1357,39 @@ const isPublishedPageDiff = (pageId) => {
|
|
|
978
1357
|
|
|
979
1358
|
const pageStatusLabel = pageId => (isPublishedPageDiff(pageId) ? 'Draft' : 'Published')
|
|
980
1359
|
const hasSelection = computed(() => Boolean(props.page) || Boolean(state.selectedPostId))
|
|
981
|
-
const showSplitView = computed(() => isTemplateSite.value || state.viewMode === 'pages' || hasSelection.value)
|
|
982
|
-
const isEditingPost = computed(() => state.viewMode === 'posts' && Boolean(state.selectedPostId))
|
|
1360
|
+
const showSplitView = computed(() => isTemplateSite.value || (canViewPagesTab.value && (state.viewMode === 'pages' || hasSelection.value)))
|
|
1361
|
+
const isEditingPost = computed(() => canViewPostsTab.value && state.viewMode === 'posts' && Boolean(state.selectedPostId))
|
|
1362
|
+
|
|
1363
|
+
const ensureValidViewMode = () => {
|
|
1364
|
+
let nextMode = state.viewMode
|
|
1365
|
+
if (nextMode === 'pages' && !canViewPagesTab.value)
|
|
1366
|
+
nextMode = defaultViewMode.value
|
|
1367
|
+
if (nextMode === 'posts' && !canViewPostsTab.value)
|
|
1368
|
+
nextMode = defaultViewMode.value
|
|
1369
|
+
if (nextMode === 'submissions' && !canViewInboxTab.value)
|
|
1370
|
+
nextMode = defaultViewMode.value
|
|
1371
|
+
|
|
1372
|
+
if (state.viewMode !== nextMode)
|
|
1373
|
+
state.viewMode = nextMode
|
|
1374
|
+
|
|
1375
|
+
if (state.viewMode !== 'posts') {
|
|
1376
|
+
state.selectedPostId = ''
|
|
1377
|
+
}
|
|
1378
|
+
if (state.viewMode !== 'submissions') {
|
|
1379
|
+
state.selectedSubmissionId = ''
|
|
1380
|
+
}
|
|
1381
|
+
if (props.page && state.viewMode !== 'pages') {
|
|
1382
|
+
router.replace(pageRouteBase.value)
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
983
1385
|
|
|
984
1386
|
const setViewMode = (mode) => {
|
|
1387
|
+
if (mode === 'pages' && !canViewPagesTab.value)
|
|
1388
|
+
return
|
|
1389
|
+
if (mode === 'posts' && !canViewPostsTab.value)
|
|
1390
|
+
return
|
|
1391
|
+
if (mode === 'submissions' && !canViewInboxTab.value)
|
|
1392
|
+
return
|
|
985
1393
|
if (state.viewMode === mode)
|
|
986
1394
|
return
|
|
987
1395
|
state.viewMode = mode
|
|
@@ -995,6 +1403,8 @@ const setViewMode = (mode) => {
|
|
|
995
1403
|
const handlePostSelect = (postId) => {
|
|
996
1404
|
if (!postId)
|
|
997
1405
|
return
|
|
1406
|
+
if (!canViewPostsTab.value)
|
|
1407
|
+
return
|
|
998
1408
|
state.selectedPostId = postId
|
|
999
1409
|
state.viewMode = 'posts'
|
|
1000
1410
|
if (props.page)
|
|
@@ -1005,6 +1415,22 @@ const clearPostSelection = () => {
|
|
|
1005
1415
|
state.selectedPostId = ''
|
|
1006
1416
|
}
|
|
1007
1417
|
|
|
1418
|
+
watch(() => state.importPageDocIdDialogOpen, (open) => {
|
|
1419
|
+
if (!open && pageImportDocIdResolver.value) {
|
|
1420
|
+
const resolver = pageImportDocIdResolver.value
|
|
1421
|
+
pageImportDocIdResolver.value = null
|
|
1422
|
+
resolver('')
|
|
1423
|
+
}
|
|
1424
|
+
})
|
|
1425
|
+
|
|
1426
|
+
watch(() => state.importPageConflictDialogOpen, (open) => {
|
|
1427
|
+
if (!open && pageImportConflictResolver.value) {
|
|
1428
|
+
const resolver = pageImportConflictResolver.value
|
|
1429
|
+
pageImportConflictResolver.value = null
|
|
1430
|
+
resolver('cancel')
|
|
1431
|
+
}
|
|
1432
|
+
})
|
|
1433
|
+
|
|
1008
1434
|
watch (() => siteData.value, () => {
|
|
1009
1435
|
if (isTemplateSite.value)
|
|
1010
1436
|
return
|
|
@@ -1040,14 +1466,33 @@ watch(pages, (pagesCollection) => {
|
|
|
1040
1466
|
watch(() => props.page, (next) => {
|
|
1041
1467
|
if (next) {
|
|
1042
1468
|
state.selectedPostId = ''
|
|
1043
|
-
|
|
1469
|
+
if (canViewPagesTab.value) {
|
|
1470
|
+
state.viewMode = 'pages'
|
|
1471
|
+
}
|
|
1472
|
+
else {
|
|
1473
|
+
state.viewMode = defaultViewMode.value
|
|
1474
|
+
if (props.page)
|
|
1475
|
+
router.replace(pageRouteBase.value)
|
|
1476
|
+
}
|
|
1044
1477
|
return
|
|
1045
1478
|
}
|
|
1046
|
-
if (state.selectedPostId) {
|
|
1479
|
+
if (state.selectedPostId && canViewPostsTab.value) {
|
|
1047
1480
|
state.viewMode = 'posts'
|
|
1481
|
+
return
|
|
1048
1482
|
}
|
|
1483
|
+
ensureValidViewMode()
|
|
1049
1484
|
})
|
|
1050
1485
|
|
|
1486
|
+
watch(cmsTabAccess, () => {
|
|
1487
|
+
ensureValidViewMode()
|
|
1488
|
+
}, { immediate: true, deep: true })
|
|
1489
|
+
|
|
1490
|
+
watch(canEditSiteSettings, (allowed) => {
|
|
1491
|
+
if (!allowed && state.siteSettings) {
|
|
1492
|
+
state.siteSettings = false
|
|
1493
|
+
}
|
|
1494
|
+
}, { immediate: true })
|
|
1495
|
+
|
|
1051
1496
|
watch([isViewingSubmissions, sortedSubmissionIds], () => {
|
|
1052
1497
|
if (!isViewingSubmissions.value)
|
|
1053
1498
|
return
|
|
@@ -1293,7 +1738,7 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1293
1738
|
@update:model-value="value => (slotProps.workingDoc.theme = value || '')"
|
|
1294
1739
|
/>
|
|
1295
1740
|
<edge-shad-select-tags
|
|
1296
|
-
v-if="Object.keys(orgUsers).length > 0"
|
|
1741
|
+
v-if="!cmsMultiOrg && Object.keys(orgUsers).length > 0"
|
|
1297
1742
|
:model-value="getSiteUsersModel(slotProps.workingDoc)"
|
|
1298
1743
|
:disabled="shouldForceCurrentUserForNewSite || !edgeGlobal.isAdminGlobal(edgeFirebase).value"
|
|
1299
1744
|
:items="userOptions"
|
|
@@ -1324,6 +1769,7 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1324
1769
|
</div>
|
|
1325
1770
|
<div class="space-y-3">
|
|
1326
1771
|
<edge-shad-select
|
|
1772
|
+
v-if="!cmsMultiOrg"
|
|
1327
1773
|
:model-value="slotProps.workingDoc.aiAgentUserId || ''"
|
|
1328
1774
|
name="aiAgentUserId"
|
|
1329
1775
|
label="User Data for AI to use to build initial site"
|
|
@@ -1350,16 +1796,20 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1350
1796
|
Only organization admins can create sites.
|
|
1351
1797
|
</div>
|
|
1352
1798
|
<div v-else class="flex flex-col h-[calc(100vh-58px)] overflow-hidden">
|
|
1353
|
-
<div
|
|
1799
|
+
<div
|
|
1800
|
+
class="grid grid-cols-[1fr_auto_1fr] items-center gap-3 px-4 py-2 border bg-secondary"
|
|
1801
|
+
:class="isTemplateSite ? 'min-h-[68px]' : ''"
|
|
1802
|
+
>
|
|
1354
1803
|
<div class="flex items-center gap-3">
|
|
1355
1804
|
<FileStack class="w-5 h-5" />
|
|
1356
|
-
<span class="text-lg font-
|
|
1805
|
+
<span class="text-lg font-normal">
|
|
1357
1806
|
{{ siteData.name || 'Templates' }}
|
|
1358
1807
|
</span>
|
|
1359
1808
|
</div>
|
|
1360
1809
|
<div class="flex justify-center">
|
|
1361
|
-
<div v-if="!isTemplateSite" class="flex items-center rounded-full border border-border bg-background p-1 shadow-sm">
|
|
1810
|
+
<div v-if="!isTemplateSite && (canViewPagesTab || canViewPostsTab || canViewInboxTab)" class="flex items-center rounded-full border border-border bg-background p-1 shadow-sm">
|
|
1362
1811
|
<edge-shad-button
|
|
1812
|
+
v-if="canViewPagesTab"
|
|
1363
1813
|
variant="ghost"
|
|
1364
1814
|
size="sm"
|
|
1365
1815
|
class="h-8 px-4 text-xs gap-2 rounded-full"
|
|
@@ -1370,6 +1820,7 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1370
1820
|
Pages
|
|
1371
1821
|
</edge-shad-button>
|
|
1372
1822
|
<edge-shad-button
|
|
1823
|
+
v-if="canViewPostsTab"
|
|
1373
1824
|
variant="ghost"
|
|
1374
1825
|
size="sm"
|
|
1375
1826
|
class="h-8 px-4 text-xs gap-2 rounded-full"
|
|
@@ -1380,6 +1831,7 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1380
1831
|
Posts
|
|
1381
1832
|
</edge-shad-button>
|
|
1382
1833
|
<edge-shad-button
|
|
1834
|
+
v-if="canViewInboxTab"
|
|
1383
1835
|
variant="ghost"
|
|
1384
1836
|
size="sm"
|
|
1385
1837
|
class="h-8 px-4 text-xs gap-2 rounded-full"
|
|
@@ -1397,76 +1849,98 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1397
1849
|
</edge-shad-button>
|
|
1398
1850
|
</div>
|
|
1399
1851
|
</div>
|
|
1400
|
-
<div
|
|
1401
|
-
<
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1852
|
+
<div class="flex items-center gap-3 justify-end">
|
|
1853
|
+
<input
|
|
1854
|
+
ref="pageImportInputRef"
|
|
1855
|
+
type="file"
|
|
1856
|
+
multiple
|
|
1857
|
+
accept=".json,application/json"
|
|
1858
|
+
class="hidden"
|
|
1859
|
+
@change="handlePageImport"
|
|
1860
|
+
>
|
|
1861
|
+
<edge-shad-button
|
|
1862
|
+
type="button"
|
|
1863
|
+
size="icon"
|
|
1864
|
+
variant="outline"
|
|
1865
|
+
class="h-9 w-9"
|
|
1866
|
+
:disabled="state.importingPages"
|
|
1867
|
+
title="Import Page"
|
|
1868
|
+
aria-label="Import Page"
|
|
1869
|
+
@click="triggerPageImport"
|
|
1870
|
+
>
|
|
1871
|
+
<Loader2 v-if="state.importingPages" class="h-3.5 w-3.5 animate-spin" />
|
|
1872
|
+
<Upload v-else class="h-3.5 w-3.5" />
|
|
1873
|
+
</edge-shad-button>
|
|
1874
|
+
<template v-if="!isTemplateSite && !hidePublishStatusAndActions">
|
|
1875
|
+
<Transition name="fade" mode="out-in">
|
|
1876
|
+
<div v-if="isSiteDiff || isAnyPagesDiff" key="unpublished" class="flex gap-2 items-center">
|
|
1877
|
+
<div class="flex gap-1 items-center bg-yellow-100 text-xs py-1 px-3 text-yellow-800 rounded">
|
|
1878
|
+
<CircleAlert class="!text-yellow-800 w-3 h-6" />
|
|
1879
|
+
<span class="font-medium text-[10px]">
|
|
1880
|
+
{{ isSiteDiff ? (useMenuPublishLabels ? 'Unpublished Menu' : 'Unpublished Settings') : 'Unpublished Pages' }}
|
|
1881
|
+
</span>
|
|
1882
|
+
</div>
|
|
1883
|
+
<edge-shad-button
|
|
1884
|
+
class="h-8 px-4 text-xs gap-2 bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm"
|
|
1885
|
+
:disabled="state.publishSiteLoading"
|
|
1886
|
+
@click="publishSiteAndSettings"
|
|
1887
|
+
>
|
|
1888
|
+
<Loader2 v-if="state.publishSiteLoading" class="h-3.5 w-3.5 animate-spin" />
|
|
1889
|
+
<FolderUp v-else class="h-3.5 w-3.5" />
|
|
1890
|
+
Publish Site
|
|
1891
|
+
</edge-shad-button>
|
|
1892
|
+
</div>
|
|
1893
|
+
<div v-else key="published" class="flex gap-1 items-center bg-green-100 text-xs py-1 px-3 text-green-800 rounded">
|
|
1894
|
+
<FileCheck class="!text-green-800 w-3 h-6" />
|
|
1405
1895
|
<span class="font-medium text-[10px]">
|
|
1406
|
-
{{
|
|
1896
|
+
{{ useMenuPublishLabels ? 'Menu Published' : 'Settings Published' }}
|
|
1407
1897
|
</span>
|
|
1408
1898
|
</div>
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
<
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
<DropdownMenuItem v-if="isAnyPagesDiff" @click="publishSite">
|
|
1452
|
-
<FolderUp />
|
|
1453
|
-
Publish All Pages
|
|
1454
|
-
</DropdownMenuItem>
|
|
1455
|
-
<DropdownMenuItem v-if="isSiteSettingPublished || isAnyPagesPublished" @click="unPublishSite">
|
|
1456
|
-
<FolderDown />
|
|
1457
|
-
Unpublish Site
|
|
1458
|
-
</DropdownMenuItem>
|
|
1459
|
-
|
|
1460
|
-
<DropdownMenuItem @click="state.siteSettings = true">
|
|
1461
|
-
<FolderCog />
|
|
1462
|
-
<span>Settings</span>
|
|
1463
|
-
</DropdownMenuItem>
|
|
1464
|
-
</DropdownMenuContent>
|
|
1465
|
-
</DropdownMenu>
|
|
1899
|
+
</Transition>
|
|
1900
|
+
<DropdownMenu>
|
|
1901
|
+
<DropdownMenuTrigger as-child>
|
|
1902
|
+
<edge-shad-button variant="outline" size="icon" class="h-9 w-9">
|
|
1903
|
+
<MoreHorizontal />
|
|
1904
|
+
</edge-shad-button>
|
|
1905
|
+
</DropdownMenuTrigger>
|
|
1906
|
+
<DropdownMenuContent side="right" align="start">
|
|
1907
|
+
<DropdownMenuLabel class="flex items-center gap-2">
|
|
1908
|
+
<FileStack class="w-5 h-5" />{{ siteData.name || 'Templates' }}
|
|
1909
|
+
</DropdownMenuLabel>
|
|
1910
|
+
|
|
1911
|
+
<DropdownMenuSeparator v-if="isSiteDiff" />
|
|
1912
|
+
<DropdownMenuLabel v-if="isSiteDiff" class="flex items-center gap-2">
|
|
1913
|
+
Site Settings
|
|
1914
|
+
</DropdownMenuLabel>
|
|
1915
|
+
|
|
1916
|
+
<DropdownMenuItem v-if="isSiteDiff" class="pl-4 text-xs" @click="publishSiteSettings">
|
|
1917
|
+
<FolderUp />
|
|
1918
|
+
Publish
|
|
1919
|
+
</DropdownMenuItem>
|
|
1920
|
+
<DropdownMenuItem v-if="isSiteDiff && isSiteSettingPublished" class="pl-4 text-xs" @click="discardSiteSettings">
|
|
1921
|
+
<FolderX />
|
|
1922
|
+
Discard Changes
|
|
1923
|
+
</DropdownMenuItem>
|
|
1924
|
+
<DropdownMenuSeparator />
|
|
1925
|
+
<DropdownMenuItem v-if="isAnyPagesDiff" @click="publishSite">
|
|
1926
|
+
<FolderUp />
|
|
1927
|
+
Publish All Pages
|
|
1928
|
+
</DropdownMenuItem>
|
|
1929
|
+
<DropdownMenuItem v-if="isSiteSettingPublished || isAnyPagesPublished" @click="unPublishSite">
|
|
1930
|
+
<FolderDown />
|
|
1931
|
+
Unpublish Site
|
|
1932
|
+
</DropdownMenuItem>
|
|
1933
|
+
|
|
1934
|
+
<DropdownMenuItem v-if="canEditSiteSettings" @click="state.siteSettings = true">
|
|
1935
|
+
<FolderCog />
|
|
1936
|
+
<span>Settings</span>
|
|
1937
|
+
</DropdownMenuItem>
|
|
1938
|
+
</DropdownMenuContent>
|
|
1939
|
+
</DropdownMenu>
|
|
1940
|
+
</template>
|
|
1466
1941
|
</div>
|
|
1467
|
-
<div v-else />
|
|
1468
1942
|
</div>
|
|
1469
|
-
<div class="flex-1">
|
|
1943
|
+
<div class="flex-1 min-h-0">
|
|
1470
1944
|
<Transition name="fade" mode="out-in">
|
|
1471
1945
|
<div v-if="isViewingSubmissions" class="flex-1 overflow-y-auto p-6">
|
|
1472
1946
|
<edge-dashboard
|
|
@@ -1616,12 +2090,12 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1616
2090
|
@update:selected-post-id="clearPostSelection"
|
|
1617
2091
|
/>
|
|
1618
2092
|
</div>
|
|
1619
|
-
<ResizablePanelGroup v-else-if="showSplitView" direction="horizontal" class="w-full h-full flex-1">
|
|
1620
|
-
<ResizablePanel class="bg-
|
|
1621
|
-
<SidebarGroup class="mt-0 pt-0">
|
|
1622
|
-
<SidebarGroupContent>
|
|
1623
|
-
<SidebarMenu>
|
|
1624
|
-
<template v-if="isTemplateSite || state.viewMode === 'pages'">
|
|
2093
|
+
<ResizablePanelGroup v-else-if="showSplitView" direction="horizontal" class="w-full h-full flex-1 min-h-0">
|
|
2094
|
+
<ResizablePanel class="bg-primary-foreground text-black min-h-0 overflow-hidden" :default-size="16">
|
|
2095
|
+
<SidebarGroup class="mt-0 pt-0 h-full min-h-0">
|
|
2096
|
+
<SidebarGroupContent class="h-full min-h-0 overflow-y-auto">
|
|
2097
|
+
<SidebarMenu class="pb-4">
|
|
2098
|
+
<template v-if="isTemplateSite || (canViewPagesTab && state.viewMode === 'pages')">
|
|
1625
2099
|
<edge-cms-menu
|
|
1626
2100
|
v-if="state.menus"
|
|
1627
2101
|
v-model="state.menus"
|
|
@@ -1645,7 +2119,7 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1645
2119
|
</SidebarGroupContent>
|
|
1646
2120
|
</SidebarGroup>
|
|
1647
2121
|
</ResizablePanel>
|
|
1648
|
-
<ResizablePanel ref="mainPanel">
|
|
2122
|
+
<ResizablePanel ref="mainPanel" class="min-h-0">
|
|
1649
2123
|
<Transition name="fade" mode="out-in">
|
|
1650
2124
|
<div v-if="props.page && !state.updating" :key="props.page" class="max-h-[calc(100vh-100px)] overflow-y-auto w-full">
|
|
1651
2125
|
<NuxtPage class="flex flex-col flex-1 px-0 mx-0 pt-0" />
|
|
@@ -1672,7 +2146,73 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1672
2146
|
</Transition>
|
|
1673
2147
|
</div>
|
|
1674
2148
|
</div>
|
|
1675
|
-
<
|
|
2149
|
+
<edge-shad-dialog v-model="state.importPageDocIdDialogOpen">
|
|
2150
|
+
<DialogContent class="pt-8">
|
|
2151
|
+
<DialogHeader>
|
|
2152
|
+
<DialogTitle class="text-left">
|
|
2153
|
+
Enter Page Doc ID
|
|
2154
|
+
</DialogTitle>
|
|
2155
|
+
<DialogDescription>
|
|
2156
|
+
This file does not include a <code>docId</code>. Enter the doc ID you want to import into this site.
|
|
2157
|
+
</DialogDescription>
|
|
2158
|
+
</DialogHeader>
|
|
2159
|
+
<edge-shad-input
|
|
2160
|
+
v-model="state.importPageDocIdValue"
|
|
2161
|
+
name="site-page-import-doc-id"
|
|
2162
|
+
label="Doc ID"
|
|
2163
|
+
placeholder="example-page-id"
|
|
2164
|
+
/>
|
|
2165
|
+
<DialogFooter class="pt-2 flex justify-between">
|
|
2166
|
+
<edge-shad-button variant="outline" @click="resolvePageImportDocId('')">
|
|
2167
|
+
Cancel
|
|
2168
|
+
</edge-shad-button>
|
|
2169
|
+
<edge-shad-button @click="resolvePageImportDocId(state.importPageDocIdValue)">
|
|
2170
|
+
Continue
|
|
2171
|
+
</edge-shad-button>
|
|
2172
|
+
</DialogFooter>
|
|
2173
|
+
</DialogContent>
|
|
2174
|
+
</edge-shad-dialog>
|
|
2175
|
+
<edge-shad-dialog v-model="state.importPageConflictDialogOpen">
|
|
2176
|
+
<DialogContent class="pt-8">
|
|
2177
|
+
<DialogHeader>
|
|
2178
|
+
<DialogTitle class="text-left">
|
|
2179
|
+
Page Already Exists
|
|
2180
|
+
</DialogTitle>
|
|
2181
|
+
<DialogDescription>
|
|
2182
|
+
<code>{{ state.importPageConflictDocId }}</code> already exists in this {{ isTemplateSite ? 'template library' : 'site' }}. Choose to overwrite it or import as a new page.
|
|
2183
|
+
</DialogDescription>
|
|
2184
|
+
</DialogHeader>
|
|
2185
|
+
<DialogFooter class="pt-2 flex justify-between">
|
|
2186
|
+
<edge-shad-button variant="outline" @click="resolvePageImportConflict('cancel')">
|
|
2187
|
+
Cancel
|
|
2188
|
+
</edge-shad-button>
|
|
2189
|
+
<edge-shad-button variant="outline" @click="resolvePageImportConflict('new')">
|
|
2190
|
+
Add As New
|
|
2191
|
+
</edge-shad-button>
|
|
2192
|
+
<edge-shad-button @click="resolvePageImportConflict('overwrite')">
|
|
2193
|
+
Overwrite
|
|
2194
|
+
</edge-shad-button>
|
|
2195
|
+
</DialogFooter>
|
|
2196
|
+
</DialogContent>
|
|
2197
|
+
</edge-shad-dialog>
|
|
2198
|
+
<edge-shad-dialog v-model="state.importPageErrorDialogOpen">
|
|
2199
|
+
<DialogContent class="pt-8">
|
|
2200
|
+
<DialogHeader>
|
|
2201
|
+
<DialogTitle class="text-left">
|
|
2202
|
+
Import Failed
|
|
2203
|
+
</DialogTitle>
|
|
2204
|
+
<DialogDescription class="text-left">
|
|
2205
|
+
{{ state.importPageErrorMessage }}
|
|
2206
|
+
</DialogDescription>
|
|
2207
|
+
</DialogHeader>
|
|
2208
|
+
<DialogFooter class="pt-2">
|
|
2209
|
+
<edge-shad-button @click="state.importPageErrorDialogOpen = false">
|
|
2210
|
+
Close
|
|
2211
|
+
</edge-shad-button>
|
|
2212
|
+
</DialogFooter>
|
|
2213
|
+
</DialogContent>
|
|
2214
|
+
</edge-shad-dialog>
|
|
2215
|
+
<Sheet v-if="canEditSiteSettings" v-model:open="state.siteSettings">
|
|
1676
2216
|
<SheetContent side="left" class="w-full md:w-1/2 max-w-none sm:max-w-none max-w-2xl">
|
|
1677
2217
|
<SheetHeader>
|
|
1678
2218
|
<SheetTitle>{{ siteData.name || 'Site' }}</SheetTitle>
|
|
@@ -1697,7 +2237,7 @@ const pageSettingsUpdated = async (pageData) => {
|
|
|
1697
2237
|
:theme-options="themeOptions"
|
|
1698
2238
|
:user-options="userOptions"
|
|
1699
2239
|
:has-users="Object.keys(orgUsers).length > 0"
|
|
1700
|
-
:show-users="
|
|
2240
|
+
:show-users="!cmsMultiOrg"
|
|
1701
2241
|
:show-theme-fields="true"
|
|
1702
2242
|
:is-admin="isAdmin"
|
|
1703
2243
|
:enable-media-picker="true"
|