feat: History page - List previous commits
This commit is contained in:
parent
a7c4f42ef0
commit
a748b3a4eb
@ -1,5 +1,4 @@
|
|||||||
client/js
|
client
|
||||||
client/scss
|
|
||||||
coverage
|
coverage
|
||||||
data
|
data
|
||||||
logs
|
logs
|
||||||
|
@ -19,7 +19,7 @@ $(() => {
|
|||||||
offset: -50
|
offset: -50
|
||||||
})
|
})
|
||||||
|
|
||||||
$('.stickyscroll').sticky({ topSpacing: 15 })
|
$('.stickyscroll').sticky({ topSpacing: 15, bottomSpacing: 75 })
|
||||||
|
|
||||||
// ====================================
|
// ====================================
|
||||||
// Notifications
|
// Notifications
|
||||||
@ -58,5 +58,6 @@ $(() => {
|
|||||||
require('./pages/create.js')(alerts, socket)
|
require('./pages/create.js')(alerts, socket)
|
||||||
require('./pages/edit.js')(alerts, socket)
|
require('./pages/edit.js')(alerts, socket)
|
||||||
require('./pages/source.js')(alerts)
|
require('./pages/source.js')(alerts)
|
||||||
|
require('./pages/history.js')(alerts)
|
||||||
require('./pages/admin.js')(alerts)
|
require('./pages/admin.js')(alerts)
|
||||||
})
|
})
|
||||||
|
11
client/js/pages/history.js
Normal file
11
client/js/pages/history.js
Normal file
@ -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') : ''
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,21 @@
|
|||||||
transition: all .4s ease;
|
transition: all .4s ease;
|
||||||
line-height: 14px;
|
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 {
|
i {
|
||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
color: mc('blue-grey', '300');
|
color: mc('blue-grey', '300');
|
||||||
@ -55,6 +70,13 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.is-small {
|
||||||
|
flex: 1 0 100%;
|
||||||
|
display: block;
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255,255,255,.5)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> ul {
|
> ul {
|
||||||
|
@ -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
|
* View document
|
||||||
*/
|
*/
|
||||||
|
@ -402,5 +402,17 @@ module.exports = {
|
|||||||
return rights.checkRole('/' + r._id, usr.rights, 'read')
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,6 +253,30 @@ module.exports = {
|
|||||||
if (_.includes(err.stdout, 'nothing to commit')) { return true }
|
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
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ block adminContent
|
|||||||
h2.subtitle Manage site configuration
|
h2.subtitle Manage site configuration
|
||||||
.form-sections
|
.form-sections
|
||||||
section
|
section
|
||||||
|
img(src='/images/logo.png', style={width:'200px', float:'right'})
|
||||||
label.label System Version
|
label.label System Version
|
||||||
.section-block
|
.section-block
|
||||||
p Current Version: #[strong= sysversion.current]
|
p Current Version: #[strong= sysversion.current]
|
||||||
|
35
server/views/pages/history.pug
Normal file
35
server/views/pages/history.pug
Normal file
@ -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
|
@ -18,9 +18,9 @@ block rootNavRight
|
|||||||
a.button.is-outlined(href='/source/' + pageData.meta.path)
|
a.button.is-outlined(href='/source/' + pageData.meta.path)
|
||||||
i.icon-loader
|
i.icon-loader
|
||||||
span Source
|
span Source
|
||||||
a.button.is-outlined(href='/diff/' + pageData.meta.path)
|
a.button.is-outlined(href='/hist/' + pageData.meta.path)
|
||||||
i.icon-flow-merge
|
i.icon-clock
|
||||||
span Diff
|
span History
|
||||||
if rights.write
|
if rights.write
|
||||||
a.button(href='/edit/' + pageData.meta.path)
|
a.button(href='/edit/' + pageData.meta.path)
|
||||||
i.icon-document-text
|
i.icon-document-text
|
||||||
|
Loading…
Reference in New Issue
Block a user