From a748b3a4eb387135deaf489f0f6deee75c4107fc Mon Sep 17 00:00:00 2001 From: NGPixel Date: Sun, 30 Apr 2017 16:37:10 -0400 Subject: [PATCH] feat: History page - List previous commits --- .build/.deployexclude | 3 +-- client/js/app.js | 3 ++- client/js/pages/history.js | 11 +++++++++ client/scss/components/sidebar.scss | 22 +++++++++++++++++ server/controllers/pages.js | 21 ++++++++++++++++ server/libs/entries.js | 12 +++++++++ server/libs/git.js | 24 ++++++++++++++++++ server/views/pages/admin/settings.pug | 1 + server/views/pages/history.pug | 35 +++++++++++++++++++++++++++ server/views/pages/view.pug | 6 ++--- 10 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 client/js/pages/history.js create mode 100644 server/views/pages/history.pug diff --git a/.build/.deployexclude b/.build/.deployexclude index 5c7e4b49..6c4ef406 100644 --- a/.build/.deployexclude +++ b/.build/.deployexclude @@ -1,5 +1,4 @@ -client/js -client/scss +client coverage data logs diff --git a/client/js/app.js b/client/js/app.js index 34b7b866..46f5afc4 100644 --- a/client/js/app.js +++ b/client/js/app.js @@ -19,7 +19,7 @@ $(() => { offset: -50 }) - $('.stickyscroll').sticky({ topSpacing: 15 }) + $('.stickyscroll').sticky({ topSpacing: 15, bottomSpacing: 75 }) // ==================================== // Notifications @@ -58,5 +58,6 @@ $(() => { require('./pages/create.js')(alerts, socket) require('./pages/edit.js')(alerts, socket) require('./pages/source.js')(alerts) + require('./pages/history.js')(alerts) require('./pages/admin.js')(alerts) }) diff --git a/client/js/pages/history.js b/client/js/pages/history.js new file mode 100644 index 00000000..2fcb230d --- /dev/null +++ b/client/js/pages/history.js @@ -0,0 +1,11 @@ +'use strict' + +import $ from 'jquery' + +module.exports = (alerts) => { + if ($('#page-type-history').length) { + let currentBasePath = ($('#page-type-history').data('entrypath') !== 'home') ? $('#page-type-history').data('entrypath') : '' + + + } +} diff --git a/client/scss/components/sidebar.scss b/client/scss/components/sidebar.scss index 61661eab..56439c84 100644 --- a/client/scss/components/sidebar.scss +++ b/client/scss/components/sidebar.scss @@ -45,6 +45,21 @@ transition: all .4s ease; line-height: 14px; + &.is-multiline { + flex-wrap: wrap; + } + + &.is-active { + border-left: 5px solid mc('blue', '500'); + color: mc('blue', '300'); + padding-left: 15px; + + .is-small { + color: mc('blue', '500'); + } + + } + i { margin-right: 7px; color: mc('blue-grey', '300'); @@ -55,6 +70,13 @@ text-decoration: none; } + .is-small { + flex: 1 0 100%; + display: block; + font-size: 11px; + color: rgba(255,255,255,.5) + } + } > ul { diff --git a/server/controllers/pages.js b/server/controllers/pages.js index 801f64b1..15171669 100644 --- a/server/controllers/pages.js +++ b/server/controllers/pages.js @@ -179,6 +179,27 @@ router.get('/source/*', (req, res, next) => { }) }) +/** + * View history of a document + */ +router.get('/hist/*', (req, res, next) => { + let safePath = entryHelper.parsePath(_.replace(req.path, '/hist', '')) + + entries.getHistory(safePath).then((pageData) => { + if (pageData) { + res.render('pages/history', { pageData }) + } else { + throw new Error('Invalid page path.') + } + return true + }).catch((err) => { + res.render('error', { + message: err.message, + error: {} + }) + }) +}) + /** * View document */ diff --git a/server/libs/entries.js b/server/libs/entries.js index 22fa322d..35716e5e 100644 --- a/server/libs/entries.js +++ b/server/libs/entries.js @@ -402,5 +402,17 @@ module.exports = { return rights.checkRole('/' + r._id, usr.rights, 'read') }) }) + }, + + getHistory (entryPath) { + return db.Entry.findOne({ _id: entryPath, isEntry: true }).then(entry => { + if (!entry) { return false } + return git.getHistory(entryPath).then(history => { + return { + meta: entry, + history + } + }) + }) } } diff --git a/server/libs/git.js b/server/libs/git.js index 66809bcf..64a512bf 100644 --- a/server/libs/git.js +++ b/server/libs/git.js @@ -253,6 +253,30 @@ module.exports = { if (_.includes(err.stdout, 'nothing to commit')) { return true } }) }) + }, + + getHistory (entryPath) { + let self = this + let gitFilePath = entryPath + '.md' + + return self._git.exec('log', ['-n', '25', '--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: ', ''), ','))) + throw new Error(errorMsg) + } + let hist = _.chain(out).split('\n').map(h => { + let hParts = h.split(' ', 4) + return { + commit: hParts[0], + commitAbbr: hParts[1], + date: hParts[2], + email: hParts[3], + name: hParts[4] + } + }).value() + return hist + }) } } diff --git a/server/views/pages/admin/settings.pug b/server/views/pages/admin/settings.pug index 6a1d1a78..ab0223c6 100644 --- a/server/views/pages/admin/settings.pug +++ b/server/views/pages/admin/settings.pug @@ -7,6 +7,7 @@ block adminContent h2.subtitle Manage site configuration .form-sections section + img(src='/images/logo.png', style={width:'200px', float:'right'}) label.label System Version .section-block p Current Version: #[strong= sysversion.current] diff --git a/server/views/pages/history.pug b/server/views/pages/history.pug new file mode 100644 index 00000000..e9c94cb6 --- /dev/null +++ b/server/views/pages/history.pug @@ -0,0 +1,35 @@ +extends ../layout.pug + +block rootNavRight + i.nav-item#notifload + .nav-item + a.button(href='/' + pageData.meta._id) + i.icon-circle-check + span View Latest + +block content + + #page-type-history.page-type-container(data-entrypath=pageData.meta._id) + .container.is-fluid.has-mkcontent + .columns.is-gapless + + .column.is-narrow.is-hidden-touch.sidebar + + aside.stickyscroll + .sidebar-label + span Past versions + ul.sidebar-menu + each item, index in pageData.history + - var itemDate = moment(item.date) + li: a.is-multiline(class={ 'is-active': index < 1 }, href='', title=itemDate.format('LLLL')) + span= itemDate.calendar(null, { sameElse: 'llll'}) + span.is-small= item.commitAbbr + + .column + + .hero + h1.title#title= pageData.meta.title + if pageData.meta.subtitle + h2.subtitle= pageData.meta.subtitle + .content.mkcontent + != pageData.html diff --git a/server/views/pages/view.pug b/server/views/pages/view.pug index bcf55d62..797206b9 100644 --- a/server/views/pages/view.pug +++ b/server/views/pages/view.pug @@ -18,9 +18,9 @@ block rootNavRight a.button.is-outlined(href='/source/' + pageData.meta.path) i.icon-loader span Source - a.button.is-outlined(href='/diff/' + pageData.meta.path) - i.icon-flow-merge - span Diff + a.button.is-outlined(href='/hist/' + pageData.meta.path) + i.icon-clock + span History if rights.write a.button(href='/edit/' + pageData.meta.path) i.icon-document-text