setup wizard intro + syscheck

This commit is contained in:
NGPixel 2017-03-04 23:20:22 -05:00
parent 48e7ea2e30
commit d8fa6ecc27
11 changed files with 205 additions and 51 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
assets/js/configure.js Normal file
View File

@ -0,0 +1 @@
"use strict";jQuery(document).ready(function(e){new Vue({el:"main",data:{loading:!1,state:"welcome",syscheck:{ok:!1,error:""},conf:{title:"Wiki",host:""}},methods:{proceedToSyscheck:function(e){var t=this;this.state="syscheck",this.loading=!0,_.delay(function(){axios.post("/syscheck").then(function(e){e.data.ok===!0?t.syscheck.ok=!0:(t.syscheck.ok=!1,t.syscheck.error=e.data.error),t.loading=!1}).catch(function(e){window.alert(e.message)})},1e3)},proceedToGeneral:function(e){this.state="general",this.loading=!0}}})});

File diff suppressed because one or more lines are too long

46
client/js/configure.js Normal file
View File

@ -0,0 +1,46 @@
'use strict'
/* global jQuery, _, Vue, axios */
jQuery(document).ready(function ($) {
new Vue({ // eslint-disable-line no-new
el: 'main',
data: {
loading: false,
state: 'welcome',
syscheck: {
ok: false,
error: ''
},
conf: {
title: 'Wiki',
host: ''
}
},
methods: {
proceedToSyscheck: function (ev) {
let self = this
this.state = 'syscheck'
this.loading = true
_.delay(() => {
axios.post('/syscheck').then(resp => {
if (resp.data.ok === true) {
self.syscheck.ok = true
} else {
self.syscheck.ok = false
self.syscheck.error = resp.data.error
}
self.loading = false
}).catch(err => {
window.alert(err.message)
})
}, 1000)
},
proceedToGeneral: function (ev) {
this.state = 'general'
this.loading = true
}
}
})
})

View File

@ -25,3 +25,28 @@ $primary: 'indigo';
}
}
i.icon-loader {
display: inline-block;
color: mc('indigo', '500')
}
i.icon-check {
color: mc('green', '500')
}
i.icon-square-cross {
color: mc('red', '500')
}
.tst-welcome-leave-active {
transition: all .5s;
overflow-y: hidden;
}
.tst-welcome-leave {
opacity: 1;
max-height: 200px;
}
.tst-welcome-leave-to {
opacity: 0;
max-height: 0;
padding-top: 0;
}

View File

@ -14,6 +14,8 @@ module.exports = (port, spinner) => {
const favicon = require('serve-favicon')
const http = require('http')
const path = require('path')
const Promise = require('bluebird')
const _ = require('lodash')
// ----------------------------------------
// Define Express App
@ -49,6 +51,60 @@ module.exports = (port, spinner) => {
res.render('configure/index')
})
app.post('/syscheck', (req, res) => {
Promise.mapSeries([
() => {
const semver = require('semver')
if (!semver.satisfies(semver.clean(process.version), '>=4.6.0')) {
throw new Error('Node.js version is too old. Minimum is 4.6.0.')
}
return true
},
() => {
const os = require('os')
if (os.totalmem() < 1024 * 1024 * 512) {
throw new Error('Not enough memory. Minimum is 512 MB.')
}
return true
},
() => {
return Promise.try(() => {
require('crypto')
}).catch(err => { // eslint-disable-line handle-callback-err
throw new Error('Crypto Node.js module is not available.')
}).return(true)
},
() => {
const exec = require('child_process').exec
const semver = require('semver')
return new Promise((resolve, reject) => {
exec('git --version', (err, stdout, stderr) => {
if (err || stdout.length < 3) {
reject(new Error('Git is not installed or not reachable from PATH.'))
}
let gitver = _.chain(stdout.replace(/[^\d.]/g, '')).split('.').take(3).join('.').value()
if (!semver.satisfies(semver.clean(gitver), '>=2.11.0')) {
reject(new Error('Git version is too old. Minimum is 2.11.0.'))
}
resolve(true)
})
})
},
() => {
let fs = require('fs')
return Promise.try(() => {
fs.accessSync(path.join(ROOTPATH, 'config.yml'), (fs.constants || fs).W_OK)
}).catch(err => { // eslint-disable-line handle-callback-err
throw new Error('config.yml file is not writable by Node.js process or was not created properly.')
}).return(true)
}
], test => { return test() }).then(results => {
res.json({ ok: true })
}).catch(err => {
res.json({ ok: false, error: err.message })
})
})
// ----------------------------------------
// Error handling
// ----------------------------------------

View File

@ -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/axios/dist/axios.min.js',
'./node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js',
'./node_modules/jquery-simple-upload/simpleUpload.min.js',
'./node_modules/jquery-contextmenu/dist/jquery.contextMenu.min.js',

View File

@ -97,6 +97,7 @@
"request": "^2.79.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",
"simplemde": "^1.11.2",
"socket.io": "^1.7.3",

View File

@ -15,7 +15,7 @@ html
// JS
script(type='text/javascript', src='/js/libs.js')
//script(type='text/javascript', src='/js/app.js')
script(type='text/javascript', src='/js/configure.js')
block head
@ -24,32 +24,56 @@ html
#header-container
nav.nav#header
.nav-left
a.nav-item(href='/')
a.nav-item
h1
i.icon-layers
| Wiki.js
main
.container
.welcome(style={'padding-bottom': '5px'})
img(src='/favicons/android-icon-96x96.png', alt='Wiki.js')
h1 Welcome to Wiki.js!
h2(style={'margin-bottom': 0}) Fill in the fields below to get up and running.
.content
.panel
h2.panel-title
span General
i(v-if='loading')
.panel-content.form-sections
section
p.control.is-fullwidth
label.label Site Title
input(type='text', placeholder='e.g. Wiki', v-model='title')
section
p.control.is-fullwidth
label.label Host
input(type='text', placeholder='http://', v-model='host')
.panel-footer
button.button.is-indigo(v-on:click='add', v-bind:disabled='loading') Continue
transition(name='tst-welcome')
.welcome(style={'padding-bottom': '5px'}, v-if='state === "welcome"')
img(src='/favicons/android-icon-96x96.png', alt='Wiki.js')
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)
template(v-if='state === "welcome"')
.panel
h2.panel-title.is-featured
span Introduction
i(v-if='loading')
.panel-content.is-text
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
button.button.is-indigo(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Start
template(v-else-if='state === "syscheck"')
.panel
h2.panel-title.is-featured
span System Check
i(v-if='loading')
.panel-content.is-text
p(v-if='loading') #[i.icon-loader.animated.rotateIn.infinite] Checking your system for compatibility...
p(v-if='!loading && syscheck.ok') #[i.icon-check] Looks great! No issues so far.
p(v-if='!loading && !syscheck.ok') #[i.icon-square-cross] Error: {{ syscheck.error }}
.panel-footer
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
template(v-else-if='state === "general"')
.panel
h2.panel-title.is-featured
span General
i(v-if='loading')
.panel-content.form-sections
section
p.control.is-fullwidth
label.label Site Title
input(type='text', placeholder='e.g. Wiki', v-model='conf.title')
section
p.control.is-fullwidth
label.label Host
input(type='text', placeholder='http://', v-model='conf.host')
.panel-footer
button.button.is-indigo(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Continue
footer.footer
span
| Powered by