Setup wizard - all UI steps
This commit is contained in:
@@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
### Fixed
|
||||
- Auth: Authentication would fail if email has uppercase chars and provider callback is in lowercase
|
||||
- Markdown: Fixed potential crash on markdown processing of video links
|
||||
- Search: Search index should now update upon article creation
|
||||
- Search: Search results are no longer duplicated upon article update
|
||||
- UI: Missing icons on login page
|
||||
|
||||
@@ -49,38 +49,41 @@ var Cron = require('cron').CronJob
|
||||
// Start Cron
|
||||
// ----------------------------------------
|
||||
|
||||
var job
|
||||
var jobIsBusy = false
|
||||
var jobUplWatchStarted = false
|
||||
|
||||
var job = new Cron({
|
||||
cronTime: '0 */5 * * * *',
|
||||
onTick: () => {
|
||||
// Make sure we don't start two concurrent jobs
|
||||
db.onReady.then(() => {
|
||||
return db.Entry.remove({})
|
||||
}).then(() => {
|
||||
job = new Cron({
|
||||
cronTime: '0 */5 * * * *',
|
||||
onTick: () => {
|
||||
// Make sure we don't start two concurrent jobs
|
||||
|
||||
if (jobIsBusy) {
|
||||
winston.warn('[AGENT] Previous job has not completed gracefully or is still running! Skipping for now. (This is not normal, you should investigate)')
|
||||
return
|
||||
}
|
||||
winston.info('[AGENT] Running all jobs...')
|
||||
jobIsBusy = true
|
||||
if (jobIsBusy) {
|
||||
winston.warn('[AGENT] Previous job has not completed gracefully or is still running! Skipping for now. (This is not normal, you should investigate)')
|
||||
return
|
||||
}
|
||||
winston.info('[AGENT] Running all jobs...')
|
||||
jobIsBusy = true
|
||||
|
||||
// Prepare async job collector
|
||||
// Prepare async job collector
|
||||
|
||||
let jobs = []
|
||||
let repoPath = path.resolve(ROOTPATH, appconfig.paths.repo)
|
||||
let dataPath = path.resolve(ROOTPATH, appconfig.paths.data)
|
||||
let uploadsTempPath = path.join(dataPath, 'temp-upload')
|
||||
let jobs = []
|
||||
let repoPath = path.resolve(ROOTPATH, appconfig.paths.repo)
|
||||
let dataPath = path.resolve(ROOTPATH, appconfig.paths.data)
|
||||
let uploadsTempPath = path.join(dataPath, 'temp-upload')
|
||||
|
||||
// ----------------------------------------
|
||||
// REGULAR JOBS
|
||||
// ----------------------------------------
|
||||
// ----------------------------------------
|
||||
// REGULAR JOBS
|
||||
// ----------------------------------------
|
||||
|
||||
//* ****************************************
|
||||
// -> Sync with Git remote
|
||||
//* ****************************************
|
||||
//* ****************************************
|
||||
// -> Sync with Git remote
|
||||
//* ****************************************
|
||||
|
||||
jobs.push(git.onReady.then(() => {
|
||||
return git.resync().then(() => {
|
||||
jobs.push(git.resync().then(() => {
|
||||
// -> Stream all documents
|
||||
|
||||
let cacheJobs = []
|
||||
@@ -131,55 +134,56 @@ var job = new Cron({
|
||||
})
|
||||
|
||||
return jobCbStreamDocs
|
||||
})
|
||||
}))
|
||||
}))
|
||||
|
||||
//* ****************************************
|
||||
// -> Clear failed temporary upload files
|
||||
//* ****************************************
|
||||
//* ****************************************
|
||||
// -> Clear failed temporary upload files
|
||||
//* ****************************************
|
||||
|
||||
jobs.push(
|
||||
fs.readdirAsync(uploadsTempPath).then((ls) => {
|
||||
let fifteenAgo = moment().subtract(15, 'minutes')
|
||||
jobs.push(
|
||||
fs.readdirAsync(uploadsTempPath).then((ls) => {
|
||||
let fifteenAgo = moment().subtract(15, 'minutes')
|
||||
|
||||
return Promise.map(ls, (f) => {
|
||||
return fs.statAsync(path.join(uploadsTempPath, f)).then((s) => { return { filename: f, stat: s } })
|
||||
}).filter((s) => { return s.stat.isFile() }).then((arrFiles) => {
|
||||
return Promise.map(arrFiles, (f) => {
|
||||
if (moment(f.stat.ctime).isBefore(fifteenAgo, 'minute')) {
|
||||
return fs.unlinkAsync(path.join(uploadsTempPath, f.filename))
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return Promise.map(ls, (f) => {
|
||||
return fs.statAsync(path.join(uploadsTempPath, f)).then((s) => { return { filename: f, stat: s } })
|
||||
}).filter((s) => { return s.stat.isFile() }).then((arrFiles) => {
|
||||
return Promise.map(arrFiles, (f) => {
|
||||
if (moment(f.stat.ctime).isBefore(fifteenAgo, 'minute')) {
|
||||
return fs.unlinkAsync(path.join(uploadsTempPath, f.filename))
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
// ----------------------------------------
|
||||
// Run
|
||||
// ----------------------------------------
|
||||
|
||||
Promise.all(jobs).then(() => {
|
||||
winston.info('[AGENT] All jobs completed successfully! Going to sleep for now.')
|
||||
|
||||
if (!jobUplWatchStarted) {
|
||||
jobUplWatchStarted = true
|
||||
upl.initialScan().then(() => {
|
||||
job.start()
|
||||
})
|
||||
}
|
||||
|
||||
return true
|
||||
}).catch((err) => {
|
||||
winston.error('[AGENT] One or more jobs have failed: ', err)
|
||||
}).finally(() => {
|
||||
jobIsBusy = false
|
||||
})
|
||||
)
|
||||
},
|
||||
start: false,
|
||||
timeZone: 'UTC',
|
||||
runOnInit: true
|
||||
})
|
||||
|
||||
// ----------------------------------------
|
||||
// Run
|
||||
// ----------------------------------------
|
||||
|
||||
Promise.all(jobs).then(() => {
|
||||
winston.info('[AGENT] All jobs completed successfully! Going to sleep for now.')
|
||||
|
||||
if (!jobUplWatchStarted) {
|
||||
jobUplWatchStarted = true
|
||||
upl.initialScan().then(() => {
|
||||
job.start()
|
||||
})
|
||||
}
|
||||
|
||||
return true
|
||||
}).catch((err) => {
|
||||
winston.error('[AGENT] One or more jobs have failed: ', err)
|
||||
}).finally(() => {
|
||||
jobIsBusy = false
|
||||
})
|
||||
},
|
||||
start: false,
|
||||
timeZone: 'UTC',
|
||||
runOnInit: true
|
||||
})
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
@@ -50,4 +50,26 @@ defaults:
|
||||
signature:
|
||||
name: Wiki
|
||||
email: wiki@example.com
|
||||
langs:
|
||||
-
|
||||
id: en
|
||||
name: English
|
||||
-
|
||||
id: fr
|
||||
name: French - Français
|
||||
-
|
||||
id: de
|
||||
name: German - Deutsch
|
||||
-
|
||||
id: ko
|
||||
name: Korean - 한국어
|
||||
-
|
||||
id: pt
|
||||
name: Portuguese - Português
|
||||
-
|
||||
id: ru
|
||||
name: Russian - Русский
|
||||
-
|
||||
id: es
|
||||
name: Spanish - Español
|
||||
# ---------------------------------
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
"use strict";jQuery(document).ready(function(t){new Vue({el:"main",data:{loading:!1,state:"considerations",syscheck:{ok:!1,error:"",results:[]},conf:{title:"Wiki",host:"",port:80,lang:"en",db:"mongodb://localhost:27017/wiki"},considerations:{https:!1,port:!1,localhost:!1}},methods:{proceedToWelcome:function(t){this.state="welcome",this.loading=!1},proceedToSyscheck:function(t){var s=this;this.state="syscheck",this.loading=!0,s.syscheck={ok:!1,error:"",results:[]},_.delay(function(){axios.post("/syscheck").then(function(t){t.data.ok===!0?(s.syscheck.ok=!0,s.syscheck.results=t.data.results):(s.syscheck.ok=!1,s.syscheck.error=t.data.error),s.loading=!1,s.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToGeneral:function(t){this.state="general",this.loading=!1},proceedToConsiderations:function(t){this.considerations={https:!_.startsWith(this.conf.host,"https"),port:!1,localhost:_.includes(this.conf.host,"localhost")},this.state="considerations",this.loading=!1},proceedToDb:function(t){this.state="db",this.loading=!1}}})});
|
||||
"use strict";Vue.use(VeeValidate,{enableAutoClasses:!0,classNames:{touched:"is-touched",untouched:"is-untouched",valid:"is-valid",invalid:"is-invalid",pristine:"is-pristine",dirty:"is-dirty"}}),jQuery(document).ready(function(t){new Vue({el:"main",data:{loading:!1,state:"welcome",syscheck:{ok:!1,error:"",results:[]},dbcheck:{ok:!1,error:""},gitcheck:{ok:!1,error:""},final:{ok:!1,error:"",results:[]},conf:{title:"Wiki",host:"http://",port:80,lang:"en",db:"mongodb://localhost:27017/wiki",pathData:"./data",pathRepo:"./repo",gitUrl:"",gitBranch:"master",gitAuthType:"ssh",gitAuthSSHKey:"",gitAuthUser:"",gitAuthPass:"",gitAuthSSL:!0,gitSignatureName:"",gitSignatureEmail:"",adminEmail:"",adminPassword:"",adminPasswordConfirm:""},considerations:{https:!1,port:!1,localhost:!1}},computed:{currentProgress:function(){var t="0%";switch(this.state){case"welcome":t="0%";break;case"syscheck":t=this.syscheck.ok?"15%":"5%";break;case"general":t="20%";break;case"considerations":t="30%";break;case"db":t="35%";break;case"dbcheck":t=this.dbcheck.ok?"50%":"40%";break;case"paths":t="55%";break;case"git":t="60%";break;case"gitcheck":t=this.gitcheck.ok?"75%":"65%";break;case"admin":t="80%"}return t}},methods:{proceedToWelcome:function(t){this.state="welcome",this.loading=!1},proceedToSyscheck:function(t){var e=this;this.state="syscheck",this.loading=!0,e.syscheck={ok:!1,error:"",results:[]},_.delay(function(){axios.post("/syscheck").then(function(t){t.data.ok===!0?(e.syscheck.ok=!0,e.syscheck.results=t.data.results):(e.syscheck.ok=!1,e.syscheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToGeneral:function(t){var e=this;e.state="general",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("general")})},proceedToConsiderations:function(t){this.considerations={https:!_.startsWith(this.conf.host,"https"),port:!1,localhost:_.includes(this.conf.host,"localhost")},this.state="considerations",this.loading=!1},proceedToDb:function(t){var e=this;e.state="db",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("db")})},proceedToDbcheck:function(t){var e=this;this.state="dbcheck",this.loading=!0,e.dbcheck={ok:!1,error:""},_.delay(function(){axios.post("/dbcheck",{db:e.conf.db}).then(function(t){t.data.ok===!0?e.dbcheck.ok=!0:(e.dbcheck.ok=!1,e.dbcheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToPaths:function(t){var e=this;e.state="paths",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("paths")})},proceedToGit:function(t){var e=this;e.state="git",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("git")})},proceedToGitCheck:function(t){var e=this;this.state="gitcheck",this.loading=!0,e.dbcheck={ok:!1,error:""},_.delay(function(){axios.post("/gitcheck",e.conf).then(function(t){t.data.ok===!0?e.gitcheck.ok=!0:(e.gitcheck.ok=!1,e.gitcheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToAdmin:function(t){var e=this;e.state="admin",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("admin")})},proceedToFinal:function(t){var e=this;e.state="final",e.loading=!0,e.final={ok:!1,error:"",results:[]},_.delay(function(){axios.post("/finalize",e.conf).then(function(t){t.data.ok===!0?(e.final.ok=!0,e.final.results=t.data.results):(e.final.ok=!1,e.final.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},finish:function(t){}}})});
|
||||
+33
-32
File diff suppressed because one or more lines are too long
@@ -93,6 +93,7 @@ if ($('#mk-editor').length === 1) {
|
||||
mdeModalOpenState = true;
|
||||
$('#modal-editor-link').slideToggle();
|
||||
} */
|
||||
window.alert('Coming soon!')
|
||||
},
|
||||
className: 'icon-link2',
|
||||
title: 'Insert Link'
|
||||
@@ -163,6 +164,7 @@ if ($('#mk-editor').length === 1) {
|
||||
{
|
||||
name: 'table',
|
||||
action: (editor) => {
|
||||
window.alert('Coming soon!')
|
||||
// todo
|
||||
},
|
||||
className: 'icon-table',
|
||||
|
||||
+196
-8
@@ -1,24 +1,63 @@
|
||||
'use strict'
|
||||
|
||||
/* global jQuery, _, Vue, axios */
|
||||
/* global jQuery, _, Vue, VeeValidate, axios */
|
||||
|
||||
Vue.use(VeeValidate, {
|
||||
enableAutoClasses: true,
|
||||
classNames: {
|
||||
touched: 'is-touched', // the control has been blurred
|
||||
untouched: 'is-untouched', // the control hasn't been blurred
|
||||
valid: 'is-valid', // model is valid
|
||||
invalid: 'is-invalid', // model is invalid
|
||||
pristine: 'is-pristine', // control has not been interacted with
|
||||
dirty: 'is-dirty' // control has been interacted with
|
||||
}
|
||||
})
|
||||
|
||||
jQuery(document).ready(function ($) {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
el: 'main',
|
||||
data: {
|
||||
loading: false,
|
||||
state: 'considerations',
|
||||
state: 'welcome',
|
||||
syscheck: {
|
||||
ok: false,
|
||||
error: '',
|
||||
results: []
|
||||
},
|
||||
dbcheck: {
|
||||
ok: false,
|
||||
error: ''
|
||||
},
|
||||
gitcheck: {
|
||||
ok: false,
|
||||
error: ''
|
||||
},
|
||||
final: {
|
||||
ok: false,
|
||||
error: '',
|
||||
results: []
|
||||
},
|
||||
conf: {
|
||||
title: 'Wiki',
|
||||
host: '',
|
||||
host: 'http://',
|
||||
port: 80,
|
||||
lang: 'en',
|
||||
db: 'mongodb://localhost:27017/wiki'
|
||||
db: 'mongodb://localhost:27017/wiki',
|
||||
pathData: './data',
|
||||
pathRepo: './repo',
|
||||
gitUrl: '',
|
||||
gitBranch: 'master',
|
||||
gitAuthType: 'ssh',
|
||||
gitAuthSSHKey: '',
|
||||
gitAuthUser: '',
|
||||
gitAuthPass: '',
|
||||
gitAuthSSL: true,
|
||||
gitSignatureName: '',
|
||||
gitSignatureEmail: '',
|
||||
adminEmail: '',
|
||||
adminPassword: '',
|
||||
adminPasswordConfirm: ''
|
||||
},
|
||||
considerations: {
|
||||
https: false,
|
||||
@@ -26,6 +65,44 @@ jQuery(document).ready(function ($) {
|
||||
localhost: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentProgress: function () {
|
||||
let perc = '0%'
|
||||
switch (this.state) {
|
||||
case 'welcome':
|
||||
perc = '0%'
|
||||
break
|
||||
case 'syscheck':
|
||||
perc = (this.syscheck.ok) ? '15%' : '5%'
|
||||
break
|
||||
case 'general':
|
||||
perc = '20%'
|
||||
break
|
||||
case 'considerations':
|
||||
perc = '30%'
|
||||
break
|
||||
case 'db':
|
||||
perc = '35%'
|
||||
break
|
||||
case 'dbcheck':
|
||||
perc = (this.dbcheck.ok) ? '50%' : '40%'
|
||||
break
|
||||
case 'paths':
|
||||
perc = '55%'
|
||||
break
|
||||
case 'git':
|
||||
perc = '60%'
|
||||
break
|
||||
case 'gitcheck':
|
||||
perc = (this.gitcheck.ok) ? '75%' : '65%'
|
||||
break
|
||||
case 'admin':
|
||||
perc = '80%'
|
||||
break
|
||||
}
|
||||
return perc
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
proceedToWelcome: function (ev) {
|
||||
this.state = 'welcome'
|
||||
@@ -58,8 +135,12 @@ jQuery(document).ready(function ($) {
|
||||
}, 1000)
|
||||
},
|
||||
proceedToGeneral: function (ev) {
|
||||
this.state = 'general'
|
||||
this.loading = false
|
||||
let self = this
|
||||
self.state = 'general'
|
||||
self.loading = false
|
||||
self.$nextTick(() => {
|
||||
self.$validator.validateAll('general')
|
||||
})
|
||||
},
|
||||
proceedToConsiderations: function (ev) {
|
||||
this.considerations = {
|
||||
@@ -71,8 +152,115 @@ jQuery(document).ready(function ($) {
|
||||
this.loading = false
|
||||
},
|
||||
proceedToDb: function (ev) {
|
||||
this.state = 'db'
|
||||
this.loading = false
|
||||
let self = this
|
||||
self.state = 'db'
|
||||
self.loading = false
|
||||
self.$nextTick(() => {
|
||||
self.$validator.validateAll('db')
|
||||
})
|
||||
},
|
||||
proceedToDbcheck: function (ev) {
|
||||
let self = this
|
||||
this.state = 'dbcheck'
|
||||
this.loading = true
|
||||
self.dbcheck = {
|
||||
ok: false,
|
||||
error: ''
|
||||
}
|
||||
|
||||
_.delay(() => {
|
||||
axios.post('/dbcheck', {
|
||||
db: self.conf.db
|
||||
}).then(resp => {
|
||||
if (resp.data.ok === true) {
|
||||
self.dbcheck.ok = true
|
||||
} else {
|
||||
self.dbcheck.ok = false
|
||||
self.dbcheck.error = resp.data.error
|
||||
}
|
||||
self.loading = false
|
||||
self.$nextTick()
|
||||
}).catch(err => {
|
||||
window.alert(err.message)
|
||||
})
|
||||
}, 1000)
|
||||
},
|
||||
proceedToPaths: function (ev) {
|
||||
let self = this
|
||||
self.state = 'paths'
|
||||
self.loading = false
|
||||
self.$nextTick(() => {
|
||||
self.$validator.validateAll('paths')
|
||||
})
|
||||
},
|
||||
proceedToGit: function (ev) {
|
||||
let self = this
|
||||
self.state = 'git'
|
||||
self.loading = false
|
||||
self.$nextTick(() => {
|
||||
self.$validator.validateAll('git')
|
||||
})
|
||||
},
|
||||
proceedToGitCheck: function (ev) {
|
||||
let self = this
|
||||
this.state = 'gitcheck'
|
||||
this.loading = true
|
||||
self.dbcheck = {
|
||||
ok: false,
|
||||
error: ''
|
||||
}
|
||||
|
||||
_.delay(() => {
|
||||
axios.post('/gitcheck', self.conf).then(resp => {
|
||||
if (resp.data.ok === true) {
|
||||
self.gitcheck.ok = true
|
||||
} else {
|
||||
self.gitcheck.ok = false
|
||||
self.gitcheck.error = resp.data.error
|
||||
}
|
||||
self.loading = false
|
||||
self.$nextTick()
|
||||
}).catch(err => {
|
||||
window.alert(err.message)
|
||||
})
|
||||
}, 1000)
|
||||
},
|
||||
proceedToAdmin: function (ev) {
|
||||
let self = this
|
||||
self.state = 'admin'
|
||||
self.loading = false
|
||||
self.$nextTick(() => {
|
||||
self.$validator.validateAll('admin')
|
||||
})
|
||||
},
|
||||
proceedToFinal: function (ev) {
|
||||
let self = this
|
||||
self.state = 'final'
|
||||
self.loading = true
|
||||
self.final = {
|
||||
ok: false,
|
||||
error: '',
|
||||
results: []
|
||||
}
|
||||
|
||||
_.delay(() => {
|
||||
axios.post('/finalize', self.conf).then(resp => {
|
||||
if (resp.data.ok === true) {
|
||||
self.final.ok = true
|
||||
self.final.results = resp.data.results
|
||||
} else {
|
||||
self.final.ok = false
|
||||
self.final.error = resp.data.error
|
||||
}
|
||||
self.loading = false
|
||||
self.$nextTick()
|
||||
}).catch(err => {
|
||||
window.alert(err.message)
|
||||
})
|
||||
}, 1000)
|
||||
},
|
||||
finish: function (ev) {
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
if ($('#page-type-edit').length) {
|
||||
let pageEntryPath = $('#page-type-edit').data('entrypath') // eslint-disable-line no-unused-vars
|
||||
// let pageCleanExit = false
|
||||
|
||||
// -> Discard
|
||||
|
||||
@@ -9,6 +10,10 @@ if ($('#page-type-edit').length) {
|
||||
$('#modal-edit-discard').toggleClass('is-active')
|
||||
})
|
||||
|
||||
// window.onbeforeunload = function () {
|
||||
// return (pageCleanExit) ? true : 'Unsaved modifications will be lost. Are you sure you want to navigate away from this page?'
|
||||
// }
|
||||
|
||||
/* eslint-disable spaced-comment */
|
||||
//=include ../components/editor.js
|
||||
/* eslint-enable spaced-comment */
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
|
||||
.editor-toolbar {
|
||||
z-index: 2;
|
||||
background-color: rgba(0,0,0,0.75);
|
||||
background-color: mc('indigo', '900');
|
||||
border: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
opacity: 1;
|
||||
position: fixed;
|
||||
top: 51px;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
||||
@@ -90,7 +90,7 @@ #btn-editor-image-upload, #btn-editor-file-upload {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ .editor-modal-image-choices {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
|
||||
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
@@ -140,7 +140,7 @@ .editor-modal-image-choices {
|
||||
|
||||
> span {
|
||||
font-size: 12px;
|
||||
|
||||
|
||||
> strong {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -358,4 +358,4 @@ #source-display, #codeblock-editor {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,3 +53,24 @@ .tst-welcome-leave-to, .tst-welcome-enter {
|
||||
max-height: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 150px;
|
||||
height: 10px;
|
||||
background-color: mc('indigo', '50');
|
||||
border:1px solid mc('indigo', '100');
|
||||
border-radius: 3px;
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 21px;
|
||||
padding: 1px;
|
||||
|
||||
> div {
|
||||
width: 5px;
|
||||
height: 6px;
|
||||
background-color: mc('indigo', '200');
|
||||
border-radius: 2px;
|
||||
transition: all 1s ease;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+115
-1
@@ -15,8 +15,11 @@ module.exports = (port, spinner) => {
|
||||
const http = require('http')
|
||||
const path = require('path')
|
||||
const Promise = require('bluebird')
|
||||
const fs = require('fs-extra')
|
||||
const yaml = require('js-yaml')
|
||||
const _ = require('lodash')
|
||||
|
||||
|
||||
// ----------------------------------------
|
||||
// Define Express App
|
||||
// ----------------------------------------
|
||||
@@ -48,9 +51,20 @@ module.exports = (port, spinner) => {
|
||||
// ----------------------------------------
|
||||
|
||||
app.get('*', (req, res) => {
|
||||
res.render('configure/index')
|
||||
let langs = []
|
||||
try {
|
||||
langs = yaml.safeLoad(fs.readFileSync('./app/data.yml', 'utf8')).langs
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
res.render('configure/index', {
|
||||
langs
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Perform basic system checks
|
||||
*/
|
||||
app.post('/syscheck', (req, res) => {
|
||||
Promise.mapSeries([
|
||||
() => {
|
||||
@@ -105,6 +119,106 @@ module.exports = (port, spinner) => {
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Check the DB connection
|
||||
*/
|
||||
app.post('/dbcheck', (req, res) => {
|
||||
let mongo = require('mongodb').MongoClient
|
||||
mongo.connect(req.body.db, {
|
||||
autoReconnect: false,
|
||||
reconnectTries: 2,
|
||||
reconnectInterval: 1000,
|
||||
connectTimeoutMS: 5000,
|
||||
socketTimeoutMS: 5000
|
||||
}, (err, db) => {
|
||||
if (err === null) {
|
||||
// Try to create a test collection
|
||||
db.createCollection('test', (err, results) => {
|
||||
if (err === null) {
|
||||
// Try to drop test collection
|
||||
db.dropCollection('test', (err, results) => {
|
||||
if (err === null) {
|
||||
res.json({ ok: true })
|
||||
} else {
|
||||
res.json({ ok: false, error: 'Unable to delete test collection. Verify permissions. ' + err.message })
|
||||
}
|
||||
db.close()
|
||||
})
|
||||
} else {
|
||||
res.json({ ok: false, error: 'Unable to create test collection. Verify permissions. ' + err.message })
|
||||
db.close()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
res.json({ ok: false, error: err.message })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Check the Git connection
|
||||
*/
|
||||
app.post('/gitcheck', (req, res) => {
|
||||
const exec = require('execa')
|
||||
|
||||
const dataDir = path.resolve(ROOTPATH, req.body.pathData)
|
||||
const gitDir = path.resolve(ROOTPATH, req.body.pathRepo)
|
||||
let results = []
|
||||
|
||||
fs.ensureDir(dataDir).then(() => {
|
||||
results.push('Data directory path is valid.')
|
||||
return fs.ensureDir(gitDir).then(() => {
|
||||
results.push('Git directory path is valid.')
|
||||
return true
|
||||
})
|
||||
}).then(() => {
|
||||
return exec.stdout('git', ['init'], { cwd: gitDir }).then(result => {
|
||||
results.push('Git local repository initialized.')
|
||||
return true
|
||||
})
|
||||
}).then(() => {
|
||||
return res.json({ ok: true, results })
|
||||
}).catch(err => {
|
||||
res.json({ ok: false, error: err.message })
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Check the DB connection
|
||||
*/
|
||||
app.post('/finalize', (req, res) => {
|
||||
let mongo = require('mongodb').MongoClient
|
||||
mongo.connect(req.body.db, {
|
||||
autoReconnect: false,
|
||||
reconnectTries: 2,
|
||||
reconnectInterval: 1000,
|
||||
connectTimeoutMS: 5000,
|
||||
socketTimeoutMS: 5000
|
||||
}, (err, db) => {
|
||||
if (err === null) {
|
||||
// Try to create a test collection
|
||||
db.createCollection('test', (err, results) => {
|
||||
if (err === null) {
|
||||
// Try to drop test collection
|
||||
db.dropCollection('test', (err, results) => {
|
||||
if (err === null) {
|
||||
res.json({ ok: true })
|
||||
} else {
|
||||
res.json({ ok: false, error: 'Unable to delete test collection. Verify permissions. ' + err.message })
|
||||
}
|
||||
db.close()
|
||||
})
|
||||
} else {
|
||||
res.json({ ok: false, error: 'Unable to create test collection. Verify permissions. ' + err.message })
|
||||
db.close()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
res.json({ ok: false, error: err.message })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// ----------------------------------------
|
||||
// Error handling
|
||||
// ----------------------------------------
|
||||
|
||||
@@ -27,6 +27,7 @@ const paths = {
|
||||
'./node_modules/socket.io-client/dist/socket.io.min.js',
|
||||
'./node_modules/jquery/dist/jquery.min.js',
|
||||
'./node_modules/vue/dist/vue.min.js',
|
||||
'./node_modules/vee-validate/dist/vee-validate.min.js',
|
||||
'./node_modules/axios/dist/axios.min.js',
|
||||
'./node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js',
|
||||
'./node_modules/jquery-simple-upload/simpleUpload.min.js',
|
||||
|
||||
+2
-58
@@ -152,7 +152,7 @@ module.exports = {
|
||||
return false
|
||||
}
|
||||
}).catch((err) => { // eslint-disable-line handle-callback-err
|
||||
return Promise.reject(new Promise.OperationalError('Entry ' + entryPath + ' does not exist!'))
|
||||
throw new Promise.OperationalError('Entry ' + entryPath + ' does not exist!')
|
||||
})
|
||||
},
|
||||
|
||||
@@ -299,8 +299,7 @@ module.exports = {
|
||||
_id: content.entryPath,
|
||||
title: content.meta.title || content.entryPath,
|
||||
subtitle: content.meta.subtitle || '',
|
||||
parent: content.parent.title || '',
|
||||
content: content.text || ''
|
||||
parent: content.parent.title || ''
|
||||
}, {
|
||||
new: true,
|
||||
upsert: true
|
||||
@@ -396,60 +395,5 @@ module.exports = {
|
||||
return fs.readFileAsync(path.join(ROOTPATH, 'client/content/create.md'), 'utf8').then((contents) => {
|
||||
return _.replace(contents, new RegExp('{TITLE}', 'g'), formattedTitle)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Searches entries based on terms.
|
||||
*
|
||||
* @param {String} terms The terms to search for
|
||||
* @return {Promise<Object>} Promise of the search results
|
||||
*/
|
||||
search (terms) {
|
||||
terms = _.chain(terms)
|
||||
.deburr()
|
||||
.toLower()
|
||||
.trim()
|
||||
.replace(/[^a-z0-9\- ]/g, '')
|
||||
.split(' ')
|
||||
.filter((f) => { return !_.isEmpty(f) })
|
||||
.join(' ')
|
||||
.value()
|
||||
|
||||
return db.Entry.find(
|
||||
{ $text: { $search: terms } },
|
||||
{ score: { $meta: 'textScore' }, title: 1 }
|
||||
)
|
||||
.sort({ score: { $meta: 'textScore' } })
|
||||
.limit(10)
|
||||
.exec()
|
||||
.then((hits) => {
|
||||
if (hits.length < 5) {
|
||||
let regMatch = new RegExp('^' + _.split(terms, ' ')[0])
|
||||
return db.Entry.find({
|
||||
_id: { $regex: regMatch }
|
||||
}, '_id')
|
||||
.sort('_id')
|
||||
.limit(5)
|
||||
.exec()
|
||||
.then((matches) => {
|
||||
return {
|
||||
match: hits,
|
||||
suggest: (matches) ? _.map(matches, '_id') : []
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return {
|
||||
match: _.filter(hits, (h) => { return h._doc.score >= 1 }),
|
||||
suggest: []
|
||||
}
|
||||
}
|
||||
}).catch((err) => {
|
||||
winston.error(err)
|
||||
return {
|
||||
match: [],
|
||||
suggest: []
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -231,10 +231,8 @@ module.exports = {
|
||||
*/
|
||||
generateThumbnail (sourcePath, destPath) {
|
||||
return jimp.read(sourcePath).then(img => {
|
||||
return img.cover(150, 150)
|
||||
.background(0xFFFFFFFF)
|
||||
.opaque()
|
||||
.rgba(false)
|
||||
return img
|
||||
.contain(150, 150)
|
||||
.write(destPath)
|
||||
})
|
||||
},
|
||||
|
||||
@@ -21,10 +21,6 @@ var entrySchema = Mongoose.Schema({
|
||||
parent: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
|
||||
},
|
||||
@@ -32,19 +28,4 @@ var entrySchema = Mongoose.Schema({
|
||||
timestamps: {}
|
||||
})
|
||||
|
||||
entrySchema.index({
|
||||
_id: 'text',
|
||||
title: 'text',
|
||||
subtitle: 'text',
|
||||
content: 'text'
|
||||
}, {
|
||||
weights: {
|
||||
_id: 3,
|
||||
title: 10,
|
||||
subtitle: 5,
|
||||
content: 1
|
||||
},
|
||||
name: 'EntriesTextIndex'
|
||||
})
|
||||
|
||||
module.exports = Mongoose.model('Entry', entrySchema)
|
||||
|
||||
+25
-22
@@ -41,7 +41,7 @@
|
||||
"bcryptjs-then": "^1.0.1",
|
||||
"bluebird": "^3.4.7",
|
||||
"body-parser": "^1.17.1",
|
||||
"bunyan": "^1.8.8",
|
||||
"bunyan": "^1.8.9",
|
||||
"cheerio": "^0.22.0",
|
||||
"child-process-promise": "^2.2.0",
|
||||
"chokidar": "^1.6.0",
|
||||
@@ -51,21 +51,22 @@
|
||||
"connect-mongo": "^1.3.2",
|
||||
"cookie-parser": "^1.4.3",
|
||||
"cron": "^1.2.1",
|
||||
"execa": "^0.6.3",
|
||||
"express": "^4.15.2",
|
||||
"express-brute": "^1.0.0",
|
||||
"express-brute-mongoose": "0.0.7",
|
||||
"express-session": "^1.15.1",
|
||||
"file-type": "^4.0.0",
|
||||
"filesize.js": "^1.0.2",
|
||||
"follow-redirects": "^1.2.1",
|
||||
"fs-extra": "^2.0.0",
|
||||
"follow-redirects": "^1.2.3",
|
||||
"fs-extra": "^2.1.2",
|
||||
"git-wrapper2-promise": "^0.2.9",
|
||||
"highlight.js": "^9.9.0",
|
||||
"i18next": "^7.1.1",
|
||||
"i18next-express-middleware": "^1.0.2",
|
||||
"i18next": "^7.1.3",
|
||||
"i18next-express-middleware": "^1.0.3",
|
||||
"i18next-node-fs-backend": "^0.1.3",
|
||||
"image-size": "^0.5.1",
|
||||
"jimp": "github:NGPixel/jimp",
|
||||
"jimp": "github:ngpixel/jimp",
|
||||
"js-yaml": "^3.8.1",
|
||||
"klaw": "^1.3.1",
|
||||
"levelup": "^1.3.5",
|
||||
@@ -80,12 +81,13 @@
|
||||
"markdown-it-footnote": "^3.0.1",
|
||||
"markdown-it-task-lists": "^1.4.1",
|
||||
"memdown": "^1.2.4",
|
||||
"mime-types": "^2.1.13",
|
||||
"moment": "^2.17.1",
|
||||
"mime-types": "^2.1.15",
|
||||
"moment": "^2.18.1",
|
||||
"moment-timezone": "^0.5.11",
|
||||
"mongoose": "^4.8.5",
|
||||
"mongodb": "^2.2.25",
|
||||
"mongoose": "^4.9.1",
|
||||
"multer": "^1.2.1",
|
||||
"ora": "^1.1.0",
|
||||
"ora": "^1.2.0",
|
||||
"passport": "^0.3.2",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport.socketio": "^3.7.0",
|
||||
@@ -94,11 +96,11 @@
|
||||
"read-chunk": "^2.0.0",
|
||||
"remove-markdown": "^0.1.0",
|
||||
"requarks-core": "^0.2.2",
|
||||
"request": "^2.80.0",
|
||||
"search-index-adder": "github:NGPixel/search-index-adder",
|
||||
"search-index-searcher": "github:NGPixel/search-index-searcher",
|
||||
"request": "^2.81.0",
|
||||
"search-index-adder": "github:ngpixel/search-index-adder",
|
||||
"search-index-searcher": "github:ngpixel/search-index-searcher",
|
||||
"semver": "^5.3.0",
|
||||
"serve-favicon": "^2.4.1",
|
||||
"serve-favicon": "^2.4.2",
|
||||
"simplemde": "^1.11.2",
|
||||
"socket.io": "^1.7.3",
|
||||
"sticky-js": "^1.0.7",
|
||||
@@ -112,16 +114,16 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"ace-builds": "^1.2.6",
|
||||
"babel-preset-es2015": "^6.16.0",
|
||||
"babel-preset-es2015": "^6.24.0",
|
||||
"chai": "^3.5.0",
|
||||
"chai-as-promised": "^6.0.0",
|
||||
"codacy-coverage": "^2.0.0",
|
||||
"eslint": "^3.16.1",
|
||||
"eslint": "^3.18.0",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-standard": "^2.1.1",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-babel": "^6.1.2",
|
||||
"gulp-clean-css": "^3.0.3",
|
||||
"gulp-clean-css": "^3.0.4",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-gzip": "^1.4.0",
|
||||
"gulp-include": "^2.3.1",
|
||||
@@ -129,12 +131,12 @@
|
||||
"gulp-plumber": "^1.1.0",
|
||||
"gulp-sass": "^3.0.0",
|
||||
"gulp-tar": "^1.9.0",
|
||||
"gulp-uglify": "^2.0.0",
|
||||
"gulp-uglify": "^2.1.2",
|
||||
"gulp-watch": "^4.3.11",
|
||||
"gulp-zip": "^4.0.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"jquery": "^3.1.1",
|
||||
"jquery-contextmenu": "^2.4.3",
|
||||
"jquery": "^3.2.1",
|
||||
"jquery-contextmenu": "^2.4.4",
|
||||
"jquery-simple-upload": "^1.0.0",
|
||||
"jquery-smooth-scroll": "^2.0.0",
|
||||
"merge-stream": "^1.0.1",
|
||||
@@ -144,10 +146,11 @@
|
||||
"pug-lint": "^2.4.0",
|
||||
"run-sequence": "^1.2.2",
|
||||
"snyk": "^1.25.1",
|
||||
"standard": "^9.0.0",
|
||||
"standard": "^9.0.2",
|
||||
"sticky-js": "^1.1.9",
|
||||
"twemoji-awesome": "^1.0.4",
|
||||
"vue": "^2.2.1"
|
||||
"vee-validate": "^2.0.0-beta.25",
|
||||
"vue": "^2.2.5"
|
||||
},
|
||||
"standard": {
|
||||
"globals": [
|
||||
|
||||
+238
-12
@@ -36,6 +36,11 @@ html
|
||||
h1 Welcome to Wiki.js!
|
||||
h2(style={'margin-bottom': 0}) A modern, lightweight and powerful wiki app built on NodeJS, Git and Markdown
|
||||
.content(v-cloak)
|
||||
|
||||
//- ==============================================
|
||||
//- WELCOME
|
||||
//- ==============================================
|
||||
|
||||
template(v-if='state === "welcome"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
@@ -45,8 +50,13 @@ html
|
||||
p This installation wizard will guide you through the steps needed to get your wiki up and running in no time!
|
||||
p Detailed information about installation and usage can be found on the #[a(href='https://docs.wiki.requarks.io/') official documentation site]. #[br] Should you have any question or would like to report something that doesn't look right, feel free to create a new issue on the #[a(href='https://github.com/Requarks/wiki/issues') GitHub project].
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Start
|
||||
|
||||
//- ==============================================
|
||||
//- SYSTEM CHECK
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "syscheck"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
@@ -62,10 +72,15 @@ html
|
||||
strong Looks good! No issues so far.
|
||||
p(v-if='!loading && !syscheck.ok') #[i.icon-square-cross] Error: {{ syscheck.error }}
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToWelcome', v-bind:disabled='loading') Back
|
||||
button.button.is-teal(v-on:click='proceedToSyscheck', v-if='!loading && !syscheck.ok') Check Again
|
||||
button.button.is-indigo(v-on:click='proceedToGeneral', v-if='loading || syscheck.ok', v-bind:disabled='loading') Continue
|
||||
|
||||
//- ==============================================
|
||||
//- GENERAL
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "general"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
@@ -75,27 +90,33 @@ html
|
||||
section
|
||||
p.control.is-fullwidth
|
||||
label.label Site Title
|
||||
input(type='text', placeholder='e.g. Wiki', v-model='conf.title')
|
||||
p.desc The site title will appear in the top left corner on every page and within the window title bar.
|
||||
input(type='text', placeholder='e.g. Wiki', v-model='conf.title', data-vv-scope='general', name='ipt-title', v-validate='{ required: true, min: 2 }')
|
||||
span.desc The site title will appear in the top left corner on every page and within the window title bar.
|
||||
section
|
||||
p.control.is-fullwidth
|
||||
label.label Host
|
||||
input(type='text', placeholder='http://', v-model='conf.host')
|
||||
p.desc The full URL to your wiki, without the trailing slash. E.g.: http://wiki.domain.com. Note that sub-folders are not supported.
|
||||
input(type='text', placeholder='http://', v-model='conf.host', data-vv-scope='general', name='ipt-host', v-validate='{ required: true, url: true }')
|
||||
span.desc The full URL to your wiki, without the trailing slash. E.g.: http://wiki.domain.com. Note that sub-folders are not supported.
|
||||
section
|
||||
p.control
|
||||
label.label Port
|
||||
input(type='text', placeholder='e.g. 80', v-model='conf.port')
|
||||
p.desc The port on which Wiki.js will listen to. Usually port 80 if connecting directly, or a random port (e.g. 3000) if using a web server in front of it.
|
||||
input(type='text', placeholder='e.g. 80', v-model.number='conf.port', data-vv-scope='general', name='ipt-port', v-validate='{ required: true, numeric: true, min_value: 1, max_value: 65535 }')
|
||||
span.desc The port on which Wiki.js will listen to. Usually port 80 if connecting directly, or a random port (e.g. 3000) if using a web server in front of it.
|
||||
section
|
||||
p.control
|
||||
label.label Site UI Language
|
||||
select(v-model='conf.lang')
|
||||
option(value='en') English
|
||||
p.desc The language in which navigation, help and other UI elements will be displayed.
|
||||
each lg in langs
|
||||
option(value=lg.id)= lg.name
|
||||
span.desc The language in which navigation, help and other UI elements will be displayed.
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Back
|
||||
button.button.is-indigo(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Continue
|
||||
button.button.is-indigo(v-on:click='proceedToConsiderations', v-bind:disabled='loading || errors.any("general")') Continue
|
||||
|
||||
//- ==============================================
|
||||
//- CONSIDERATIONS
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "considerations"')
|
||||
.panel
|
||||
@@ -120,23 +141,228 @@ html
|
||||
h3 Are you sure you want to use localhost as the host base URL? #[i.icon-warning-outline.animated.fadeOut.infinite]
|
||||
p The host URL you specified is localhost. Unless you are a developer running Wiki.js locally on your machine, this is not recommended!
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToGeneral', v-bind:disabled='loading') Back
|
||||
button.button.is-indigo(v-on:click='proceedToDb', v-bind:disabled='loading') Continue
|
||||
|
||||
//- ==============================================
|
||||
//- DATABASE
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "db"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
span Database
|
||||
i(v-if='loading')
|
||||
.panel-content.is-text
|
||||
p Wiki.js stores administrative data such as users, permissions and assets metadata in a MongoDB database. Article contents and uploads are <u>not</u> stored in the DB. Instead, they are stored on-disk and synced automatically with a remote git repository of your choice.
|
||||
.panel-content.form-sections
|
||||
section
|
||||
p.control.is-fullwidth
|
||||
label.label MongoDB Connection String
|
||||
input(type='text', placeholder='e.g. mongodb://localhost:27017/wiki', v-model='conf.db')
|
||||
p.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server.
|
||||
input(type='text', placeholder='e.g. mongodb://localhost:27017/wiki', v-model='conf.db', data-vv-scope='db', name='ipt-db', v-validate='{ required: true, min: 14 }')
|
||||
span.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server.
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Back
|
||||
button.button.is-indigo(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Connect
|
||||
button.button.is-indigo(v-on:click='proceedToDbcheck', v-bind:disabled='loading || errors.any("db")') Connect
|
||||
|
||||
//- ==============================================
|
||||
//- DATABASE CHECK
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "dbcheck"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
span Database Check
|
||||
i(v-if='loading')
|
||||
.panel-content.is-text
|
||||
p(v-if='loading') #[i.icon-loader.animated.rotateIn.infinite] Testing the connection to MongoDB...
|
||||
p(v-if='!loading && dbcheck.ok')
|
||||
i.icon-check
|
||||
strong Connected successfully!
|
||||
p(v-if='!loading && !dbcheck.ok') #[i.icon-square-cross] Error: {{ dbcheck.error }}
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
|
||||
button.button.is-teal(v-on:click='proceedToDbcheck', v-if='!loading && !dbcheck.ok') Try Again
|
||||
button.button.is-indigo(v-on:click='proceedToPaths', v-if='loading || dbcheck.ok', v-bind:disabled='loading') Continue
|
||||
|
||||
//- ==============================================
|
||||
//- PATHS
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "paths"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
span Paths
|
||||
i(v-if='loading')
|
||||
.panel-content.is-text
|
||||
p It is recommended to leave the default values.
|
||||
.panel-content.form-sections
|
||||
section
|
||||
p.control.is-fullwidth
|
||||
label.label Local Data Path
|
||||
input(type='text', placeholder='e.g. ./data', v-model='conf.pathData', data-vv-scope='paths', name='ipt-datapath', v-validate='{ required: true, min: 2 }')
|
||||
span.desc The path where cache (processed content, thumbnails, search index, etc.) will be stored on disk.
|
||||
section
|
||||
p.control.is-fullwidth
|
||||
label.label Local Repository Path
|
||||
input(type='text', placeholder='e.g. ./repo', v-model='conf.pathRepo', data-vv-scope='paths', name='ipt-repopath', v-validate='{ required: true, min: 2 }')
|
||||
span.desc The path where the local git repository will be created, used to store content in markdown files and uploads.
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
|
||||
button.button.is-indigo(v-on:click='proceedToGit', v-bind:disabled='loading || errors.any("paths")') Continue
|
||||
|
||||
//- ==============================================
|
||||
//- GIT
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "git"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
span Git Repository
|
||||
i(v-if='loading')
|
||||
.panel-content.is-text
|
||||
p Wiki.js stores article content and uploads locally on disk. All content is then regularly kept in sync with a remote git repository. This acts a backup protection and provides history / revert features. While optional, it is <strong>HIGHLY</strong> recommended to setup the remote git repository connection.
|
||||
.panel-content.form-sections
|
||||
section.columns
|
||||
.column.is-two-thirds
|
||||
p.control.is-fullwidth
|
||||
label.label Repository URL
|
||||
input(type='text', placeholder='e.g. git@github.com/org/repo.git or https://github.com/org/repo', v-model='conf.gitUrl', data-vv-scope='git', name='ipt-giturl', v-validate='{ required: true, min: 5 }')
|
||||
span.desc The full git repository URL to connect to.
|
||||
.column
|
||||
p.control.is-fullwidth
|
||||
label.label Branch
|
||||
input(type='text', placeholder='e.g. master', v-model='conf.gitBranch', data-vv-scope='git', name='ipt-gitbranch', v-validate='{ required: true, min: 2 }')
|
||||
span.desc The git branch to use when synchronizing changes.
|
||||
section.columns
|
||||
.column.is-one-third
|
||||
p.control.is-fullwidth
|
||||
label.label Authentication
|
||||
select(v-model='conf.gitAuthType')
|
||||
option(value='ssh') SSH (recommended)
|
||||
option(value='basic') Basic
|
||||
span.desc The authentication method used to connect to your remote Git repository.
|
||||
p.control.is-fullwidth
|
||||
input#ipt-git-verify-ssl(type='checkbox', v-model='conf.gitAuthSSL')
|
||||
label.label(for='ipt-git-verify-ssl') Verify SSL
|
||||
.column(v-show='conf.gitAuthType === "basic"')
|
||||
p.control.is-fullwidth
|
||||
label.label Username
|
||||
input(type='text', v-model='conf.gitUrl')
|
||||
span.desc The username for the remote git connection.
|
||||
.column(v-show='conf.gitAuthType === "basic"')
|
||||
p.control.is-fullwidth
|
||||
label.label Password
|
||||
input(type='password', v-model='conf.gitUrl')
|
||||
span.desc The password for the remote git connection.
|
||||
.column(v-show='conf.gitAuthType === "ssh"')
|
||||
p.control.is-fullwidth
|
||||
label.label Private Key location
|
||||
input(type='text', placeholder='e.g. /etc/wiki/keys/git.pem')
|
||||
span.desc The full path to the private key on disk.
|
||||
section.columns
|
||||
.column
|
||||
p.control.is-fullwidth
|
||||
label.label Sync User Name
|
||||
input(type='text', placeholder='e.g. John Smith', v-model.number='conf.gitSignatureName', data-vv-scope='git', name='ipt-gitsigname', v-validate='{ required: true }')
|
||||
span.desc The name to use when pushing commits to the git repository.
|
||||
.column
|
||||
p.control.is-fullwidth
|
||||
label.label Sync User Email
|
||||
input(type='text', placeholder='e.g. user@example.com', v-model.number='conf.gitSignatureEmail', data-vv-scope='git', name='ipt-gitsigemail', v-validate='{ required: true, email: true }')
|
||||
span.desc The email to use when pushing commits to the git repository.
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToAdmin', v-bind:disabled='loading') Skip this step
|
||||
button.button.is-indigo(v-on:click='proceedToGitCheck', v-bind:disabled='loading || errors.any("git")') Continue
|
||||
|
||||
//- ==============================================
|
||||
//- GIT CHECK
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "gitcheck"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
span Git Repository Check
|
||||
i(v-if='loading')
|
||||
.panel-content.is-text
|
||||
p(v-if='loading') #[i.icon-loader.animated.rotateIn.infinite] Testing the connection to Git repository...
|
||||
p(v-if='!loading && gitcheck.ok')
|
||||
ul
|
||||
li(v-for='rs in gitcheck.results') #[i.icon-check] {{rs}}
|
||||
p(v-if='!loading && gitcheck.ok')
|
||||
i.icon-check
|
||||
strong Git settings are correct!
|
||||
p(v-if='!loading && !gitcheck.ok') #[i.icon-square-cross] Error: {{ gitcheck.error }}
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
|
||||
button.button.is-teal(v-on:click='proceedToGitCheck', v-if='!loading && !gitcheck.ok') Try Again
|
||||
button.button.is-indigo(v-on:click='proceedToAdmin', v-if='loading || gitcheck.ok', v-bind:disabled='loading') Continue
|
||||
|
||||
//- ==============================================
|
||||
//- ADMINISTRATOR ACCOUNT
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "admin"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
span Administrator Account
|
||||
i(v-if='loading')
|
||||
.panel-content.is-text
|
||||
p An administrator account will be created for local authentication. From this account, you can create or authorize more users.
|
||||
.panel-content.form-sections
|
||||
section
|
||||
p.control.is-fullwidth
|
||||
label.label Administrator Email
|
||||
input(type='text', placeholder='e.g. admin@example.com', v-model='conf.adminEmail', data-vv-scope='admin', name='ipt-adminemail', v-validate='{ required: true, email: true }')
|
||||
span.desc The full git repository URL to connect to.
|
||||
section.columns
|
||||
.column
|
||||
p.control.is-fullwidth
|
||||
label.label Password
|
||||
input(type='password', v-model='conf.adminPassword', data-vv-scope='admin', name='ipt-adminpwd', v-validate='{ required: true, min: 8 }')
|
||||
span.desc The full git repository URL to connect to.
|
||||
.column
|
||||
p.control.is-fullwidth
|
||||
label.label Confirm Password
|
||||
input(type='password', v-model='conf.adminPasswordConfirm', data-vv-scope='admin', name='ipt-adminpwd2', v-validate='{ required: true, confirmed: "ipt-adminpwd" }')
|
||||
span.desc The git branch to use when synchronizing changes.
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
|
||||
button.button.is-indigo(v-on:click='proceedToFinal', v-bind:disabled='loading || errors.any("admin")') Continue
|
||||
|
||||
//- ==============================================
|
||||
//- FINAL
|
||||
//- ==============================================
|
||||
|
||||
template(v-else-if='state === "final"')
|
||||
.panel
|
||||
h2.panel-title.is-featured
|
||||
span Finalizing
|
||||
i(v-if='loading')
|
||||
.panel-content.is-text
|
||||
p(v-if='loading') #[i.icon-loader.animated.rotateIn.infinite] Finalizing your installation...
|
||||
p(v-if='!loading && final.ok')
|
||||
ul
|
||||
li(v-for='rs in final.results') #[i.icon-check] {{rs}}
|
||||
p(v-if='!loading && final.ok')
|
||||
i.icon-check
|
||||
strong Wiki.js was configured successfully and is now ready for use.
|
||||
p(v-if='!loading && final.ok')
|
||||
| Click the <strong>Start</strong> button below to start the Wiki.js server.
|
||||
p(v-if='!loading && !final.ok') #[i.icon-square-cross] Error: {{ final.error }}
|
||||
.panel-footer
|
||||
.progress-bar: div(v-bind:style='{width: currentProgress}')
|
||||
button.button.is-indigo.is-outlined(v-on:click='proceedToWelcome', v-bind:disabled='loading') Back
|
||||
button.button.is-teal(v-on:click='proceedToFinal', v-if='!loading && !final.ok') Try Again
|
||||
button.button.is-green(v-on:click='finish', v-if='loading || final.ok', v-bind:disabled='loading') Start
|
||||
|
||||
footer.footer
|
||||
span
|
||||
|
||||
Reference in New Issue
Block a user