feat: rename / move page + code styling fixes

vega
NGPixel 2 days ago
parent 7425a74b6a
commit d9523fe393
No known key found for this signature in database
GPG Key ID: B755FB6870B30F63

@ -86,7 +86,7 @@ export default {
// -> Add Highlighting if enabled // -> Add Highlighting if enabled
if (WIKI.config.search.termHighlighting && hasQuery) { if (WIKI.config.search.termHighlighting && hasQuery) {
searchCols.push(WIKI.db.knex.raw(`ts_headline(?, "searchContent", query, 'MaxWords=5, MinWords=3, MaxFragments=5') AS highlight`, [dictName])) searchCols.push(WIKI.db.knex.raw('ts_headline(?, "searchContent", query, \'MaxWords=5, MinWords=3, MaxFragments=5\') AS highlight', [dictName]))
} }
const results = await WIKI.db.knex const results = await WIKI.db.knex
@ -408,7 +408,7 @@ export default {
* CHECK FOR EDITING CONFLICT * CHECK FOR EDITING CONFLICT
*/ */
async checkConflicts (obj, args, context, info) { async checkConflicts (obj, args, context, info) {
let page = await WIKI.db.pages.query().select('path', 'locale', 'updatedAt').findById(args.id) const page = await WIKI.db.pages.query().select('path', 'locale', 'updatedAt').findById(args.id)
if (page) { if (page) {
if (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], { if (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], {
path: page.path, path: page.path,
@ -426,7 +426,7 @@ export default {
* FETCH LATEST VERSION FOR CONFLICT COMPARISON * FETCH LATEST VERSION FOR CONFLICT COMPARISON
*/ */
async checkConflictsLatest (obj, args, context, info) { async checkConflictsLatest (obj, args, context, info) {
let page = await WIKI.db.pages.getPageFromDb(args.id) const page = await WIKI.db.pages.getPageFromDb(args.id)
if (page) { if (page) {
if (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], { if (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], {
path: page.path, path: page.path,
@ -449,7 +449,7 @@ export default {
/** /**
* CREATE PAGE * CREATE PAGE
*/ */
async createPage(obj, args, context) { async createPage (obj, args, context) {
try { try {
const page = await WIKI.db.pages.createPage({ const page = await WIKI.db.pages.createPage({
...args, ...args,
@ -466,7 +466,7 @@ export default {
/** /**
* UPDATE PAGE * UPDATE PAGE
*/ */
async updatePage(obj, args, context) { async updatePage (obj, args, context) {
try { try {
const page = await WIKI.db.pages.updatePage({ const page = await WIKI.db.pages.updatePage({
...args, ...args,
@ -483,7 +483,7 @@ export default {
/** /**
* CONVERT PAGE * CONVERT PAGE
*/ */
async convertPage(obj, args, context) { async convertPage (obj, args, context) {
try { try {
await WIKI.db.pages.convertPage({ await WIKI.db.pages.convertPage({
...args, ...args,
@ -497,9 +497,9 @@ export default {
} }
}, },
/** /**
* RENAME PAGE * MOVE PAGE
*/ */
async renamePage(obj, args, context) { async movePage (obj, args, context) {
try { try {
await WIKI.db.pages.movePage({ await WIKI.db.pages.movePage({
...args, ...args,
@ -515,7 +515,7 @@ export default {
/** /**
* DELETE PAGE * DELETE PAGE
*/ */
async deletePage(obj, args, context) { async deletePage (obj, args, context) {
try { try {
await WIKI.db.pages.deletePage({ await WIKI.db.pages.deletePage({
...args, ...args,
@ -571,7 +571,7 @@ export default {
/** /**
* FLUSH PAGE CACHE * FLUSH PAGE CACHE
*/ */
async flushCache(obj, args, context) { async flushCache (obj, args, context) {
try { try {
await WIKI.db.pages.flushCache() await WIKI.db.pages.flushCache()
WIKI.events.outbound.emit('flushCache') WIKI.events.outbound.emit('flushCache')
@ -585,7 +585,7 @@ export default {
/** /**
* MIGRATE ALL PAGES FROM SOURCE LOCALE TO TARGET LOCALE * MIGRATE ALL PAGES FROM SOURCE LOCALE TO TARGET LOCALE
*/ */
async migrateToLocale(obj, args, context) { async migrateToLocale (obj, args, context) {
try { try {
const count = await WIKI.db.pages.migrateToLocale(args) const count = await WIKI.db.pages.migrateToLocale(args)
return { return {
@ -599,7 +599,7 @@ export default {
/** /**
* REBUILD TREE * REBUILD TREE
*/ */
async rebuildPageTree(obj, args, context) { async rebuildPageTree (obj, args, context) {
try { try {
await WIKI.db.pages.rebuildTree() await WIKI.db.pages.rebuildTree()
return { return {

@ -162,10 +162,11 @@ extend type Mutation {
editor: String! editor: String!
): DefaultResponse ): DefaultResponse
renamePage( movePage(
id: Int! id: UUID!
destinationPath: String!
destinationLocale: String! destinationLocale: String!
destinationPath: String!
title: String
): DefaultResponse ): DefaultResponse
deletePage( deletePage(

@ -1,5 +1,5 @@
import { Model } from 'objection' import { Model } from 'objection'
import { find, get, has, initial, isEmpty, isString, last, pick } from 'lodash-es' import { cloneDeep, find, get, has, initial, isEmpty, isString, last, pick } from 'lodash-es'
import { Type as JSBinType } from 'js-binary' import { Type as JSBinType } from 'js-binary'
import { getDictNameFromLocale } from '../helpers/common.mjs' import { getDictNameFromLocale } from '../helpers/common.mjs'
import { generateHash, getFileExtension, injectPageMetadata } from '../helpers/page.mjs' import { generateHash, getFileExtension, injectPageMetadata } from '../helpers/page.mjs'
@ -888,15 +888,10 @@ export class Page extends Model {
* @returns {Promise} Promise with no value * @returns {Promise} Promise with no value
*/ */
static async movePage (opts) { static async movePage (opts) {
let page if (!has(opts, 'id')) {
if (has(opts, 'id')) { throw new Error('Missing page ID')
page = await WIKI.db.pages.query().findById(opts.id)
} else {
page = await WIKI.db.pages.query().findOne({
path: opts.path,
locale: opts.locale
})
} }
const page = await WIKI.db.pages.query().findById(opts.id)
if (!page) { if (!page) {
throw new WIKI.Error.PageNotFound() throw new WIKI.Error.PageNotFound()
} }
@ -947,63 +942,83 @@ export class Page extends Model {
versionDate: page.updatedAt versionDate: page.updatedAt
}) })
const destinationHash = generateHash({ path: opts.destinationPath, locale: opts.destinationLocale }) // -> Update page object
const updatedPage = cloneDeep(page)
updatedPage.path = opts.destinationPath
updatedPage.locale = opts.destinationLocale
updatedPage.title = opts.title ?? page.title
updatedPage.hash = generateHash({ path: opts.destinationPath, locale: opts.destinationLocale })
updatedPage.authorId = opts.user.id
// -> Move page // -> Move page
const destinationTitle = (page.title === page.path ? opts.destinationPath : page.title)
await WIKI.db.pages.query().patch({ await WIKI.db.pages.query().patch({
path: opts.destinationPath, path: updatedPage.path,
locale: opts.destinationLocale, locale: updatedPage.locale,
title: destinationTitle, title: updatedPage.title,
hash: destinationHash hash: updatedPage.hash,
authorId: updatedPage.authorId
}).findById(page.id) }).findById(page.id)
await WIKI.db.pages.deletePageFromCache(page.hash) await WIKI.db.pages.deletePageFromCache(page.hash)
WIKI.events.outbound.emit('deletePageFromCache', page.hash) WIKI.events.outbound.emit('deletePageFromCache', page.hash)
// -> Rebuild page tree // -> Replace tree node
await WIKI.db.pages.rebuildTree() const pathParts = updatedPage.path.split('/')
await WIKI.db.knex('tree').where('id', page.id).del()
await WIKI.db.tree.addPage({
id: page.id,
parentPath: initial(pathParts).join('/'),
fileName: last(pathParts),
locale: updatedPage.locale,
title: updatedPage.title,
tags: updatedPage.tags,
meta: {
authorId: updatedPage.authorId,
contentType: updatedPage.contentType,
creatorId: updatedPage.creatorId,
description: updatedPage.description,
isBrowsable: updatedPage.isBrowsable,
ownerId: updatedPage.ownerId,
publishState: updatedPage.publishState,
publishEndDate: updatedPage.publishEndDate,
publishStartDate: updatedPage.publishStartDate
},
siteId: updatedPage.siteId
})
// -> Rename in Search Index // -> Rename in Search Index
const pageContents = await WIKI.db.pages.query().findById(page.id).select('render') WIKI.db.pages.updatePageSearchVector({ id: page.id })
page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render)
await WIKI.data.searchEngine.renamed({
...page,
destinationPath: opts.destinationPath,
destinationLocale: opts.destinationLocale,
destinationHash
})
// -> Rename in Storage // -> Rename in Storage
if (!opts.skipStorage) { if (!opts.skipStorage) {
await WIKI.db.storage.pageEvent({ // await WIKI.db.storage.pageEvent({
event: 'renamed', // event: 'renamed',
page: { // page: {
...page, // ...page,
destinationPath: opts.destinationPath, // destinationPath: updatedPage.path,
destinationLocale: opts.destinationLocale, // destinationLocale: updatedPage.locale,
destinationHash, // destinationHash: updatedPage.hash,
moveAuthorId: opts.user.id, // moveAuthorId: opts.user.id,
moveAuthorName: opts.user.name, // moveAuthorName: opts.user.name,
moveAuthorEmail: opts.user.email // moveAuthorEmail: opts.user.email
} // }
}) // })
} }
// -> Reconnect Links : Changing old links to the new path // // -> Reconnect Links : Changing old links to the new path
await WIKI.db.pages.reconnectLinks({ // await WIKI.db.pages.reconnectLinks({
sourceLocale: page.locale, // sourceLocale: page.locale,
sourcePath: page.path, // sourcePath: page.path,
locale: opts.destinationLocale, // locale: opts.destinationLocale,
path: opts.destinationPath, // path: opts.destinationPath,
mode: 'move' // mode: 'move'
}) // })
// -> Reconnect Links : Validate invalid links to the new path // // -> Reconnect Links : Validate invalid links to the new path
await WIKI.db.pages.reconnectLinks({ // await WIKI.db.pages.reconnectLinks({
locale: opts.destinationLocale, // locale: opts.destinationLocale,
path: opts.destinationPath, // path: opts.destinationPath,
mode: 'create' // mode: 'create'
}) // })
} }
/** /**

@ -17,7 +17,7 @@ const reTitle = /^[^<>"]+$/
* Tree model * Tree model
*/ */
export class Tree extends Model { export class Tree extends Model {
static get tableName() { return 'tree' } static get tableName () { return 'tree' }
static get jsonSchema () { static get jsonSchema () {
return { return {
@ -25,22 +25,22 @@ export class Tree extends Model {
required: ['fileName'], required: ['fileName'],
properties: { properties: {
id: {type: 'string'}, id: { type: 'string' },
folderPath: {type: 'string'}, folderPath: { type: 'string' },
fileName: {type: 'string'}, fileName: { type: 'string' },
type: {type: 'string'}, type: { type: 'string' },
title: {type: 'string'}, title: { type: 'string' },
createdAt: {type: 'string'}, createdAt: { type: 'string' },
updatedAt: {type: 'string'} updatedAt: { type: 'string' }
} }
} }
} }
static get jsonAttributes() { static get jsonAttributes () {
return ['meta'] return ['meta']
} }
static get relationMappings() { static get relationMappings () {
return { return {
site: { site: {
relation: Model.BelongsToOneRelation, relation: Model.BelongsToOneRelation,
@ -53,10 +53,11 @@ export class Tree extends Model {
} }
} }
$beforeUpdate() { $beforeUpdate () {
this.updatedAt = new Date().toISOString() this.updatedAt = new Date().toISOString()
} }
$beforeInsert() {
$beforeInsert () {
this.createdAt = new Date().toISOString() this.createdAt = new Date().toISOString()
this.updatedAt = new Date().toISOString() this.updatedAt = new Date().toISOString()
} }
@ -90,7 +91,7 @@ export class Tree extends Model {
const parent = await WIKI.db.knex('tree').where({ const parent = await WIKI.db.knex('tree').where({
...parentFilter, ...parentFilter,
type: 'folder', type: 'folder',
locale: locale, locale,
siteId siteId
}).first() }).first()
if (parent) { if (parent) {
@ -123,13 +124,15 @@ export class Tree extends Model {
* @param {Object} [args.meta] - Extra metadata * @param {Object} [args.meta] - Extra metadata
*/ */
static async addPage ({ id, parentId, parentPath, fileName, title, locale, siteId, tags = [], meta = {} }) { static async addPage ({ id, parentId, parentPath, fileName, title, locale, siteId, tags = [], meta = {} }) {
const folder = (parentId || parentPath) ? await WIKI.db.tree.getFolder({ const folder = (parentId || parentPath)
? await WIKI.db.tree.getFolder({
id: parentId, id: parentId,
path: parentPath, path: parentPath,
locale, locale,
siteId, siteId,
createIfMissing: true createIfMissing: true
}) : { })
: {
folderPath: '', folderPath: '',
fileName: '' fileName: ''
} }
@ -143,9 +146,9 @@ export class Tree extends Model {
folderPath: encodeFolderPath(folderPath), folderPath: encodeFolderPath(folderPath),
fileName, fileName,
type: 'page', type: 'page',
title: title, title,
hash: generateHash(fullPath), hash: generateHash(fullPath),
locale: locale, locale,
siteId, siteId,
tags, tags,
meta, meta,
@ -169,13 +172,15 @@ export class Tree extends Model {
* @param {Object} [args.meta] - Extra metadata * @param {Object} [args.meta] - Extra metadata
*/ */
static async addAsset ({ id, parentId, parentPath, fileName, title, locale, siteId, tags = [], meta = {} }) { static async addAsset ({ id, parentId, parentPath, fileName, title, locale, siteId, tags = [], meta = {} }) {
const folder = (parentId || parentPath) ? await WIKI.db.tree.getFolder({ const folder = (parentId || parentPath)
? await WIKI.db.tree.getFolder({
id: parentId, id: parentId,
path: parentPath, path: parentPath,
locale, locale,
siteId, siteId,
createIfMissing: true createIfMissing: true
}) : { })
: {
folderPath: '', folderPath: '',
fileName: '' fileName: ''
} }
@ -189,9 +194,9 @@ export class Tree extends Model {
folderPath: encodeFolderPath(folderPath), folderPath: encodeFolderPath(folderPath),
fileName, fileName,
type: 'asset', type: 'asset',
title: title, title,
hash: generateHash(fullPath), hash: generateHash(fullPath),
locale: locale, locale,
siteId, siteId,
tags, tags,
meta meta
@ -246,8 +251,8 @@ export class Tree extends Model {
// Check for collision // Check for collision
const existingFolder = await WIKI.db.knex('tree').select('id').where({ const existingFolder = await WIKI.db.knex('tree').select('id').where({
siteId: siteId, siteId,
locale: locale, locale,
folderPath: encodeFolderPath(parentPath), folderPath: encodeFolderPath(parentPath),
fileName: pathName, fileName: pathName,
type: 'folder' type: 'folder'
@ -281,8 +286,8 @@ export class Tree extends Model {
type: 'folder', type: 'folder',
title: ancestor.fileName, title: ancestor.fileName,
hash: generateHash(newAncestorFullPath), hash: generateHash(newAncestorFullPath),
locale: locale, locale,
siteId: siteId, siteId,
meta: { meta: {
children: 1 children: 1
} }
@ -301,10 +306,10 @@ export class Tree extends Model {
folderPath: encodeFolderPath(parentPath), folderPath: encodeFolderPath(parentPath),
fileName: pathName, fileName: pathName,
type: 'folder', type: 'folder',
title: title, title,
hash: generateHash(fullPath), hash: generateHash(fullPath),
locale: locale, locale,
siteId: siteId, siteId,
meta: { meta: {
children: 0 children: 0
} }
@ -383,13 +388,13 @@ export class Tree extends Model {
const fullPath = folder.folderPath ? `${decodeFolderPath(folder.folderPath)}/${pathName}` : pathName const fullPath = folder.folderPath ? `${decodeFolderPath(folder.folderPath)}/${pathName}` : pathName
await WIKI.db.knex('tree').where('id', folder.id).update({ await WIKI.db.knex('tree').where('id', folder.id).update({
fileName: pathName, fileName: pathName,
title: title, title,
hash: generateHash(fullPath) hash: generateHash(fullPath)
}) })
} else { } else {
// Update the folder title only // Update the folder title only
await WIKI.db.knex('tree').where('id', folder.id).update({ await WIKI.db.knex('tree').where('id', folder.id).update({
title: title title
}) })
} }

@ -244,8 +244,27 @@ function renamePage () {
itemTitle: pageStore.title, itemTitle: pageStore.title,
itemFileName: pageStore.path itemFileName: pageStore.path
} }
}).onOk(() => { }).onOk(async (renamedPageOpts) => {
// TODO: change route to new location try {
if (renamedPageOpts.path === pageStore.path) {
await pageStore.pageRename({ id: pageStore.id, title: renamedPageOpts.title })
$q.notify({
type: 'positive',
message: 'Page renamed successfully.'
})
} else {
await pageStore.pageMove({ id: pageStore.id, path: renamedPageOpts.path, title: renamedPageOpts.title })
$q.notify({
type: 'positive',
message: 'Page moved successfully.'
})
}
} catch (err) {
$q.notify({
type: 'negative',
message: err.message
})
}
}) })
} }

@ -65,6 +65,8 @@ q-dialog(ref='dialogRef', @hide='onDialogHide')
outlined outlined
@focus='state.pathDirty = true; state.currentFileId = null' @focus='state.pathDirty = true; state.currentFileId = null'
) )
//- template(#append)
//- q-badge(outline, color='grey', label='valid')
q-card-actions.card-actions.q-px-md q-card-actions.card-actions.q-px-md
q-btn.acrylic-btn( q-btn.acrylic-btn(
icon='las la-ellipsis-h' icon='las la-ellipsis-h'
@ -408,10 +410,19 @@ onMounted(() => {
fName = last(fParts) fName = last(fParts)
} }
switch (props.mode) { switch (props.mode) {
case 'pageSave': { case 'savePage': {
state.typesToFetch = ['folder', 'page'] state.typesToFetch = ['folder', 'page']
break break
} }
case 'duplicatePage': {
state.typesToFetch = ['folder', 'page']
break
}
case 'renamePage': {
state.typesToFetch = ['folder', 'page']
state.pathDirty = true
break
}
} }
loadTree({ loadTree({
parentPath: fPath, parentPath: fPath,

@ -452,6 +452,83 @@ export const usePageStore = defineStore('page', {
editor: this.editor editor: this.editor
}) })
}, },
/**
* PAGE - MOVE
*/
async pageMove ({ id, title, path } = {}) {
const resp = await APOLLO_CLIENT.mutate({
mutation: gql`
mutation movePage (
$id: UUID!
$destinationLocale: String!
$destinationPath: String!
$title: String
) {
movePage (
id: $id
destinationLocale: $destinationLocale
destinationPath: $destinationPath
title: $title
) {
operation {
succeeded
message
}
}
}
`,
variables: {
id,
destinationLocale: this.locale,
destinationPath: path,
title
}
})
const result = resp?.data?.movePage?.operation ?? {}
if (!result.succeeded) {
throw new Error(result.message)
} else {
this.router.replace(`/${path}`)
}
},
/**
* PAGE - Rename
*/
async pageRename ({ id, title } = {}) {
const resp = await APOLLO_CLIENT.mutate({
mutation: gql`
mutation renamePage (
$id: UUID!
$patch: PageUpdateInput!
) {
updatePage (
id: $id
patch: $patch
) {
operation {
succeeded
message
}
}
}
`,
variables: {
id: id,
patch: {
title
}
}
})
const result = resp?.data?.updatePage?.operation ?? {}
if (!result.succeeded) {
throw new Error(result.message)
}
// Update page store
if (id === this.id) {
this.$patch({ title })
}
},
/** /**
* PAGE SAVE * PAGE SAVE
*/ */

Loading…
Cancel
Save