From 20a2e0e3ce2f308935b6295850b31592dc8ca8b0 Mon Sep 17 00:00:00 2001 From: NGPixel Date: Thu, 6 Jul 2017 00:10:41 -0400 Subject: [PATCH] feat: history browse diffs --- client/js/components/editor-codeblock.vue | 2 +- client/js/components/history.vue | 71 +++++++++++++---------- client/scss/components/sidebar.scss | 1 + server/controllers/pages.js | 21 ++++++- server/libs/git.js | 20 ++++++- server/locales/en/browser.json | 12 +++- 6 files changed, 93 insertions(+), 34 deletions(-) diff --git a/client/js/components/editor-codeblock.vue b/client/js/components/editor-codeblock.vue index 2fb4f942..b9fde4c8 100644 --- a/client/js/components/editor-codeblock.vue +++ b/client/js/components/editor-codeblock.vue @@ -94,7 +94,7 @@ export default { }) } }).catch(err => { - his.$store.dispatch('alert', { + this.$store.dispatch('alert', { style: 'red', icon: 'square-cross', msg: 'Error: ' + err.body.msg diff --git a/client/js/components/history.vue b/client/js/components/history.vue index bd2dac4a..614f4cdb 100644 --- a/client/js/components/history.vue +++ b/client/js/components/history.vue @@ -5,10 +5,10 @@ .column.is-narrow.is-hidden-touch.sidebar aside.stickyscroll .sidebar-label - span {{ $t('sidebar.pastversions') }} + span {{ $t('history.pastversions') }} ul.sidebar-menu li(v-for='item in versions') - a.is-multiline(:title='item.dateFull') + a.is-multiline(:title='item.dateFull', @click='changeCommit(item)', :class='{ "is-active": item.commit === current.commit }') span {{ item.dateCalendar }} span.is-small {{ item.commitAbbr }} @@ -20,37 +20,39 @@ .column.history-info-meta p i.nc-icon-outline.ui-1_calendar-check-62 - span Timestamp: #[strong 2017/07/02 5:19 PM] + span {{ $t('history.timestamp') }}: #[strong {{ current.dateFull }}] p i.nc-icon-outline.i.nc-icon-outline.users_man-23 - span Author: #[strong Nicolas Giard] + span {{ $t('history.author') }}: #[strong {{ current.name }} <{{ current.email }}>] p i.nc-icon-outline.media-1_flash-21 - span Commit: #[strong 379ff16957b2b7f978e02bfe50cd0cee182fcb8a] + span {{ $t('history.commit') }}: #[strong {{ current.commit }}] .column.history-info-actions .button-group button.button.is-blue-grey() i.nc-icon-outline.design_path-intersect - span Compare With... + span {{ $t('history.comparewith') }} button.button.is-blue-grey() i.nc-icon-outline.ui-1_eye-17 - span View + span {{ $t('history.view') }} button.button.is-blue-grey() i.nc-icon-outline.arrows-4_undo-29 - span Revert to version - toggle.is-dark(v-model='sidebyside', desc='Side-by-side View') + span {{ $t('history.reverttoversion') }} + toggle.is-dark(v-model='sidebyside', :desc='$t("history.sidebyside")') .history-diff#diff diff --git a/client/scss/components/sidebar.scss b/client/scss/components/sidebar.scss index 12849fba..b6305e94 100644 --- a/client/scss/components/sidebar.scss +++ b/client/scss/components/sidebar.scss @@ -46,6 +46,7 @@ font-size: 14px; transition: all .4s ease; line-height: 14px; + cursor: pointer; &.is-multiline { flex-wrap: wrap; diff --git a/server/controllers/pages.js b/server/controllers/pages.js index 44fcb82e..951294e3 100644 --- a/server/controllers/pages.js +++ b/server/controllers/pages.js @@ -1,6 +1,6 @@ 'use strict' -/* global entries, lang, winston */ +/* global entries, git, lang, winston */ const express = require('express') const router = express.Router() @@ -202,6 +202,25 @@ router.get('/hist/*', (req, res, next) => { }) }) +/** + * View history of a document + */ +router.post('/hist', (req, res, next) => { + let commit = req.body.commit + let safePath = entryHelper.parsePath(req.body.path) + + if (!/^[a-f0-9]{40}$/.test(commit)) { + return res.status(400).json({ ok: false, error: 'Invalid commit' }) + } + + git.getHistoryDiff(safePath, commit).then((diff) => { + res.json({ ok: true, diff }) + return true + }).catch((err) => { + res.status(500).json({ ok: false, error: err.message }) + }) +}) + /** * View document */ diff --git a/server/libs/git.js b/server/libs/git.js index bdc6bd5e..2f86fbb2 100644 --- a/server/libs/git.js +++ b/server/libs/git.js @@ -265,7 +265,7 @@ module.exports = { let self = this let gitFilePath = entryPath + '.md' - return self._git.exec('log', ['-n', '25', '--format=format:%H %h %cI %cE %cN', '--', gitFilePath]).then((cProc) => { + return self._git.exec('log', ['--max-count=25', '--skip=1', '--format=format:%H %h %cI %cE %cN', '--', gitFilePath]).then((cProc) => { let out = cProc.stdout.toString() if (_.includes(out, 'fatal')) { let errorMsg = _.capitalize(_.head(_.split(_.replace(out, 'fatal: ', ''), ','))) @@ -286,6 +286,24 @@ module.exports = { }).value() return hist }) + }, + + getHistoryDiff(path, commit, comparewith) { + let self = this + if (!comparewith) { + comparewith = 'HEAD' + } + + return self._git.exec('diff', ['--no-color', `${commit}:${path}.md`, `${comparewith}:${path}.md`]).then((cProc) => { + let out = cProc.stdout.toString() + if (_.startsWith(out, 'fatal: ')) { + throw new Error(out) + } else if (!_.includes(out, 'diff')) { + throw new Error('Unable to query diff data.') + } else { + return out + } + }) } } diff --git a/server/locales/en/browser.json b/server/locales/en/browser.json index c203362b..e8bdcda5 100644 --- a/server/locales/en/browser.json +++ b/server/locales/en/browser.json @@ -45,6 +45,16 @@ "videosupportedtitle": "The following are supported:", "videotitle": "Insert Video" }, + "history": { + "pastversions": "Past Versions", + "timestamp": "Timestamp", + "author": "Author", + "commit": "Commit", + "comparewith": "Compare With...", + "view": "View", + "reverttoversion": "Revert to Version", + "sidebyside": "Side-by-side View" + }, "modal": { "abort": "Abort", "anchorerror": "Clipboard copy failed. Copy the URL manually.", @@ -103,4 +113,4 @@ "placeholder": "Search...", "results": "Search Results" } -} \ No newline at end of file +}