| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 | 
							- <template lang='pug'>
 
-   v-app(:dark='darkMode').history
 
-     nav-header
 
-     v-content
 
-       v-toolbar(color='primary', dark)
 
-         .subheading Viewing history of #[strong /{{path}}]
 
-         template(v-if='$vuetify.breakpoint.mdAndUp')
 
-           v-spacer
 
-           .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(xs12, md4)
 
-             v-chip.my-0.ml-6(
 
-               label
 
-               small
 
-               :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.pb-2(
 
-                 v-for='(ph, idx) in fullTrail'
 
-                 :key='ph.versionId'
 
-                 :small='ph.actionType === `edit`'
 
-                 :color='trailColor(ph.actionType)'
 
-                 :icon='trailIcon(ph.actionType)'
 
-                 )
 
-                 v-card.radius-7(flat, :class='trailBgColor(ph.actionType)')
 
-                   v-toolbar(flat, :color='trailBgColor(ph.actionType)', height='40')
 
-                     .caption(:title='$options.filters.moment(ph.versionDate, `LLL`)') {{ ph.versionDate | moment('ll') }}
 
-                     v-divider.mx-3(vertical)
 
-                     .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-if='ph.actionType === `live`') Last Edited by #[strong {{ ph.authorName }}]
 
-                     .caption(v-else) Unknown Action by #[strong {{ ph.authorName }}]
 
-                     v-spacer
 
-                     v-menu(offset-x, left)
 
-                       template(v-slot:activator='{ on }')
 
-                         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-item(@click='setDiffSource(ph.versionId)', :disabled='(ph.versionId >= diffTarget && diffTarget !== 0) || ph.versionId === 0')
 
-                           v-list-item-avatar(size='24'): v-avatar A
 
-                           v-list-item-title Set as Differencing Source
 
-                         v-list-item(@click='setDiffTarget(ph.versionId)', :disabled='ph.versionId <= diffSource && ph.versionId !== 0')
 
-                           v-list-item-avatar(size='24'): v-avatar B
 
-                           v-list-item-title Set as Differencing Target
 
-                         v-list-item(@click='viewSource(ph.versionId)')
 
-                           v-list-item-avatar(size='24'): v-icon mdi-code-tags
 
-                           v-list-item-title View Source
 
-                         v-list-item(@click='download(ph.versionId)')
 
-                           v-list-item-avatar(size='24'): v-icon mdi-cloud-download-outline
 
-                           v-list-item-title Download Version
 
-                         v-list-item(@click='restore(ph.versionId, ph.versionDate)', :disabled='ph.versionId === 0')
 
-                           v-list-item-avatar(size='24'): v-icon(:disabled='ph.versionId === 0') mdi-history
 
-                           v-list-item-title Restore
 
-                         v-list-item(@click='branchOff(ph.versionId)')
 
-                           v-list-item-avatar(size='24'): v-icon mdi-source-branch
 
-                           v-list-item-title Branch off from here
 
-                     v-btn.mr-2.radius-4(
 
-                       @click='setDiffSource(ph.versionId)'
 
-                       icon
 
-                       small
 
-                       depressed
 
-                       tile
 
-                       :class='diffSource === ph.versionId ? `pink white--text` : ($vuetify.theme.dark ? `grey darken-2` : `grey lighten-2`)'
 
-                       :disabled='(ph.versionId >= diffTarget && diffTarget !== 0) || ph.versionId === 0'
 
-                       ): strong A
 
-                     v-btn.mr-0.radius-4(
 
-                       @click='setDiffTarget(ph.versionId)'
 
-                       icon
 
-                       small
 
-                       depressed
 
-                       tile
 
-                       :class='diffTarget === ph.versionId ? `pink white--text` : ($vuetify.theme.dark ? `grey darken-2` : `grey lighten-2`)'
 
-                       :disabled='ph.versionId <= diffSource && ph.versionId !== 0'
 
-                       ): strong B
 
-             v-btn.ma-0.radius-7(
 
-               v-if='total > trail.length'
 
-               block
 
-               color='primary'
 
-               @click='loadMore'
 
-               )
 
-               .caption.white--text Load More...
 
