diff --git a/client/components/history.vue b/client/components/history.vue index 950ab3bd..b70e9b0d 100644 --- a/client/components/history.vue +++ b/client/components/history.vue @@ -5,48 +5,49 @@ v-toolbar(color='primary', dark) .subheading Viewing history of page #[strong /{{path}}] v-spacer - .caption.blue--text.text--lighten-3 ID {{pageId}} + .caption.blue--text.text--lighten-3.mr-4 Trail Length: {{total}} + .caption.blue--text.text--lighten-3 ID: {{pageId}} v-btn.ml-4(depressed, color='blue darken-1', @click='goLive') Return to Live Version v-container(fluid, grid-list-xl) v-layout(row, wrap) v-flex(xs4) - v-chip.ma-0.grey--text.text--darken-2( + v-chip.ma-0( label small - color='grey lighten-2' + :color='darkMode ? `grey darken-2` : `grey lighten-2`' + :class='darkMode ? `grey--text text--lighten-2` : `grey--text text--darken-2`' ) span Live v-timeline( dense ) - v-timeline-item( - v-for='ph in trail' + v-timeline-item.pb-2( + v-for='(ph, idx) in trail' :key='ph.versionId' :small='ph.actionType === `edit`' fill-dot :color='trailColor(ph.actionType)' :icon='trailIcon(ph.actionType)' + :class='idx >= trail.length - 1 ? `pb-4` : `pb-2`' ) v-card.radius-7(flat, :class='trailBgColor(ph.actionType)') - v-toolbar(flat, :color='trailBgColor(ph.actionType)') + v-toolbar(flat, :color='trailBgColor(ph.actionType)', height='40') v-chip.ml-0.mr-3( v-if='diffSource === ph.versionId' - label small color='pink' ) .caption.white--text Source v-chip.ml-0.mr-3( v-if='diffTarget === ph.versionId' - label small color='pink' ) .caption.white--text Target - .caption(v-if='ph.actionType === `edit`') Edited by {{ ph.authorName }} - .caption(v-else-if='ph.actionType === `move`') Moved from #[strong {{ph.valueBefore}}] to #[strong {{ph.valueAfter}}] by {{ ph.authorName }} - .caption(v-else-if='ph.actionType === `initial`') Created by {{ ph.authorName }} - .caption(v-else) Unknown Action by {{ ph.authorName }} + .caption(v-if='ph.actionType === `edit`') Edited by #[strong {{ ph.authorName }}] + .caption(v-else-if='ph.actionType === `move`') Moved from #[strong {{ph.valueBefore}}] to #[strong {{ph.valueAfter}}] by #[strong {{ ph.authorName }}] + .caption(v-else-if='ph.actionType === `initial`') Created by #[strong {{ ph.authorName }}] + .caption(v-else) Unknown Action by #[strong {{ ph.authorName }}] v-spacer .caption {{ ph.createdAt | moment('calendar') }} v-menu(offset-x, left) @@ -76,20 +77,30 @@ v-list-tile-avatar: v-icon call_split v-list-tile-title Branch off from here - v-chip.ma-0.grey--text.text--darken-2( + v-btn.ma-0.radius-7( + v-if='total > trail.length' + block + color='grey darken-2' + @click='loadMore' + ) + .caption.white--text Load More... + + v-chip.ma-0( + v-else label small - color='grey lighten-2' + :color='darkMode ? `grey darken-2` : `grey lighten-2`' + :class='darkMode ? `grey--text text--lighten-2` : `grey--text text--darken-2`' ) End of history trail v-flex(xs8) v-card.radius-7 v-card-text - v-card.grey.lighten-4.radius-7(flat) + v-card.grey.radius-7(flat, :class='darkMode ? `darken-2` : `lighten-4`') v-card-text .subheading Page Title .caption Some page description - .mt-3(v-html='diffHTML') + v-card.mt-3(light, v-html='diffHTML') nav-footer @@ -129,7 +140,8 @@ export default { trail: [], diffSource: 0, diffTarget: 0, - offset: 0 + offsetPage: 0, + total: 0 } }, computed: { @@ -173,6 +185,28 @@ export default { setDiffTarget(versionId) { this.diffTarget = versionId }, + loadMore() { + this.offsetPage++ + this.$apollo.queries.trail.fetchMore({ + variables: { + id: this.pageId, + offsetPage: this.offsetPage, + offsetSize: 25 + }, + updateQuery: (previousResult, { fetchMoreResult }) => { + return { + pages: { + history: { + total: previousResult.pages.history.total, + trail: [...previousResult.pages.history.trail, ...fetchMoreResult.pages.history.trail], + __typename: previousResult.pages.history.__typename + }, + __typename: previousResult.pages.__typename + } + } + } + }) + }, trailColor(actionType) { switch (actionType) { case 'edit': @@ -200,11 +234,11 @@ export default { trailBgColor(actionType) { switch (actionType) { case 'move': - return 'purple lighten-5' + return this.darkMode ? 'purple' : 'purple lighten-5' case 'initial': - return 'teal lighten-5' + return this.darkMode ? 'teal darken-3' : 'teal lighten-5' default: - return 'grey lighten-3' + return this.darkMode ? 'grey darken-3' : 'grey lighten-3' } } }, @@ -214,10 +248,15 @@ export default { variables() { return { id: this.pageId, - offset: 0 + offsetPage: 0, + offsetSize: 25 } }, - update: (data) => data.pages.history, + manual: true, + result({ data, loading, networkStatus }) { + this.total = data.pages.history.total + this.trail = data.pages.history.trail + }, watchLoading (isLoading) { this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'history-trail-refresh') } diff --git a/client/graph/history/history-trail-query.gql b/client/graph/history/history-trail-query.gql index d7ff2d25..9dc1ae8b 100644 --- a/client/graph/history/history-trail-query.gql +++ b/client/graph/history/history-trail-query.gql @@ -1,13 +1,16 @@ -query($id: Int!, $offset: Int) { +query($id: Int!, $offsetPage: Int, $offsetSize: Int) { pages { - history(id:$id, offset:$offset) { - versionId - authorId - authorName - actionType - valueBefore - valueAfter - createdAt + history(id:$id, offsetPage:$offsetPage, offsetSize:$offsetSize) { + trail { + versionId + authorId + authorName + actionType + valueBefore + valueAfter + createdAt + } + total } } } diff --git a/server/graph/resolvers/page.js b/server/graph/resolvers/page.js index 3e560826..95703d41 100644 --- a/server/graph/resolvers/page.js +++ b/server/graph/resolvers/page.js @@ -13,7 +13,8 @@ module.exports = { async history(obj, args, context, info) { return WIKI.models.pageHistory.getHistory({ pageId: args.id, - offset: args.offset || 0 + offsetPage: args.offsetPage || 0, + offsetSize: args.offsetSize || 100 }) }, async list(obj, args, context, info) { diff --git a/server/graph/schemas/page.graphql b/server/graph/schemas/page.graphql index 808a0286..fcc13b28 100644 --- a/server/graph/schemas/page.graphql +++ b/server/graph/schemas/page.graphql @@ -17,8 +17,9 @@ extend type Mutation { type PageQuery { history( id: Int! - offset: Int - ): [PageHistory] + offsetPage: Int + offsetSize: Int + ): PageHistoryResult list( filter: String @@ -107,3 +108,8 @@ type PageHistory { valueAfter: String createdAt: Date! } + +type PageHistoryResult { + trail: [PageHistory] + total: Int! +} diff --git a/server/models/pageHistory.js b/server/models/pageHistory.js index aae8d379..5f38df53 100644 --- a/server/models/pageHistory.js +++ b/server/models/pageHistory.js @@ -103,7 +103,7 @@ module.exports = class PageHistory extends Model { }) } - static async getHistory({ pageId, offset = 0 }) { + static async getHistory({ pageId, offsetPage = 0, offsetSize = 100 }) { const history = await WIKI.models.pageHistory.query() .column([ 'pageHistory.id', @@ -118,37 +118,61 @@ module.exports = class PageHistory extends Model { .where({ 'pageHistory.pageId': pageId }) - .orderBy('pageHistory.createdAt', 'asc') - .offset(offset) - .limit(20) + .orderBy('pageHistory.createdAt', 'desc') + .page(offsetPage, offsetSize) let prevPh = null + const upperLimit = (offsetPage + 1) * offsetSize - return _.reduce(history, (res, ph) => { - let actionType = 'edit' - let valueBefore = null - let valueAfter = null + if (history.total >= upperLimit) { + prevPh = await WIKI.models.pageHistory.query() + .column([ + 'pageHistory.id', + 'pageHistory.path', + 'pageHistory.authorId', + 'pageHistory.createdAt', + { + authorName: 'author.name' + } + ]) + .joinRelation('author') + .where({ + 'pageHistory.pageId': pageId + }) + .orderBy('pageHistory.createdAt', 'desc') + .offset((offsetPage + 1) * offsetSize) + .limit(1) + .first() + } - if (!prevPh && offset === 0) { - actionType = 'initial' - } else if (_.get(prevPh, 'path', '') !== ph.path) { - actionType = 'move' - valueBefore = _.get(prevPh, 'path', '') - valueAfter = ph.path - } + return { + trail: _.reduce(_.reverse(history.results), (res, ph) => { + let actionType = 'edit' + let valueBefore = null + let valueAfter = null - res.unshift({ - versionId: ph.id, - authorId: ph.authorId, - authorName: ph.authorName, - actionType, - valueBefore, - valueAfter, - createdAt: ph.createdAt - }) + if (!prevPh && history.total < upperLimit) { + actionType = 'initial' + } else if (_.get(prevPh, 'path', '') !== ph.path) { + actionType = 'move' + valueBefore = _.get(prevPh, 'path', '') + valueAfter = ph.path + } + + res.unshift({ + versionId: ph.id, + authorId: ph.authorId, + authorName: ph.authorName, + actionType, + valueBefore, + valueAfter, + createdAt: ph.createdAt + }) - prevPh = ph - return res - }, []) + prevPh = ph + return res + }, []), + total: history.total + } } }