feat: History page - List previous commits
This commit is contained in:
		| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user