diff --git a/server/controllers/common.js b/server/controllers/common.js
index 21f4b21f..7c7312bb 100644
--- a/server/controllers/common.js
+++ b/server/controllers/common.js
@@ -153,6 +153,11 @@ router.get(['/d', '/d/*'], async (req, res, next) => {
*/
router.get(['/_edit', '/_edit/*'], async (req, res, next) => {
const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
+ const site = await WIKI.db.sites.getSiteByHostname({ hostname: req.hostname })
+
+ if (!site) {
+ throw new Error('INVALID_SITE')
+ }
if (pageArgs.path === '') {
return res.redirect(`/_edit/home`)
@@ -175,10 +180,10 @@ router.get(['/_edit', '/_edit/*'], async (req, res, next) => {
// -> Get page data from DB
let page = await WIKI.db.pages.getPageFromDb({
+ siteId: site.id,
path: pageArgs.path,
locale: pageArgs.locale,
- userId: req.user.id,
- isPrivate: false
+ userId: req.user.id
})
pageArgs.tags = _.get(page, 'tags', [])
@@ -415,6 +420,11 @@ router.get('/*', async (req, res, next) => {
const stripExt = _.some(WIKI.data.pageExtensions, ext => _.endsWith(req.path, `.${ext}`))
const pageArgs = pageHelper.parsePath(req.path, { stripExt })
const isPage = (stripExt || pageArgs.path.indexOf('.') === -1)
+ const site = await WIKI.db.sites.getSiteByHostname({ hostname: req.hostname })
+
+ if (!site) {
+ throw new Error('INVALID_SITE')
+ }
if (isPage) {
// if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
@@ -426,6 +436,7 @@ router.get('/*', async (req, res, next) => {
try {
// -> Get Page from cache
const page = await WIKI.db.pages.getPage({
+ siteId: site.id,
path: pageArgs.path,
locale: pageArgs.locale,
userId: req.user.id
@@ -470,67 +481,8 @@ router.get('/*', async (req, res, next) => {
})
}
- // -> Build sidebar navigation
- let sdi = 1
- const sidebar = (await WIKI.db.navigation.getTree({ cache: true, locale: pageArgs.locale, groups: req.user.groups })).map(n => ({
- i: `sdi-${sdi++}`,
- k: n.kind,
- l: n.label,
- c: n.icon,
- y: n.targetType,
- t: n.target
- }))
-
- // -> Build theme code injection
- const injectCode = {
- css: '', // WIKI.config.theming.injectCSS,
- head: '', // WIKI.config.theming.injectHead,
- body: '' // WIKI.config.theming.injectBody
- }
-
- // Handle missing extra field
- page.extra = page.extra || { css: '', js: '' }
-
- if (!_.isEmpty(page.extra.css)) {
- injectCode.css = `${injectCode.css}\n${page.extra.css}`
- }
-
- if (!_.isEmpty(page.extra.js)) {
- injectCode.body = `${injectCode.body}\n${page.extra.js}`
- }
-
- // -> Convert page TOC
- if (!_.isString(page.toc)) {
- page.toc = JSON.stringify(page.toc)
- }
-
- // -> Inject comments variables
- const commentTmpl = {
- codeTemplate: '', // WIKI.data.commentProvider.codeTemplate,
- head: '', // WIKI.data.commentProvider.head,
- body: '', // WIKI.data.commentProvider.body,
- main: '' // WIKI.data.commentProvider.main
- }
- if (false && WIKI.config.features.featurePageComments && WIKI.data.commentProvider.codeTemplate) {
- [
- { key: 'pageUrl', value: `${WIKI.config.host}/i/${page.id}` },
- { key: 'pageId', value: page.id }
- ].forEach((cfg) => {
- commentTmpl.head = _.replace(commentTmpl.head, new RegExp(`{{${cfg.key}}}`, 'g'), cfg.value)
- commentTmpl.body = _.replace(commentTmpl.body, new RegExp(`{{${cfg.key}}}`, 'g'), cfg.value)
- commentTmpl.main = _.replace(commentTmpl.main, new RegExp(`{{${cfg.key}}}`, 'g'), cfg.value)
- })
- }
-
// -> Render view
res.sendFile(path.join(WIKI.ROOTPATH, 'assets/index.html'))
- // res.render('page', {
- // page,
- // sidebar,
- // injectCode,
- // comments: commentTmpl,
- // effectivePermissions
- // })
} else if (pageArgs.path === 'home') {
res.redirect('/_welcome')
} else {
diff --git a/server/graph/resolvers/page.js b/server/graph/resolvers/page.js
index 09710808..524e0898 100644
--- a/server/graph/resolvers/page.js
+++ b/server/graph/resolvers/page.js
@@ -166,7 +166,10 @@ module.exports = {
*/
async pageByPath (obj, args, context, info) {
const pageArgs = pageHelper.parsePath(args.path)
- let page = await WIKI.db.pages.getPageFromDb(pageArgs)
+ let page = await WIKI.db.pages.getPageFromDb({
+ ...pageArgs,
+ siteId: args.siteId
+ })
if (page) {
return {
...page,
diff --git a/server/graph/schemas/page.graphql b/server/graph/schemas/page.graphql
index 3d300cfe..29086992 100644
--- a/server/graph/schemas/page.graphql
+++ b/server/graph/schemas/page.graphql
@@ -35,6 +35,7 @@ extend type Query {
): Page
pageByPath(
+ siteId: UUID!
path: String!
): Page
@@ -173,7 +174,7 @@ type Page {
tags: [PageTag]
content: String
render: String
- toc: String
+ toc: [JSON]
contentType: String
createdAt: Date
updatedAt: Date
diff --git a/server/models/pages.js b/server/models/pages.js
index 3c374497..24964c1f 100644
--- a/server/models/pages.js
+++ b/server/models/pages.js
@@ -1010,6 +1010,7 @@ module.exports = class Page extends Model {
.where(queryModeID ? {
'pages.id': opts
} : {
+ 'pages.siteId': opts.siteId,
'pages.path': opts.path,
'pages.localeCode': opts.locale
})
diff --git a/server/tasks/workers/render-page.js b/server/tasks/workers/render-page.js
index 6c23cbf5..4a8e4278 100644
--- a/server/tasks/workers/render-page.js
+++ b/server/tasks/workers/render-page.js
@@ -62,8 +62,8 @@ module.exports = async ({ payload }) => {
$('.toc-anchor', el).remove()
_.get(toc, leafPath).push({
- title: _.trim($(el).text()),
- anchor: leafSlug,
+ label: _.trim($(el).text()),
+ key: leafSlug.substring(1),
children: []
})
})
diff --git a/ux/src/components/PageDataDialog.vue b/ux/src/components/PageDataDialog.vue
index ee4b8777..f23a5139 100644
--- a/ux/src/components/PageDataDialog.vue
+++ b/ux/src/components/PageDataDialog.vue
@@ -1,7 +1,7 @@
q-card.page-data-dialog(style='width: 750px;')
q-toolbar.bg-primary.text-white.flex
- .text-subtitle2 {{$t('editor.pageData.title')}}
+ .text-subtitle2 {{t('editor.pageData.title')}}
q-space
q-btn(
icon='las la-times'
@@ -10,13 +10,13 @@ q-card.page-data-dialog(style='width: 750px;')
v-close-popup
)
q-card-section.page-data-dialog-selector
- //- .text-overline.text-white {{$t('editor.pageData.template')}}
+ //- .text-overline.text-white {{t('editor.pageData.template')}}
.flex.q-gutter-sm
q-select(
dark
- v-model='templateId'
- :label='$t(`editor.pageData.template`)'
- :aria-label='$t(`editor.pageData.template`)'
+ v-model='state.templateId'
+ :label='t(`editor.pageData.template`)'
+ :aria-label='t(`editor.pageData.template`)'
:options='templates'
option-value='id'
map-options
@@ -28,14 +28,14 @@ q-card.page-data-dialog(style='width: 750px;')
q-btn.acrylic-btn(
dark
icon='las la-pen'
- :label='$t(`common.actions.manage`)'
+ :label='t(`common.actions.manage`)'
unelevated
no-caps
color='deep-orange-9'
@click='editTemplates'
)
q-tabs.alt-card(
- v-model='mode'
+ v-model='state.mode'
inline-label
no-caps
)
@@ -48,11 +48,11 @@ q-card.page-data-dialog(style='width: 750px;')
label='YAML'
)
q-scroll-area(
- :thumb-style='thumbStyle'
- :bar-style='barStyle'
+ :thumb-style='siteStore.thumbStyle'
+ :bar-style='siteStore.barStyle'
style='height: calc(100% - 50px - 75px - 48px);'
)
- q-card-section(v-if='mode === `visual`')
+ q-card-section(v-if='state.mode === `visual`')
.q-gutter-sm
q-input(
label='Attribute Text'
@@ -76,60 +76,69 @@ q-card.page-data-dialog(style='width: 750px;')
dense
size='lg'
)
- q-no-ssr(v-else, :placeholder='$t(`common.loading`)')
+ q-no-ssr(v-else, :placeholder='t(`common.loading`)')
codemirror.admin-theme-cm(
ref='cmData'
- v-model='content'
+ v-model='state.content'
:options='{ mode: `text/yaml` }'
)
q-dialog(
- v-model='showDataTemplateDialog'
+ v-model='state.showDataTemplateDialog'
)
page-data-template-dialog
-
diff --git a/ux/src/components/PageDataTemplateDialog.vue b/ux/src/components/PageDataTemplateDialog.vue
index c78d9774..1f43dba0 100644
--- a/ux/src/components/PageDataTemplateDialog.vue
+++ b/ux/src/components/PageDataTemplateDialog.vue
@@ -1,7 +1,7 @@
q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
q-toolbar.bg-primary.text-white
- .text-subtitle2 {{$t('editor.pageData.manageTemplates')}}
+ .text-subtitle2 {{t('editor.pageData.manageTemplates')}}
q-space
q-btn(
icon='las la-times'
@@ -12,10 +12,10 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
q-card-section.page-datatmpl-selector
.flex.q-gutter-md
q-select.col(
- v-model='selectedTemplateId'
- :options='templates'
+ v-model='state.selectedTemplateId'
+ :options='siteStore.pageDataTemplates'
standout
- :label='$t(`editor.pageData.template`)'
+ :label='t(`editor.pageData.template`)'
dense
dark
option-value='id'
@@ -24,23 +24,23 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
)
q-btn(
icon='las la-plus'
- :label='$t(`common.actions.new`)'
+ :label='t(`common.actions.new`)'
unelevated
color='primary'
no-caps
@click='create'
)
- .row(v-if='tmpl')
+ .row(v-if='state.tmpl')
.col-auto.page-datatmpl-sd
.q-pa-md
q-btn.acrylic-btn.full-width(
- :label='$t(`common.actions.howItWorks`)'
+ :label='t(`common.actions.howItWorks`)'
icon='las la-question-circle'
flat
color='pink'
no-caps
)
- q-item-label(header, style='margin-top: 2px;') {{$t('editor.pageData.templateFullRowTypes')}}
+ q-item-label(header, style='margin-top: 2px;') {{t('editor.pageData.templateFullRowTypes')}}
.q-px-md
draggable(
class='q-list rounded-borders'
@@ -49,8 +49,8 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
:clone='cloneFieldType'
:sort='false'
:animation='150'
- @start='dragStarted = true'
- @end='dragStarted = false'
+ @start='state.dragStarted = true'
+ @end='state.dragStarted = false'
item-key='id'
)
template(#item='{element}')
@@ -59,7 +59,7 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
q-icon(:name='element.icon', color='primary')
q-item-section
q-item-label {{element.label}}
- q-item-label(header) {{$t('editor.pageData.templateKeyValueTypes')}}
+ q-item-label(header) {{t('editor.pageData.templateKeyValueTypes')}}
.q-px-md.q-pb-md
draggable(
class='q-list rounded-borders'
@@ -68,8 +68,8 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
:clone='cloneFieldType'
:sort='false'
:animation='150'
- @start='dragStarted = true'
- @end='dragStarted = false'
+ @start='state.dragStarted = true'
+ @end='state.dragStarted = false'
item-key='id'
)
template(#item='{element}')
@@ -81,21 +81,21 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
.col.page-datatmpl-content
q-scroll-area(
ref='scrollArea'
- :thumb-style='thumbStyle'
- :bar-style='barStyle'
+ :thumb-style='siteStore.thumbStyle'
+ :bar-style='siteStore.barStyle'
style='height: 100%;'
)
.col.page-datatmpl-meta.q-px-md.q-py-md.flex.q-gutter-md
q-input.col(
ref='tmplTitleIpt'
- :label='$t(`editor.pageData.templateTitle`)'
+ :label='t(`editor.pageData.templateTitle`)'
outlined
dense
- v-model='tmpl.label'
+ v-model='state.tmpl.label'
)
q-btn.acrylic-btn(
icon='las la-check'
- :label='$t(`common.actions.commit`)'
+ :label='t(`common.actions.commit`)'
no-caps
flat
color='positive'
@@ -103,22 +103,22 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
)
q-btn.acrylic-btn(
icon='las la-trash'
- :aria-label='$t(`common.actions.delete`)'
+ :aria-label='t(`common.actions.delete`)'
flat
color='negative'
@click='remove'
)
- q-item-label(header) {{$t('editor.pageData.templateStructure')}}
+ q-item-label(header) {{t('editor.pageData.templateStructure')}}
.q-px-md.q-pb-md
- div(:class='(dragStarted || tmpl.data.length < 1 ? `page-datatmpl-box` : ``)')
- .text-caption.text-primary.q-pa-md(v-if='tmpl.data.length < 1 && !dragStarted'): em {{$t('editor.pageData.dragDropHint')}}
+ div(:class='(state.dragStarted || state.tmpl.data.length < 1 ? `page-datatmpl-box` : ``)')
+ .text-caption.text-primary.q-pa-md(v-if='state.tmpl.data.length < 1 && !state.dragStarted'): em {{t('editor.pageData.dragDropHint')}}
draggable(
class='q-list rounded-borders'
- :list='tmpl.data'
+ :list='state.tmpl.data'
group='shared'
:animation='150'
handle='.handle'
- @end='dragStarted = false'
+ @end='state.dragStarted = false'
item-key='id'
)
template(#item='{element}')
@@ -129,14 +129,14 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
q-icon(:name='element.icon', color='primary')
q-item-section
q-input(
- :label='$t(`editor.pageData.label`)'
+ :label='t(`editor.pageData.label`)'
v-model='element.label'
outlined
dense
)
q-item-section(v-if='element.type !== `header`')
q-input(
- :label='$t(`editor.pageData.uniqueKey`)'
+ :label='t(`editor.pageData.uniqueKey`)'
v-model='element.key'
outlined
dense
@@ -144,7 +144,7 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
q-item-section(side)
q-btn.acrylic-btn(
color='negative'
- :aria-label='$t(`common.actions.delete`)'
+ :aria-label='t(`common.actions.delete`)'
padding='xs'
icon='las la-times'
flat
@@ -152,171 +152,194 @@ q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
)
.page-datatmpl-scrollend(ref='scrollAreaEnd')
- .q-pa-md.text-center(v-else-if='templates.length > 0')
- em.text-grey-6 {{$t('editor.pageData.selectTemplateAbove')}}
+ .q-pa-md.text-center(v-else-if='siteStore.pageDataTemplates.length > 0')
+ em.text-grey-6 {{t('editor.pageData.selectTemplateAbove')}}
.q-pa-md.text-center(v-else)
- em.text-grey-6 {{$t('editor.pageData.noTemplate')}}
+ em.text-grey-6 {{t('editor.pageData.noTemplate')}}
-
diff --git a/ux/src/stores/page.js b/ux/src/stores/page.js
index 5d2242fa..24a3b541 100644
--- a/ux/src/stores/page.js
+++ b/ux/src/stores/page.js
@@ -80,7 +80,8 @@ export const usePageStore = defineStore('page', {
},
commentsCount: 0,
content: '',
- render: ''
+ render: '',
+ toc: []
}),
getters: {},
actions: {
@@ -93,9 +94,11 @@ export const usePageStore = defineStore('page', {
const resp = await APOLLO_CLIENT.query({
query: gql`
query loadPage (
+ $siteId: UUID!
$path: String!
) {
pageByPath(
+ siteId: $siteId
path: $path
) {
id
@@ -105,10 +108,12 @@ export const usePageStore = defineStore('page', {
locale
updatedAt
render
+ toc
}
}
`,
variables: {
+ siteId: siteStore.id,
path
},
fetchPolicy: 'network-only'