feat: history version diff
This commit is contained in:
parent
27ff329d16
commit
95f01cdeb8
@ -3,7 +3,7 @@
|
|||||||
nav-header
|
nav-header
|
||||||
v-content
|
v-content
|
||||||
v-toolbar(color='primary', dark)
|
v-toolbar(color='primary', dark)
|
||||||
.subheading Viewing history of page #[strong /{{path}}]
|
.subheading Viewing history of #[strong /{{path}}]
|
||||||
v-spacer
|
v-spacer
|
||||||
.caption.blue--text.text--lighten-3.mr-4 Trail Length: {{total}}
|
.caption.blue--text.text--lighten-3.mr-4 Trail Length: {{total}}
|
||||||
.caption.blue--text.text--lighten-3 ID: {{pageId}}
|
.caption.blue--text.text--lighten-3 ID: {{pageId}}
|
||||||
@ -42,12 +42,12 @@
|
|||||||
template(v-slot:activator='{ on }')
|
template(v-slot:activator='{ on }')
|
||||||
v-btn.mr-2.radius-4(icon, v-on='on', small, tile): v-icon mdi-dots-horizontal
|
v-btn.mr-2.radius-4(icon, v-on='on', small, tile): v-icon mdi-dots-horizontal
|
||||||
v-list(dense, nav).history-promptmenu
|
v-list(dense, nav).history-promptmenu
|
||||||
v-list-item(@click='setDiffTarget(ph.versionId)')
|
|
||||||
v-list-item-avatar(size='24'): v-icon mdi-call-received
|
|
||||||
v-list-item-title Set as Differencing Target (B)
|
|
||||||
v-list-item(@click='setDiffSource(ph.versionId)')
|
v-list-item(@click='setDiffSource(ph.versionId)')
|
||||||
v-list-item-avatar(size='24'): v-icon mdi-call-made
|
v-list-item-avatar(size='24'): v-icon mdi-call-made
|
||||||
v-list-item-title Set as Differencing Source (A)
|
v-list-item-title Set as Differencing Source (A)
|
||||||
|
v-list-item(@click='setDiffTarget(ph.versionId)')
|
||||||
|
v-list-item-avatar(size='24'): v-icon mdi-call-received
|
||||||
|
v-list-item-title Set as Differencing Target (B)
|
||||||
v-list-item
|
v-list-item
|
||||||
v-list-item-avatar(size='24'): v-icon mdi-code-tags
|
v-list-item-avatar(size='24'): v-icon mdi-code-tags
|
||||||
v-list-item-title View Source
|
v-list-item-title View Source
|
||||||
@ -94,7 +94,7 @@
|
|||||||
) End of history trail
|
) End of history trail
|
||||||
|
|
||||||
v-flex(xs12, md8)
|
v-flex(xs12, md8)
|
||||||
v-card.radius-7
|
v-card.radius-7.mt-8
|
||||||
v-card-text
|
v-card-text
|
||||||
v-card.grey.radius-7(flat, :class='darkMode ? `darken-2` : `lighten-4`')
|
v-card.grey.radius-7(flat, :class='darkMode ? `darken-2` : `lighten-4`')
|
||||||
v-row(no-gutters, align='center')
|
v-row(no-gutters, align='center')
|
||||||
@ -118,8 +118,7 @@ import * as Diff2Html from 'diff2html'
|
|||||||
import { createPatch } from 'diff'
|
import { createPatch } from 'diff'
|
||||||
import { get } from 'vuex-pathify'
|
import { get } from 'vuex-pathify'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import gql from 'graphql-tag'
|
||||||
import historyTrailQuery from 'gql/history/history-trail-query.gql'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
@ -140,14 +139,16 @@ export default {
|
|||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
source: {
|
source: {
|
||||||
|
versionId: 0,
|
||||||
content: '',
|
content: '',
|
||||||
title: '',
|
title: '',
|
||||||
description: ''
|
description: ''
|
||||||
},
|
},
|
||||||
target: {
|
target: {
|
||||||
|
versionId: 0,
|
||||||
content: '',
|
content: '',
|
||||||
title: '',
|
title: '',
|
||||||
description: ''
|
description: ''
|
||||||
@ -157,15 +158,16 @@ export default {
|
|||||||
diffTarget: 0,
|
diffTarget: 0,
|
||||||
offsetPage: 0,
|
offsetPage: 0,
|
||||||
total: 0,
|
total: 0,
|
||||||
viewMode: 'line-by-line'
|
viewMode: 'line-by-line',
|
||||||
|
cache: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
darkMode: get('site/dark'),
|
darkMode: get('site/dark'),
|
||||||
diffs() {
|
diffs () {
|
||||||
return createPatch(`/${this.path}`, this.source.content, this.target.content)
|
return createPatch(`/${this.path}`, this.source.content, this.target.content)
|
||||||
},
|
},
|
||||||
diffHTML() {
|
diffHTML () {
|
||||||
return Diff2Html.html(this.diffs, {
|
return Diff2Html.html(this.diffs, {
|
||||||
inputFormat: 'diff',
|
inputFormat: 'diff',
|
||||||
drawFileList: false,
|
drawFileList: false,
|
||||||
@ -175,11 +177,31 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
trail(newValue, oldValue) {
|
trail (newValue, oldValue) {
|
||||||
if (newValue && newValue.length > 0) {
|
if (newValue && newValue.length > 0) {
|
||||||
this.diffTarget = _.get(_.head(newValue), 'versionId', 0)
|
this.diffTarget = _.get(_.head(newValue), 'versionId', 0)
|
||||||
this.diffSource = _.get(_.nth(newValue, 1), 'versionId', 0)
|
this.diffSource = _.get(_.nth(newValue, 1), 'versionId', 0)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async diffSource (newValue, oldValue) {
|
||||||
|
if (this.diffSource !== this.source.versionId) {
|
||||||
|
const page = _.find(this.cache, { versionId: newValue })
|
||||||
|
if (page) {
|
||||||
|
this.source = page
|
||||||
|
} else {
|
||||||
|
this.source = await this.loadVersion(newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async diffTarget (newValue, oldValue) {
|
||||||
|
if (this.diffTarget !== this.target.versionId) {
|
||||||
|
const page = _.find(this.cache, { versionId: newValue })
|
||||||
|
if (page) {
|
||||||
|
this.target = page
|
||||||
|
} else {
|
||||||
|
this.target = await this.loadVersion(newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
@ -192,19 +214,62 @@ export default {
|
|||||||
this.target.content = this.liveContent
|
this.target.content = this.liveContent
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async loadVersion (versionId) {
|
||||||
|
this.$store.commit(`loadingStart`, 'history-version-' + versionId)
|
||||||
|
const resp = await this.$apollo.query({
|
||||||
|
query: gql`
|
||||||
|
query ($pageId: Int!, $versionId: Int!) {
|
||||||
|
pages {
|
||||||
|
version (pageId: $pageId, versionId: $versionId) {
|
||||||
|
action
|
||||||
|
authorId
|
||||||
|
authorName
|
||||||
|
content
|
||||||
|
contentType
|
||||||
|
createdAt
|
||||||
|
description
|
||||||
|
editor
|
||||||
|
isPrivate
|
||||||
|
isPublished
|
||||||
|
locale
|
||||||
|
pageId
|
||||||
|
path
|
||||||
|
publishEndDate
|
||||||
|
publishStartDate
|
||||||
|
tags
|
||||||
|
title
|
||||||
|
versionId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
versionId,
|
||||||
|
pageId: this.pageId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$store.commit(`loadingStop`, 'history-version-' + versionId)
|
||||||
|
const page = _.get(resp, 'data.pages.version', null)
|
||||||
|
if (page) {
|
||||||
|
this.cache.push(page)
|
||||||
|
return page
|
||||||
|
} else {
|
||||||
|
return { content: '' }
|
||||||
|
}
|
||||||
|
},
|
||||||
toggleViewMode () {
|
toggleViewMode () {
|
||||||
this.viewMode = (this.viewMode === 'line-by-line') ? 'side-by-side' : 'line-by-line'
|
this.viewMode = (this.viewMode === 'line-by-line') ? 'side-by-side' : 'line-by-line'
|
||||||
},
|
},
|
||||||
goLive() {
|
goLive () {
|
||||||
window.location.assign(`/${this.path}`)
|
window.location.assign(`/${this.path}`)
|
||||||
},
|
},
|
||||||
setDiffSource(versionId) {
|
setDiffSource (versionId) {
|
||||||
this.diffSource = versionId
|
this.diffSource = versionId
|
||||||
},
|
},
|
||||||
setDiffTarget(versionId) {
|
setDiffTarget (versionId) {
|
||||||
this.diffTarget = versionId
|
this.diffTarget = versionId
|
||||||
},
|
},
|
||||||
loadMore() {
|
loadMore () {
|
||||||
this.offsetPage++
|
this.offsetPage++
|
||||||
this.$apollo.queries.trail.fetchMore({
|
this.$apollo.queries.trail.fetchMore({
|
||||||
variables: {
|
variables: {
|
||||||
@ -226,7 +291,7 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
trailColor(actionType) {
|
trailColor (actionType) {
|
||||||
switch (actionType) {
|
switch (actionType) {
|
||||||
case 'edit':
|
case 'edit':
|
||||||
return 'primary'
|
return 'primary'
|
||||||
@ -238,7 +303,7 @@ export default {
|
|||||||
return 'grey'
|
return 'grey'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
trailIcon(actionType) {
|
trailIcon (actionType) {
|
||||||
switch (actionType) {
|
switch (actionType) {
|
||||||
case 'edit':
|
case 'edit':
|
||||||
return '' // 'mdi-pencil'
|
return '' // 'mdi-pencil'
|
||||||
@ -250,7 +315,7 @@ export default {
|
|||||||
return 'warning'
|
return 'warning'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
trailBgColor(actionType) {
|
trailBgColor (actionType) {
|
||||||
switch (actionType) {
|
switch (actionType) {
|
||||||
case 'move':
|
case 'move':
|
||||||
return this.darkMode ? 'purple' : 'purple lighten-5'
|
return this.darkMode ? 'purple' : 'purple lighten-5'
|
||||||
@ -263,8 +328,25 @@ export default {
|
|||||||
},
|
},
|
||||||
apollo: {
|
apollo: {
|
||||||
trail: {
|
trail: {
|
||||||
query: historyTrailQuery,
|
query: gql`
|
||||||
variables() {
|
query($id: Int!, $offsetPage: Int, $offsetSize: Int) {
|
||||||
|
pages {
|
||||||
|
history(id:$id, offsetPage:$offsetPage, offsetSize:$offsetSize) {
|
||||||
|
trail {
|
||||||
|
versionId
|
||||||
|
authorId
|
||||||
|
authorName
|
||||||
|
actionType
|
||||||
|
valueBefore
|
||||||
|
valueAfter
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables () {
|
||||||
return {
|
return {
|
||||||
id: this.pageId,
|
id: this.pageId,
|
||||||
offsetPage: 0,
|
offsetPage: 0,
|
||||||
@ -272,7 +354,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
manual: true,
|
manual: true,
|
||||||
result({ data, loading, networkStatus }) {
|
result ({ data, loading, networkStatus }) {
|
||||||
this.total = data.pages.history.total
|
this.total = data.pages.history.total
|
||||||
this.trail = data.pages.history.trail
|
this.trail = data.pages.history.trail
|
||||||
},
|
},
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
query($id: Int!, $offsetPage: Int, $offsetSize: Int) {
|
|
||||||
pages {
|
|
||||||
history(id:$id, offsetPage:$offsetPage, offsetSize:$offsetSize) {
|
|
||||||
trail {
|
|
||||||
versionId
|
|
||||||
authorId
|
|
||||||
authorName
|
|
||||||
actionType
|
|
||||||
valueBefore
|
|
||||||
valueAfter
|
|
||||||
createdAt
|
|
||||||
}
|
|
||||||
total
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,6 +21,15 @@ module.exports = {
|
|||||||
offsetSize: args.offsetSize || 100
|
offsetSize: args.offsetSize || 100
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* PAGE VERSION
|
||||||
|
*/
|
||||||
|
async version(obj, args, context, info) {
|
||||||
|
return WIKI.models.pageHistory.getVersion({
|
||||||
|
pageId: args.pageId,
|
||||||
|
versionId: args.versionId
|
||||||
|
})
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* SEARCH PAGES
|
* SEARCH PAGES
|
||||||
*/
|
*/
|
||||||
|
@ -19,7 +19,12 @@ type PageQuery {
|
|||||||
id: Int!
|
id: Int!
|
||||||
offsetPage: Int
|
offsetPage: Int
|
||||||
offsetSize: Int
|
offsetSize: Int
|
||||||
): PageHistoryResult @auth(requires: ["manage:system", "read:pages"])
|
): PageHistoryResult @auth(requires: ["manage:system", "read:history"])
|
||||||
|
|
||||||
|
version(
|
||||||
|
pageId: Int!
|
||||||
|
versionId: Int!
|
||||||
|
): PageVersion @auth(requires: ["manage:system", "read:history"])
|
||||||
|
|
||||||
search(
|
search(
|
||||||
query: String!
|
query: String!
|
||||||
@ -150,7 +155,7 @@ type Page {
|
|||||||
isPublished: Boolean!
|
isPublished: Boolean!
|
||||||
privateNS: String
|
privateNS: String
|
||||||
publishStartDate: Date!
|
publishStartDate: Date!
|
||||||
publishEndDate: String!
|
publishEndDate: Date!
|
||||||
tags: [PageTag]!
|
tags: [PageTag]!
|
||||||
content: String!
|
content: String!
|
||||||
render: String
|
render: String
|
||||||
@ -186,6 +191,27 @@ type PageHistory {
|
|||||||
createdAt: Date!
|
createdAt: Date!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PageVersion {
|
||||||
|
action: String!
|
||||||
|
authorId: String!
|
||||||
|
authorName: String!
|
||||||
|
content: String!
|
||||||
|
contentType: String!
|
||||||
|
createdAt: Date!
|
||||||
|
description: String!
|
||||||
|
editor: String!
|
||||||
|
isPrivate: Boolean!
|
||||||
|
isPublished: Boolean!
|
||||||
|
locale: String!
|
||||||
|
pageId: Int!
|
||||||
|
path: String!
|
||||||
|
publishEndDate: Date!
|
||||||
|
publishStartDate: Date!
|
||||||
|
tags: [String]!
|
||||||
|
title: String!
|
||||||
|
versionId: Int!
|
||||||
|
}
|
||||||
|
|
||||||
type PageHistoryResult {
|
type PageHistoryResult {
|
||||||
trail: [PageHistory]
|
trail: [PageHistory]
|
||||||
total: Int!
|
total: Int!
|
||||||
|
@ -104,6 +104,40 @@ module.exports = class PageHistory extends Model {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getVersion({ pageId, versionId }) {
|
||||||
|
const version = await WIKI.models.pageHistory.query()
|
||||||
|
.column([
|
||||||
|
'pageHistory.path',
|
||||||
|
'pageHistory.title',
|
||||||
|
'pageHistory.description',
|
||||||
|
'pageHistory.isPrivate',
|
||||||
|
'pageHistory.isPublished',
|
||||||
|
'pageHistory.publishStartDate',
|
||||||
|
'pageHistory.publishEndDate',
|
||||||
|
'pageHistory.content',
|
||||||
|
'pageHistory.contentType',
|
||||||
|
'pageHistory.createdAt',
|
||||||
|
'pageHistory.action',
|
||||||
|
'pageHistory.authorId',
|
||||||
|
'pageHistory.pageId',
|
||||||
|
{
|
||||||
|
versionId: 'pageHistory.id',
|
||||||
|
editor: 'pageHistory.editorKey',
|
||||||
|
locale: 'pageHistory.localeCode',
|
||||||
|
authorName: 'author.name'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.joinRelated('author')
|
||||||
|
.where({
|
||||||
|
'pageHistory.id': versionId,
|
||||||
|
'pageHistory.pageId': pageId
|
||||||
|
}).first()
|
||||||
|
return {
|
||||||
|
...version,
|
||||||
|
tags: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async getHistory({ pageId, offsetPage = 0, offsetSize = 100 }) {
|
static async getHistory({ pageId, offsetPage = 0, offsetSize = 100 }) {
|
||||||
const history = await WIKI.models.pageHistory.query()
|
const history = await WIKI.models.pageHistory.query()
|
||||||
.column([
|
.column([
|
||||||
|
Loading…
Reference in New Issue
Block a user