mirror of
https://github.com/requarks/wiki.git
synced 2026-08-26 13:17:10 -05:00
feat: rename / move page + code styling fixes
This commit is contained in:
@@ -86,7 +86,7 @@ export default {
|
||||
|
||||
// -> Add Highlighting if enabled
|
||||
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
|
||||
@@ -408,7 +408,7 @@ export default {
|
||||
* CHECK FOR EDITING CONFLICT
|
||||
*/
|
||||
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 (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], {
|
||||
path: page.path,
|
||||
@@ -426,7 +426,7 @@ export default {
|
||||
* FETCH LATEST VERSION FOR CONFLICT COMPARISON
|
||||
*/
|
||||
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 (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], {
|
||||
path: page.path,
|
||||
@@ -449,7 +449,7 @@ export default {
|
||||
/**
|
||||
* CREATE PAGE
|
||||
*/
|
||||
async createPage(obj, args, context) {
|
||||
async createPage (obj, args, context) {
|
||||
try {
|
||||
const page = await WIKI.db.pages.createPage({
|
||||
...args,
|
||||
@@ -466,7 +466,7 @@ export default {
|
||||
/**
|
||||
* UPDATE PAGE
|
||||
*/
|
||||
async updatePage(obj, args, context) {
|
||||
async updatePage (obj, args, context) {
|
||||
try {
|
||||
const page = await WIKI.db.pages.updatePage({
|
||||
...args,
|
||||
@@ -483,7 +483,7 @@ export default {
|
||||
/**
|
||||
* CONVERT PAGE
|
||||
*/
|
||||
async convertPage(obj, args, context) {
|
||||
async convertPage (obj, args, context) {
|
||||
try {
|
||||
await WIKI.db.pages.convertPage({
|
||||
...args,
|
||||
@@ -497,9 +497,9 @@ export default {
|
||||
}
|
||||
},
|
||||
/**
|
||||
* RENAME PAGE
|
||||
* MOVE PAGE
|
||||
*/
|
||||
async renamePage(obj, args, context) {
|
||||
async movePage (obj, args, context) {
|
||||
try {
|
||||
await WIKI.db.pages.movePage({
|
||||
...args,
|
||||
@@ -515,7 +515,7 @@ export default {
|
||||
/**
|
||||
* DELETE PAGE
|
||||
*/
|
||||
async deletePage(obj, args, context) {
|
||||
async deletePage (obj, args, context) {
|
||||
try {
|
||||
await WIKI.db.pages.deletePage({
|
||||
...args,
|
||||
@@ -571,7 +571,7 @@ export default {
|
||||
/**
|
||||
* FLUSH PAGE CACHE
|
||||
*/
|
||||
async flushCache(obj, args, context) {
|
||||
async flushCache (obj, args, context) {
|
||||
try {
|
||||
await WIKI.db.pages.flushCache()
|
||||
WIKI.events.outbound.emit('flushCache')
|
||||
@@ -585,7 +585,7 @@ export default {
|
||||
/**
|
||||
* MIGRATE ALL PAGES FROM SOURCE LOCALE TO TARGET LOCALE
|
||||
*/
|
||||
async migrateToLocale(obj, args, context) {
|
||||
async migrateToLocale (obj, args, context) {
|
||||
try {
|
||||
const count = await WIKI.db.pages.migrateToLocale(args)
|
||||
return {
|
||||
@@ -599,7 +599,7 @@ export default {
|
||||
/**
|
||||
* REBUILD TREE
|
||||
*/
|
||||
async rebuildPageTree(obj, args, context) {
|
||||
async rebuildPageTree (obj, args, context) {
|
||||
try {
|
||||
await WIKI.db.pages.rebuildTree()
|
||||
return {
|
||||
|
||||
@@ -162,10 +162,11 @@ extend type Mutation {
|
||||
editor: String!
|
||||
): DefaultResponse
|
||||
|
||||
renamePage(
|
||||
id: Int!
|
||||
destinationPath: String!
|
||||
movePage(
|
||||
id: UUID!
|
||||
destinationLocale: String!
|
||||
destinationPath: String!
|
||||
title: String
|
||||
): DefaultResponse
|
||||
|
||||
deletePage(
|
||||
|
||||
+66
-51
@@ -1,5 +1,5 @@
|
||||
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 { getDictNameFromLocale } from '../helpers/common.mjs'
|
||||
import { generateHash, getFileExtension, injectPageMetadata } from '../helpers/page.mjs'
|
||||
@@ -888,15 +888,10 @@ export class Page extends Model {
|
||||
* @returns {Promise} Promise with no value
|
||||
*/
|
||||
static async movePage (opts) {
|
||||
let page
|
||||
if (has(opts, 'id')) {
|
||||
page = await WIKI.db.pages.query().findById(opts.id)
|
||||
} else {
|
||||
page = await WIKI.db.pages.query().findOne({
|
||||
path: opts.path,
|
||||
locale: opts.locale
|
||||
})
|
||||
if (!has(opts, 'id')) {
|
||||
throw new Error('Missing page ID')
|
||||
}
|
||||
const page = await WIKI.db.pages.query().findById(opts.id)
|
||||
if (!page) {
|
||||
throw new WIKI.Error.PageNotFound()
|
||||
}
|
||||
@@ -947,63 +942,83 @@ export class Page extends Model {
|
||||
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
|
||||
const destinationTitle = (page.title === page.path ? opts.destinationPath : page.title)
|
||||
await WIKI.db.pages.query().patch({
|
||||
path: opts.destinationPath,
|
||||
locale: opts.destinationLocale,
|
||||
title: destinationTitle,
|
||||
hash: destinationHash
|
||||
path: updatedPage.path,
|
||||
locale: updatedPage.locale,
|
||||
title: updatedPage.title,
|
||||
hash: updatedPage.hash,
|
||||
authorId: updatedPage.authorId
|
||||
}).findById(page.id)
|
||||
await WIKI.db.pages.deletePageFromCache(page.hash)
|
||||
WIKI.events.outbound.emit('deletePageFromCache', page.hash)
|
||||
|
||||
// -> Rebuild page tree
|
||||
await WIKI.db.pages.rebuildTree()
|
||||
// -> Replace tree node
|
||||
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
|
||||
const pageContents = await WIKI.db.pages.query().findById(page.id).select('render')
|
||||
page.safeContent = WIKI.db.pages.cleanHTML(pageContents.render)
|
||||
await WIKI.data.searchEngine.renamed({
|
||||
...page,
|
||||
destinationPath: opts.destinationPath,
|
||||
destinationLocale: opts.destinationLocale,
|
||||
destinationHash
|
||||
})
|
||||
WIKI.db.pages.updatePageSearchVector({ id: page.id })
|
||||
|
||||
// -> Rename in Storage
|
||||
if (!opts.skipStorage) {
|
||||
await WIKI.db.storage.pageEvent({
|
||||
event: 'renamed',
|
||||
page: {
|
||||
...page,
|
||||
destinationPath: opts.destinationPath,
|
||||
destinationLocale: opts.destinationLocale,
|
||||
destinationHash,
|
||||
moveAuthorId: opts.user.id,
|
||||
moveAuthorName: opts.user.name,
|
||||
moveAuthorEmail: opts.user.email
|
||||
}
|
||||
})
|
||||
// await WIKI.db.storage.pageEvent({
|
||||
// event: 'renamed',
|
||||
// page: {
|
||||
// ...page,
|
||||
// destinationPath: updatedPage.path,
|
||||
// destinationLocale: updatedPage.locale,
|
||||
// destinationHash: updatedPage.hash,
|
||||
// moveAuthorId: opts.user.id,
|
||||
// moveAuthorName: opts.user.name,
|
||||
// moveAuthorEmail: opts.user.email
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
// -> Reconnect Links : Changing old links to the new path
|
||||
await WIKI.db.pages.reconnectLinks({
|
||||
sourceLocale: page.locale,
|
||||
sourcePath: page.path,
|
||||
locale: opts.destinationLocale,
|
||||
path: opts.destinationPath,
|
||||
mode: 'move'
|
||||
})
|
||||
// // -> Reconnect Links : Changing old links to the new path
|
||||
// await WIKI.db.pages.reconnectLinks({
|
||||
// sourceLocale: page.locale,
|
||||
// sourcePath: page.path,
|
||||
// locale: opts.destinationLocale,
|
||||
// path: opts.destinationPath,
|
||||
// mode: 'move'
|
||||
// })
|
||||
|
||||
// -> Reconnect Links : Validate invalid links to the new path
|
||||
await WIKI.db.pages.reconnectLinks({
|
||||
locale: opts.destinationLocale,
|
||||
path: opts.destinationPath,
|
||||
mode: 'create'
|
||||
})
|
||||
// // -> Reconnect Links : Validate invalid links to the new path
|
||||
// await WIKI.db.pages.reconnectLinks({
|
||||
// locale: opts.destinationLocale,
|
||||
// path: opts.destinationPath,
|
||||
// mode: 'create'
|
||||
// })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+51
-46
@@ -17,7 +17,7 @@ const reTitle = /^[^<>"]+$/
|
||||
* Tree model
|
||||
*/
|
||||
export class Tree extends Model {
|
||||
static get tableName() { return 'tree' }
|
||||
static get tableName () { return 'tree' }
|
||||
|
||||
static get jsonSchema () {
|
||||
return {
|
||||
@@ -25,22 +25,22 @@ export class Tree extends Model {
|
||||
required: ['fileName'],
|
||||
|
||||
properties: {
|
||||
id: {type: 'string'},
|
||||
folderPath: {type: 'string'},
|
||||
fileName: {type: 'string'},
|
||||
type: {type: 'string'},
|
||||
title: {type: 'string'},
|
||||
createdAt: {type: 'string'},
|
||||
updatedAt: {type: 'string'}
|
||||
id: { type: 'string' },
|
||||
folderPath: { type: 'string' },
|
||||
fileName: { type: 'string' },
|
||||
type: { type: 'string' },
|
||||
title: { type: 'string' },
|
||||
createdAt: { type: 'string' },
|
||||
updatedAt: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static get jsonAttributes() {
|
||||
static get jsonAttributes () {
|
||||
return ['meta']
|
||||
}
|
||||
|
||||
static get relationMappings() {
|
||||
static get relationMappings () {
|
||||
return {
|
||||
site: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
@@ -53,10 +53,11 @@ export class Tree extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
$beforeUpdate() {
|
||||
$beforeUpdate () {
|
||||
this.updatedAt = new Date().toISOString()
|
||||
}
|
||||
$beforeInsert() {
|
||||
|
||||
$beforeInsert () {
|
||||
this.createdAt = 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({
|
||||
...parentFilter,
|
||||
type: 'folder',
|
||||
locale: locale,
|
||||
locale,
|
||||
siteId
|
||||
}).first()
|
||||
if (parent) {
|
||||
@@ -123,16 +124,18 @@ export class Tree extends Model {
|
||||
* @param {Object} [args.meta] - Extra metadata
|
||||
*/
|
||||
static async addPage ({ id, parentId, parentPath, fileName, title, locale, siteId, tags = [], meta = {} }) {
|
||||
const folder = (parentId || parentPath) ? await WIKI.db.tree.getFolder({
|
||||
id: parentId,
|
||||
path: parentPath,
|
||||
locale,
|
||||
siteId,
|
||||
createIfMissing: true
|
||||
}) : {
|
||||
folderPath: '',
|
||||
fileName: ''
|
||||
}
|
||||
const folder = (parentId || parentPath)
|
||||
? await WIKI.db.tree.getFolder({
|
||||
id: parentId,
|
||||
path: parentPath,
|
||||
locale,
|
||||
siteId,
|
||||
createIfMissing: true
|
||||
})
|
||||
: {
|
||||
folderPath: '',
|
||||
fileName: ''
|
||||
}
|
||||
const folderPath = folder.folderPath ? `${folder.folderPath}.${folder.fileName}` : folder.fileName
|
||||
const fullPath = folderPath ? `${folderPath}/${fileName}` : fileName
|
||||
|
||||
@@ -143,9 +146,9 @@ export class Tree extends Model {
|
||||
folderPath: encodeFolderPath(folderPath),
|
||||
fileName,
|
||||
type: 'page',
|
||||
title: title,
|
||||
title,
|
||||
hash: generateHash(fullPath),
|
||||
locale: locale,
|
||||
locale,
|
||||
siteId,
|
||||
tags,
|
||||
meta,
|
||||
@@ -169,16 +172,18 @@ export class Tree extends Model {
|
||||
* @param {Object} [args.meta] - Extra metadata
|
||||
*/
|
||||
static async addAsset ({ id, parentId, parentPath, fileName, title, locale, siteId, tags = [], meta = {} }) {
|
||||
const folder = (parentId || parentPath) ? await WIKI.db.tree.getFolder({
|
||||
id: parentId,
|
||||
path: parentPath,
|
||||
locale,
|
||||
siteId,
|
||||
createIfMissing: true
|
||||
}) : {
|
||||
folderPath: '',
|
||||
fileName: ''
|
||||
}
|
||||
const folder = (parentId || parentPath)
|
||||
? await WIKI.db.tree.getFolder({
|
||||
id: parentId,
|
||||
path: parentPath,
|
||||
locale,
|
||||
siteId,
|
||||
createIfMissing: true
|
||||
})
|
||||
: {
|
||||
folderPath: '',
|
||||
fileName: ''
|
||||
}
|
||||
const folderPath = folder.folderPath ? `${folder.folderPath}.${folder.fileName}` : folder.fileName
|
||||
const fullPath = folderPath ? `${folderPath}/${fileName}` : fileName
|
||||
|
||||
@@ -189,9 +194,9 @@ export class Tree extends Model {
|
||||
folderPath: encodeFolderPath(folderPath),
|
||||
fileName,
|
||||
type: 'asset',
|
||||
title: title,
|
||||
title,
|
||||
hash: generateHash(fullPath),
|
||||
locale: locale,
|
||||
locale,
|
||||
siteId,
|
||||
tags,
|
||||
meta
|
||||
@@ -246,8 +251,8 @@ export class Tree extends Model {
|
||||
|
||||
// Check for collision
|
||||
const existingFolder = await WIKI.db.knex('tree').select('id').where({
|
||||
siteId: siteId,
|
||||
locale: locale,
|
||||
siteId,
|
||||
locale,
|
||||
folderPath: encodeFolderPath(parentPath),
|
||||
fileName: pathName,
|
||||
type: 'folder'
|
||||
@@ -281,8 +286,8 @@ export class Tree extends Model {
|
||||
type: 'folder',
|
||||
title: ancestor.fileName,
|
||||
hash: generateHash(newAncestorFullPath),
|
||||
locale: locale,
|
||||
siteId: siteId,
|
||||
locale,
|
||||
siteId,
|
||||
meta: {
|
||||
children: 1
|
||||
}
|
||||
@@ -301,10 +306,10 @@ export class Tree extends Model {
|
||||
folderPath: encodeFolderPath(parentPath),
|
||||
fileName: pathName,
|
||||
type: 'folder',
|
||||
title: title,
|
||||
title,
|
||||
hash: generateHash(fullPath),
|
||||
locale: locale,
|
||||
siteId: siteId,
|
||||
locale,
|
||||
siteId,
|
||||
meta: {
|
||||
children: 0
|
||||
}
|
||||
@@ -383,13 +388,13 @@ export class Tree extends Model {
|
||||
const fullPath = folder.folderPath ? `${decodeFolderPath(folder.folderPath)}/${pathName}` : pathName
|
||||
await WIKI.db.knex('tree').where('id', folder.id).update({
|
||||
fileName: pathName,
|
||||
title: title,
|
||||
title,
|
||||
hash: generateHash(fullPath)
|
||||
})
|
||||
} else {
|
||||
// Update the folder title only
|
||||
await WIKI.db.knex('tree').where('id', folder.id).update({
|
||||
title: title
|
||||
title
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -244,8 +244,27 @@ function renamePage () {
|
||||
itemTitle: pageStore.title,
|
||||
itemFileName: pageStore.path
|
||||
}
|
||||
}).onOk(() => {
|
||||
// TODO: change route to new location
|
||||
}).onOk(async (renamedPageOpts) => {
|
||||
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
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,9 @@ q-dialog(ref='dialogRef', @hide='onDialogHide')
|
||||
dense
|
||||
outlined
|
||||
@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-btn.acrylic-btn(
|
||||
icon='las la-ellipsis-h'
|
||||
@@ -408,10 +410,19 @@ onMounted(() => {
|
||||
fName = last(fParts)
|
||||
}
|
||||
switch (props.mode) {
|
||||
case 'pageSave': {
|
||||
case 'savePage': {
|
||||
state.typesToFetch = ['folder', 'page']
|
||||
break
|
||||
}
|
||||
case 'duplicatePage': {
|
||||
state.typesToFetch = ['folder', 'page']
|
||||
break
|
||||
}
|
||||
case 'renamePage': {
|
||||
state.typesToFetch = ['folder', 'page']
|
||||
state.pathDirty = true
|
||||
break
|
||||
}
|
||||
}
|
||||
loadTree({
|
||||
parentPath: fPath,
|
||||
|
||||
@@ -452,6 +452,83 @@ export const usePageStore = defineStore('page', {
|
||||
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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user