-             v-chip.ma-0(
 
-               v-else
 
-               label
 
-               small
 
-               :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(xs12, md8)
 
-             v-card.radius-7(:class='$vuetify.breakpoint.mdAndUp ? `mt-8` : ``')
 
-               v-card-text
 
-                 v-card.grey.radius-7(flat, :class='darkMode ? `darken-2` : `lighten-4`')
 
-                   v-row(no-gutters, align='center')
 
-                     v-col
 
-                       v-card-text
 
-                         .subheading {{target.title}}
 
-                         .caption {{target.description}}
 
-                     v-col.text-right.py-3(cols='2', v-if='$vuetify.breakpoint.mdAndUp')
 
-                       v-btn.mr-3(:color='$vuetify.theme.dark ? `white` : `grey darken-3`', small, dark, outlined, @click='toggleViewMode')
 
-                         v-icon(left) mdi-eye
 
-                         .overline View Mode
 
-                 v-card.mt-3(light, v-html='diffHTML', flat)
 
-     v-dialog(v-model='isRestoreConfirmDialogShown', max-width='650', persistent)
 
-       v-card
 
-         .dialog-header.is-orange {{$t('history:restore.confirmTitle')}}
 
-         v-card-text.pa-4
 
-           i18next(tag='span', path='history:restore.confirmText')
 
-             strong(place='date') {{ restoreTarget.versionDate | moment('LLL') }}
 
-         v-card-actions
 
-           v-spacer
 
-           v-btn(text, @click='isRestoreConfirmDialogShown = false', :disabled='restoreLoading') {{$t('common:actions.cancel')}}
 
-           v-btn(color='orange darken-2', dark, @click='restoreConfirm', :loading='restoreLoading') {{$t('history:restore.confirmButton')}}
 
-     page-selector(mode='create', v-model='branchOffOpts.modal', :open-handler='branchOffHandle', :path='branchOffOpts.path', :locale='branchOffOpts.locale')
 
-     nav-footer
 
-     notify
 
-     search-results
 
- </template>
 
- <script>
 
- import * as Diff2Html from 'diff2html'
 
- import { createPatch } from 'diff'
 
- import { get } from 'vuex-pathify'
 
- import _ from 'lodash'
 
- import gql from 'graphql-tag'
 
- export default {
 
-   i18nOptions: { namespaces: 'history' },
 
-   props: {
 
-     pageId: {
 
-       type: Number,
 
-       default: 0
 
-     },
 
-     locale: {
 
-       type: String,
 
-       default: 'en'
 
-     },
 
-     path: {
 
-       type: String,
 
-       default: 'home'
 
-     },
 
-     title: {
 
-       type: String,
 
-       default: 'Untitled Page'
 
-     },
 
-     description: {
 
-       type: String,
 
-       default: ''
 
-     },
 
-     createdAt: {
 
-       type: String,
 
-       default: ''
 
-     },
 
-     updatedAt: {
 
-       type: String,
 
-       default: ''
 
-     },
 
-     tags: {
 
-       type: Array,
 
-       default: () => ([])
 
-     },
 
-     authorName: {
 
-       type: String,
 
-       default: 'Unknown'
 
-     },
 
-     authorId: {
 
-       type: Number,
 
-       default: 0
 
-     },
 
-     isPublished: {
 
-       type: Boolean,
 
-       default: false
 
-     },
 
-     liveContent: {
 
-       type: String,
 
-       default: ''
 
-     }
 
-   },
 
-   data () {
 
-     return {
 
-       source: {
 
-         versionId: 0,
 
-         content: '',
 
-         title: '',
 
-         description: ''
 
-       },
 
-       target: {
 
-         versionId: 0,
 
-         content: '',
 
-         title: '',
 
-         description: ''
 
-       },
 
-       trail: [],
 
-       diffSource: 0,
 
-       diffTarget: 0,
 
-       offsetPage: 0,
 
-       total: 0,
 
-       viewMode: 'line-by-line',
 
-       cache: [],
 
-       restoreTarget: {
 
-         versionId: 0,
 
-         versionDate: ''
 
-       },
 
-       branchOffOpts: {
 
-         versionId: 0,
 
-         locale: 'en',
 
-         path: 'new-page',
 
-         modal: false
 
-       },
 
-       isRestoreConfirmDialogShown: false,
 
-       restoreLoading: false
 
-     }
 
-   },
 
-   computed: {
 
-     darkMode: get('site/dark'),
 
-     fullTrail () {
 
-       const liveTrailItem = {
 
-         versionId: 0,
 
-         authorId: this.authorId,
 
-         authorName: this.authorName,
 
-         actionType: 'live',
 
-         valueBefore: null,
 
-         valueAfter: null,
 
-         versionDate: this.updatedAt
 
-       }
 
-       // -> Check for move between latest and live
 
-       const prevPage = _.find(this.cache, ['versionId', _.get(this.trail, '[0].versionId', -1)])
 
-       if (prevPage && this.path !== prevPage.path) {
 
-         liveTrailItem.actionType = 'move'
 
-         liveTrailItem.valueBefore = prevPage.path
 
-         liveTrailItem.valueAfter = this.path
 
-       }
 
-       // -> Combine trail with live
 
-       return [
 
-         liveTrailItem,
 
-         ...this.trail
 
-       ]
 
-     },
 
-     diffs () {
 
-       return createPatch(`/${this.path}`, this.source.content, this.target.content)
 
-     },
 
-     diffHTML () {
 
-       return Diff2Html.html(this.diffs, {
 
-         inputFormat: 'diff',
 
-         drawFileList: false,
 
-         matching: 'lines',
 
-         outputFormat: this.viewMode
 
-       })
 
-     }
 
-   },
 
-   watch: {
 
-     trail (newValue, oldValue) {
 
-       if (newValue && newValue.length > 0) {
 
-         this.diffTarget = 0
 
-         this.diffSource = _.get(_.head(newValue), '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 () {
 
-     this.$store.commit('page/SET_ID', this.id)
 
-     this.$store.commit('page/SET_LOCALE', this.locale)
 
-     this.$store.commit('page/SET_PATH', this.path)
 
-     this.$store.commit('page/SET_MODE', 'history')
 
-     this.cache.push({
 
-       action: 'live',
 
-       authorId: this.authorId,
 
-       authorName: this.authorName,
 
-       content: this.liveContent,
 
-       contentType: '',
 
-       createdAt: this.createdAt,
 
-       description: this.description,
 
-       editor: '',
 
-       isPrivate: false,
 
-       isPublished: this.isPublished,
 
-       locale: this.locale,
 
-       pageId: this.pageId,
 
-       path: this.path,
 
-       publishEndDate: '',
 
-       publishStartDate: '',
 
-       tags: this.tags,
 
-       title: this.title,
 
-       versionId: 0,
 
-       versionDate: this.updatedAt
 
-     })
 
-     this.target = this.cache[0]
 
-   },
 
-   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
 
-                 versionDate
 
-                 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: '' }
 
-       }
 
-     },
 
-     viewSource (versionId) {
 
-       window.location.assign(`/s/${this.locale}/${this.path}?v=${versionId}`)
 
-     },
 
-     download (versionId) {
 
-       window.location.assign(`/d/${this.locale}/${this.path}?v=${versionId}`)
 
-     },
 
-     restore (versionId, versionDate) {
 
-       this.restoreTarget = {
 
-         versionId,
 
-         versionDate
 
-       }
 
-       this.isRestoreConfirmDialogShown = true
 
-     },
 
-     async restoreConfirm () {
 
-       this.restoreLoading = true
 
-       this.$store.commit(`loadingStart`, 'history-restore')
 
-       try {
 
-         const resp = await this.$apollo.mutate({
 
-           mutation: gql`
 
-             mutation ($pageId: Int!, $versionId: Int!) {
 
-               pages {
 
-                 restore (pageId: $pageId, versionId: $versionId) {
 
-                   responseResult {
 
-                     succeeded
 
-                     errorCode
 
-                     slug
 
-                     message
 
-                   }
 
-                 }
 
-               }
 
-             }
 
-           `,
 
-           variables: {
 
-             versionId: this.restoreTarget.versionId,
 
-             pageId: this.pageId
 
-           }
 
-         })
 
-         if (_.get(resp, 'data.pages.restore.responseResult.succeeded', false) === true) {
 
-           this.$store.commit('showNotification', {
 
-             style: 'success',
 
-             message: this.$t('history:restore.success'),
 
-             icon: 'check'
 
-           })
 
-           this.isRestoreConfirmDialogShown = false
 
-           setTimeout(() => {
 
-             window.location.assign(`/${this.locale}/${this.path}`)
 
-           }, 1000)
 
-         } else {
 
-           throw new Error(_.get(resp, 'data.pages.restore.responseResult.message', 'An unexpected error occured'))
 
-         }
 
-       } catch (err) {
 
-         this.$store.commit('showNotification', {
 
-           style: 'red',
 
-           message: err.message,
 
-           icon: 'alert'
 
-         })
 
-       }
 
-       this.$store.commit(`loadingStop`, 'history-restore')
 
-       this.restoreLoading = false
 
-     },
 
-     branchOff (versionId) {
 
-       const pathParts = this.path.split('/')
 
-       this.branchOffOpts = {
 
-         versionId: versionId,
 
-         locale: this.locale,
 
-         path: (pathParts.length > 1) ? _.initial(pathParts).join('/') + `/new-page` : `new-page`,
 
-         modal: true
 
-       }
 
-     },
 
-     branchOffHandle ({ locale, path }) {
 
-       window.location.assign(`/e/${locale}/${path}?from=${this.pageId},${this.branchOffOpts.versionId}`)
 
-     },
 
-     toggleViewMode () {
 
-       this.viewMode = (this.viewMode === 'line-by-line') ? 'side-by-side' : 'line-by-line'
 
-     },
 
-     goLive () {
 
-       window.location.assign(`/${this.path}`)
 
-     },
 
-     setDiffSource (versionId) {
 
-       this.diffSource = versionId
 
-     },
 
-     setDiffTarget (versionId) {
 
-       this.diffTarget = versionId
 
-     },
 
-     loadMore () {
 
-       this.offsetPage++
 
-       this.$apollo.queries.trail.fetchMore({
 
-         variables: {
 
-           id: this.pageId,
 
-           offsetPage: this.offsetPage,
 
-           offsetSize: this.$vuetify.breakpoint.mdAndUp ? 25 : 5
 
-         },
 
-         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':
 
-           return 'primary'
 
-         case 'move':
 
-           return 'purple'
 
-         case 'initial':
 
-           return 'teal'
 
-         case 'live':
 
-           return 'orange'
 
-         default:
 
-           return 'grey'
 
-       }
 
-     },
 
-     trailIcon (actionType) {
 
-       switch (actionType) {
 
-         case 'edit':
 
-           return '' // 'mdi-pencil'
 
-         case 'move':
 
-           return 'mdi-forward'
 
-         case 'initial':
 
-           return 'mdi-plus'
 
-         case 'live':
 
-           return 'mdi-atom-variant'
 
-         default:
 
-           return 'mdi-alert'
 
-       }
 
-     },
 
-     trailBgColor (actionType) {
 
-       switch (actionType) {
 
-         case 'move':
 
-           return this.darkMode ? 'purple' : 'purple lighten-5'
 
-         case 'initial':
 
-           return this.darkMode ? 'teal darken-3' : 'teal lighten-5'
 
-         case 'live':
 
-           return this.darkMode ? 'orange darken-3' : 'orange lighten-5'
 
-         default:
 
-           return this.darkMode ? 'grey darken-3' : 'grey lighten-4'
 
-       }
 
-     }
 
-   },
 
-   apollo: {
 
-     trail: {
 
-       query: gql`
 
-         query($id: Int!, $offsetPage: Int, $offsetSize: Int) {
 
-           pages {
 
-             history(id:$id, offsetPage:$offsetPage, offsetSize:$offsetSize) {
 
-               trail {
 
-                 versionId
 
-                 authorId
 
-                 authorName
 
-                 actionType
 
-                 valueBefore
 
-                 valueAfter
 
-                 versionDate
 
-               }
 
-               total
 
-             }
 
-           }
 
-         }
 
-       `,
 
-       variables () {
 
-         return {
 
-           id: this.pageId,
 
-           offsetPage: 0,
 
-           offsetSize: this.$vuetify.breakpoint.mdAndUp ? 25 : 5
 
-         }
 
-       },
 
-       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')
 
-       }
 
-     }
 
-   }
 
- }
 
- </script>
 
- <style lang='scss'>
 
- .history {
 
-   &-promptmenu {
 
-     border-top: 5px solid mc('blue', '700');
 
-   }
 
-   .d2h-file-wrapper {
 
-     border: 1px solid #EEE;
 
-     border-left: none;
 
-   }
 
-   .d2h-file-header {
 
-     display: none;
 
-   }
 
- }
 
- </style>
 
 
  |