瀏覽代碼

feat: config-manager component

NGPixel 7 年之前
父節點
當前提交
c94e2d5700

+ 0 - 4
client/configure.js

@@ -1,4 +0,0 @@
-'use strict'
-
-require('./scss/configure.scss')
-require('./js/configure.js')

+ 2 - 0
client/js/app.js

@@ -52,6 +52,7 @@ import adminEditUserComponent from './pages/admin-edit-user.component.js'
 import adminProfileComponent from './pages/admin-profile.component.js'
 import adminSettingsComponent from './pages/admin-settings.component.js'
 import adminThemeComponent from './pages/admin-theme.component.js'
+import configManagerComponent from './components/config-manager.component.js'
 import contentViewComponent from './pages/content-view.component.js'
 import editorComponent from './components/editor.component.js'
 import sourceViewComponent from './pages/source-view.component.js'
@@ -94,6 +95,7 @@ Vue.component('adminSettings', adminSettingsComponent)
 Vue.component('adminTheme', adminThemeComponent)
 Vue.component('anchor', anchorComponent)
 Vue.component('colorPicker', colorPickerComponent)
+Vue.component('configManager', configManagerComponent)
 Vue.component('contentView', contentViewComponent)
 Vue.component('editor', editorComponent)
 Vue.component('editorCodeblock', editorCodeblockComponent)

+ 304 - 0
client/js/components/config-manager.component.js

@@ -0,0 +1,304 @@
+'use strict'
+
+/* global siteConfig */
+
+import VeeValidate from 'vee-validate'
+import axios from '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
+  }
+})
+
+export default {
+  name: 'configManager',
+  data() {
+    return {
+      loading: false,
+      state: 'welcome',
+      syscheck: {
+        ok: false,
+        error: '',
+        results: []
+      },
+      dbcheck: {
+        ok: false,
+        error: ''
+      },
+      gitcheck: {
+        ok: false,
+        error: ''
+      },
+      final: {
+        ok: false,
+        error: '',
+        results: []
+      },
+      conf: {
+        title: siteConfig.title || 'Wiki',
+        host: siteConfig.host || 'http://',
+        port: siteConfig.port || 80,
+        lang: siteConfig.lang || 'en',
+        public: (siteConfig.public === true),
+        db: siteConfig.db || 'mongodb://localhost:27017/wiki',
+        pathData: './data',
+        pathRepo: './repo',
+        gitUseRemote: (siteConfig.git !== false),
+        gitUrl: '',
+        gitBranch: 'master',
+        gitAuthType: 'ssh',
+        gitAuthSSHKey: '',
+        gitAuthUser: '',
+        gitAuthPass: '',
+        gitAuthSSL: true,
+        gitShowUserEmail: true,
+        gitServerEmail: '',
+        adminEmail: '',
+        adminPassword: '',
+        adminPasswordConfirm: ''
+      },
+      considerations: {
+        https: false,
+        port: false,
+        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
+    }
+  },
+  mounted: function () {
+    /* if (appconfig.paths) {
+      this.conf.pathData = appconfig.paths.data || './data'
+      this.conf.pathRepo = appconfig.paths.repo || './repo'
+    }
+    if (appconfig.git !== false && _.isPlainObject(appconfig.git)) {
+      this.conf.gitUrl = appconfig.git.url || ''
+      this.conf.gitBranch = appconfig.git.branch || 'master'
+      this.conf.gitShowUserEmail = (appconfig.git.showUserEmail !== false)
+      this.conf.gitServerEmail = appconfig.git.serverEmail || ''
+      if (_.isPlainObject(appconfig.git.auth)) {
+        this.conf.gitAuthType = appconfig.git.auth.type || 'ssh'
+        this.conf.gitAuthSSHKey = appconfig.git.auth.privateKey || ''
+        this.conf.gitAuthUser = appconfig.git.auth.username || ''
+        this.conf.gitAuthPass = appconfig.git.auth.password || ''
+        this.conf.gitAuthSSL = (appconfig.git.auth.sslVerify !== false)
+      }
+    } */
+  },
+  methods: {
+    proceedToWelcome: function (ev) {
+      this.state = 'welcome'
+      this.loading = false
+    },
+    proceedToSyscheck: function (ev) {
+      let self = this
+      this.state = 'syscheck'
+      this.loading = true
+      self.syscheck = {
+        ok: false,
+        error: '',
+        results: []
+      }
+
+      this.$helpers._.delay(() => {
+        axios.post('/syscheck').then(resp => {
+          if (resp.data.ok === true) {
+            self.syscheck.ok = true
+            self.syscheck.results = resp.data.results
+          } else {
+            self.syscheck.ok = false
+            self.syscheck.error = resp.data.error
+          }
+          self.loading = false
+          self.$nextTick()
+        }).catch(err => {
+          window.alert(err.message)
+        })
+      }, 1000)
+    },
+    proceedToGeneral: function (ev) {
+      let self = this
+      self.state = 'general'
+      self.loading = false
+      self.$nextTick(() => {
+        self.$validator.validateAll('general')
+      })
+    },
+    proceedToConsiderations: function (ev) {
+      this.considerations = {
+        https: !this.$helpers._.startsWith(this.conf.host, 'https'),
+        port: false, // TODO
+        localhost: this.$helpers._.includes(this.conf.host, 'localhost')
+      }
+      this.state = 'considerations'
+      this.loading = false
+    },
+    proceedToDb: function (ev) {
+      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: ''
+      }
+
+      this.$helpers._.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.gitcheck = {
+        ok: false,
+        results: [],
+        error: ''
+      }
+
+      this.$helpers._.delay(() => {
+        axios.post('/gitcheck', self.conf).then(resp => {
+          if (resp.data.ok === true) {
+            self.gitcheck.ok = true
+            self.gitcheck.results = resp.data.results
+          } 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: []
+      }
+
+      this.$helpers._.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) {
+      let self = this
+      self.state = 'restart'
+
+      this.$helpers._.delay(() => {
+        axios.post('/restart', {}).then(resp => {
+          this.$helpers._.delay(() => {
+            window.location.assign(self.conf.host)
+          }, 30000)
+        }).catch(err => {
+          window.alert(err.message)
+        })
+      }, 1000)
+    }
+  }
+}

+ 3 - 3
client/js/components/editor-video.vue

@@ -34,9 +34,9 @@
 
 <script>
   const videoRules = {
-    'youtube': new RegExp(/(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|&v(?:i)?=))([^#&?]*).*/, 'i'),
-    'vimeo': new RegExp(/vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/(?:[^/]*)\/videos\/|album\/(?:\d+)\/video\/|)(\d+)(?:$|\/|\?)/, 'i'),
-    'dailymotion': new RegExp(/(?:dailymotion\.com(?:\/embed)?(?:\/video|\/hub)|dai\.ly)\/([0-9a-z]+)(?:[-_0-9a-zA-Z]+(?:#video=)?([a-z0-9]+)?)?/, 'i')
+    'youtube': new RegExp('/(?:(?:youtu\\.be\\/|v\\/|vi\\/|u\\/\\w\\/|embed\\/)|(?:(?:watch)?\\?v(?:i)?=|&v(?:i)?=))([^#&?]*).*/', 'i'),
+    'vimeo': new RegExp('/vimeo.com\\/(?:channels\\/(?:\\w+\\/)?|groups\\/(?:[^/]*)\\/videos\\/|album\\/(?:\\d+)\\/video\\/|)(\\d+)(?:$|\\/|\\?)/', 'i'),
+    'dailymotion': new RegExp('/(?:dailymotion\\.com(?:\\/embed)?(?:\\/video|\\/hub)|dai\\.ly)\\/([0-9a-z]+)(?:[-_0-9a-zA-Z]+(?:#video=)?([a-z0-9]+)?)?/', 'i')
   }
 
   export default {

+ 1 - 0
client/scss/app.scss

@@ -15,6 +15,7 @@ $primary: 'indigo';
 @import 'components/button';
 @import 'components/collapsable-nav';
 @import 'components/color-picker';
+@import 'components/config-manager';
 @import 'components/footer';
 @import 'components/form';
 @import 'components/grid';

+ 5 - 1
client/scss/components/button.scss

@@ -97,7 +97,11 @@
       background-color: mc('grey', '300') !important;
       color: mc('grey', '500') !important;
     }
-	}
+  }
+
+  &.is-small {
+    height: 30px;
+  }
 
 }
 

+ 61 - 0
client/scss/components/config-manager.scss

@@ -0,0 +1,61 @@
+.config-manager {
+  .welcome {
+    text-align: center;
+    padding: 50px 0 15px 0;
+    color: mc('grey', '700');
+
+    h2 {
+      margin: 0;
+    }
+
+  }
+
+  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')
+  }
+  i.icon-warning-outline {
+    color: mc('orange', '500')
+  }
+
+  .tst-welcome-leave-active, .tst-welcome-enter-active {
+    transition: all .5s;
+    overflow-y: hidden;
+  }
+  .tst-welcome-leave, .tst-welcome-enter-to {
+    opacity: 1;
+    max-height: 200px;
+  }
+  .tst-welcome-leave-to, .tst-welcome-enter {
+    opacity: 0;
+    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;
+    }
+
+  }
+}

+ 11 - 0
server/app/data.yml

@@ -24,6 +24,17 @@ defaults:
     ha:
       nodeuid: primary
       readonly: false
+    site:
+      path: ''
+    title: Wiki.js
+configNamespaces:
+  - auth
+  - features
+  - git
+  - logging
+  - site
+  - theme
+  - uploads
 queues:
   - gitSync
   - uplClearTemp

+ 33 - 50
server/configure.js

@@ -1,12 +1,8 @@
-'use strict'
+const path = require('path')
 
-module.exports = (port, spinner) => {
-  const path = require('path')
-
-  const ROOTPATH = process.cwd()
-  const SERVERPATH = path.join(ROOTPATH, 'server')
-  const IS_DEBUG = process.env.NODE_ENV === 'development'
+/* global wiki */
 
+module.exports = () => {
   // ----------------------------------------
   // Load modules
   // ----------------------------------------
@@ -26,28 +22,30 @@ module.exports = (port, spinner) => {
   // Define Express App
   // ----------------------------------------
 
-  var app = express()
+  let app = express()
   app.use(compression())
 
-  var server
+  let server
 
   // ----------------------------------------
   // Public Assets
   // ----------------------------------------
 
-  app.use(favicon(path.join(ROOTPATH, 'assets', 'favicon.ico')))
-  app.use(express.static(path.join(ROOTPATH, 'assets')))
+  app.use(favicon(path.join(wiki.ROOTPATH, 'assets', 'favicon.ico')))
+  app.use(express.static(path.join(wiki.ROOTPATH, 'assets')))
 
   // ----------------------------------------
   // View Engine Setup
   // ----------------------------------------
 
-  app.set('views', path.join(SERVERPATH, 'views'))
+  app.set('views', path.join(wiki.SERVERPATH, 'views'))
   app.set('view engine', 'pug')
 
   app.use(bodyParser.json())
   app.use(bodyParser.urlencoded({ extended: false }))
 
+  app.locals.config = wiki.config
+  app.locals.data = wiki.data
   app.locals._ = require('lodash')
 
   // ----------------------------------------
@@ -55,22 +53,7 @@ module.exports = (port, spinner) => {
   // ----------------------------------------
 
   app.get('*', (req, res) => {
-    let langs = []
-    let conf = {}
-    try {
-      langs = yaml.safeLoad(fs.readFileSync(path.join(SERVERPATH, 'app/data.yml'), 'utf8')).langs
-      conf = yaml.safeLoad(fs.readFileSync(path.join(ROOTPATH, 'config.yml'), 'utf8'))
-    } catch (err) {
-      console.error(err)
-    }
-    res.render('configure/index', {
-      langs,
-      conf,
-      runmode: {
-        staticPort: (process.env.WIKI_JS_HEROKU || process.env.WIKI_JS_DOCKER),
-        staticMongo: (!_.isNil(process.env.WIKI_JS_HEROKU))
-      }
-    })
+    res.render('configure/index')
   })
 
   /**
@@ -81,14 +64,14 @@ module.exports = (port, spinner) => {
       () => {
         const semver = require('semver')
         if (!semver.satisfies(semver.clean(process.version), '>=6.9.0')) {
-          throw new Error('Node.js version is too old. Minimum is v6.11.1.')
+          throw new Error('Node.js version is too old. Minimum is 6.11.1.')
         }
-        return 'Node.js ' + process.version + ' detected.'
+        return 'Node.js ' + process.version + ' detected. Minimum is 6.11.1.'
       },
       () => {
         return Promise.try(() => {
           require('crypto')
-        }).catch(err => { // eslint-disable-line handle-callback-err
+        }).catch(err => {
           throw new Error('Crypto Node.js module is not available.')
         }).return('Node.js Crypto module is available.')
       },
@@ -102,9 +85,9 @@ module.exports = (port, spinner) => {
             }
             let gitver = _.head(stdout.match(/[\d]+\.[\d]+(\.[\d]+)?/gi))
             if (!gitver || !semver.satisfies(semver.clean(gitver), '>=2.7.4')) {
-              reject(new Error('Git version is too old. Minimum is v2.7.4.'))
+              reject(new Error('Git version is too old. Minimum is 2.7.4.'))
             }
-            resolve('Git v' + gitver + ' detected. Minimum is v2.7.4.')
+            resolve('Git ' + gitver + ' detected. Minimum is 2.7.4.')
           })
         })
       },
@@ -118,8 +101,8 @@ module.exports = (port, spinner) => {
       () => {
         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
+          fs.accessSync(path.join(wiki.ROOTPATH, 'config.yml'), (fs.constants || fs).W_OK)
+        }).catch(err => {
           throw new Error('config.yml file is not writable by Node.js process or was not created properly.')
         }).return('config.yml is writable by the setup process.')
       }
@@ -174,8 +157,8 @@ module.exports = (port, spinner) => {
     const exec = require('execa')
     const url = require('url')
 
-    const dataDir = path.resolve(ROOTPATH, cfgHelper.parseConfigValue(req.body.pathData))
-    const gitDir = path.resolve(ROOTPATH, cfgHelper.parseConfigValue(req.body.pathRepo))
+    const dataDir = path.resolve(wiki.ROOTPATH, cfgHelper.parseConfigValue(req.body.pathData))
+    const gitDir = path.resolve(wiki.ROOTPATH, cfgHelper.parseConfigValue(req.body.pathRepo))
 
     let gitRemoteUrl = ''
 
@@ -315,7 +298,7 @@ module.exports = (port, spinner) => {
           }
         })
       }),
-      fs.readFileAsync(path.join(ROOTPATH, 'config.yml'), 'utf8').then(confRaw => {
+      fs.readFileAsync(path.join(wiki.ROOTPATH, 'config.yml'), 'utf8').then(confRaw => {
         let conf = yaml.safeLoad(confRaw)
         conf.title = req.body.title
         conf.host = req.body.host
@@ -356,12 +339,12 @@ module.exports = (port, spinner) => {
         return crypto.randomBytesAsync(32).then(buf => {
           conf.sessionSecret = buf.toString('hex')
           confRaw = yaml.safeDump(conf)
-          return fs.writeFileAsync(path.join(ROOTPATH, 'config.yml'), confRaw)
+          return fs.writeFileAsync(path.join(wiki.ROOTPATH, 'config.yml'), confRaw)
         })
       })
     ).then(() => {
       if (process.env.IS_HEROKU) {
-        return fs.outputJsonAsync(path.join(SERVERPATH, 'app/heroku.json'), { configured: true })
+        return fs.outputJsonAsync(path.join(wiki.SERVERPATH, 'app/heroku.json'), { configured: true })
       } else {
         return true
       }
@@ -377,7 +360,7 @@ module.exports = (port, spinner) => {
    */
   app.post('/restart', (req, res) => {
     res.status(204).end()
-    server.destroy(() => {
+    /* server.destroy(() => {
       spinner.text = 'Setup wizard terminated. Restarting in normal mode...'
       _.delay(() => {
         const exec = require('execa')
@@ -386,7 +369,7 @@ module.exports = (port, spinner) => {
           process.exit(0)
         })
       }, 1000)
-    })
+    }) */
   })
 
   // ----------------------------------------
@@ -403,9 +386,9 @@ module.exports = (port, spinner) => {
     res.status(err.status || 500)
     res.send({
       message: err.message,
-      error: IS_DEBUG ? err : {}
+      error: wiki.IS_DEBUG ? err : {}
     })
-    spinner.fail(err.message)
+    wiki.logger.error(err.message)
     process.exit(1)
   })
 
@@ -413,11 +396,11 @@ module.exports = (port, spinner) => {
   // Start HTTP server
   // ----------------------------------------
 
-  spinner.text = 'Starting HTTP server...'
+  wiki.logger.info(`HTTP Server on port: ${wiki.config.port}`)
 
-  app.set('port', port)
+  app.set('port', wiki.config.port)
   server = http.createServer(app)
-  server.listen(port)
+  server.listen(wiki.config.port)
 
   var openConnections = []
 
@@ -443,10 +426,10 @@ module.exports = (port, spinner) => {
 
     switch (error.code) {
       case 'EACCES':
-        spinner.fail('Listening on port ' + port + ' requires elevated privileges!')
+        wiki.logger.error('Listening on port ' + wiki.config.port + ' requires elevated privileges!')
         return process.exit(1)
       case 'EADDRINUSE':
-        spinner.fail('Port ' + port + ' is already in use!')
+        wiki.logger.error('Port ' + wiki.config.port + ' is already in use!')
         return process.exit(1)
       default:
         throw error
@@ -454,6 +437,6 @@ module.exports = (port, spinner) => {
   })
 
   server.on('listening', () => {
-    spinner.text = 'Browse to http://localhost:' + port + ' to configure Wiki.js!'
+    wiki.logger.info('HTTP Server: RUNNING')
   })
 }

+ 0 - 2
server/models/_relations.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * Associate DB Model relations
  */

+ 0 - 2
server/models/comment.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * Comment schema
  */

+ 0 - 2
server/models/document.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * Document schema
  */

+ 0 - 2
server/models/file.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * File schema
  */

+ 0 - 2
server/models/folder.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * Folder schema
  */

+ 0 - 2
server/models/group.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * Group schema
  */

+ 0 - 2
server/models/right.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * Right schema
  */

+ 0 - 2
server/models/setting.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * Settings schema
  */

+ 0 - 2
server/models/tag.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /**
  * Tags schema
  */

+ 0 - 2
server/models/user.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /* global wiki */
 
 const Promise = require('bluebird')

+ 0 - 2
server/modules/auth.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /* global wiki */
 
 const _ = require('lodash')

+ 1 - 5
server/modules/config.js

@@ -1,5 +1,3 @@
-'use strict'
-
 /* global wiki */
 
 const fs = require('fs')
@@ -9,8 +7,6 @@ const path = require('path')
 const cfgHelper = require('../helpers/config')
 
 module.exports = {
-  SUBSETS: ['auth', 'features', 'git', 'logging', 'site', 'theme', 'uploads'],
-
   /**
    * Load root config from disk
    */
@@ -64,7 +60,7 @@ module.exports = {
    */
   loadFromDb(subsets) {
     if (!_.isArray(subsets) || subsets.length === 0) {
-      subsets = this.SUBSETS
+      subsets = wiki.data.configNamespaces
     }
 
     return wiki.db.Setting.findAll({

+ 1 - 1
server/modules/db.js

@@ -110,7 +110,7 @@ module.exports = {
       // -> Sync DB Schemas
       syncSchemas() {
         return self.inst.sync({
-          force: true,
+          force: false,
           logging: log => { wiki.logger.log('verbose', log) }
         })
       },

+ 38 - 68
server/views/configure/index.pug

@@ -1,31 +1,9 @@
-doctype html
-html(data-logic='configure')
-  head
-    meta(http-equiv='X-UA-Compatible', content='IE=edge')
-    meta(charset='UTF-8')
-    title Wiki.js | Configure
-
-    // Favicon
-    each favsize in [32, 96, 16]
-      link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
-
-    // JS / CSS
-    script(type='text/javascript').
-      var appconfig = !{JSON.stringify(conf)};
-      var runmode = !{JSON.stringify(runmode)};
-    script(type='text/javascript', src='/js/vendor.js')
-    script(type='text/javascript', src='/js/configure.js')
+extends ../master.pug
 
+block body
   body
-    #root
-      #header-container
-        nav.nav#header
-          .nav-left
-            a.nav-item
-              h1
-                i.icon-layers
-                | Wiki.js
-      main
+    #app.config-manager
+      config-manager(inline-template)
         .container
           transition(name='tst-welcome')
             .welcome(v-if='state === "welcome" || state === "restart"')
@@ -47,7 +25,7 @@ html(data-logic='configure')
                   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-light-blue(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Start
+                  button.button.is-small.is-light-blue(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Start
 
             //- ==============================================
             //- SYSTEM CHECK
@@ -69,9 +47,9 @@ html(data-logic='configure')
                   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-light-blue.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-light-blue(v-on:click='proceedToGeneral', v-if='loading || syscheck.ok', v-bind:disabled='loading') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToWelcome', v-bind:disabled='loading') Back
+                  button.button.is-small.is-teal(v-on:click='proceedToSyscheck', v-if='!loading && !syscheck.ok') Check Again
+                  button.button.is-small.is-light-blue(v-on:click='proceedToGeneral', v-if='loading || syscheck.ok', v-bind:disabled='loading') Continue
 
             //- ==============================================
             //- GENERAL
@@ -93,17 +71,16 @@ html(data-logic='configure')
                       label.label Host
                       input(type='text', placeholder='http://', v-model='conf.host', data-vv-scope='general', name='ipt-host', v-validate='{ required: true, min: 4 }')
                       span.desc The full URL to your wiki, without the trailing slash. E.g.: http://wiki.domain.com. Note that sub-folders are #[u not supported].
-                  if !runmode.staticPort
-                    section
-                      p.control
-                        label.label Port
-                        input(type='text', placeholder='e.g. 80', v-model.number='conf.port', data-vv-scope='general', name='ipt-port', v-validate='{ required: true }')
-                        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.<br>Set <strong>$(PORT)</strong> to use PORT environment variable.
+                  section
+                    p.control
+                      label.label Port
+                      input(type='text', placeholder='e.g. 80', v-model.number='conf.port', data-vv-scope='general', name='ipt-port', v-validate='{ required: true }')
+                      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.<br>Set <strong>$(PORT)</strong> to use PORT environment variable.
                   section
                     p.control
                       label.label Site UI Language
-                      select(v-model='conf.lang')
-                        each lg in langs
+                      select(v-model='conf.site.lang')
+                        each lg in data.langs
                           option(value=lg.id)= lg.name
                       span.desc The language in which navigation, help and other UI elements will be displayed.
                   section
@@ -113,8 +90,8 @@ html(data-logic='configure')
                       span.desc Should the site be accessible (read only) without login.
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToConsiderations', v-bind:disabled='loading || errors.any("general")') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToSyscheck', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToConsiderations', v-bind:disabled='loading || errors.any("general")') Continue
 
             //- ==============================================
             //- CONSIDERATIONS
@@ -144,8 +121,8 @@ html(data-logic='configure')
                     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-light-blue.is-outlined(v-on:click='proceedToGeneral', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToDb', v-bind:disabled='loading') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToGeneral', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToDb', v-bind:disabled='loading') Continue
 
             //- ==============================================
             //- DATABASE
@@ -166,8 +143,8 @@ html(data-logic='configure')
                       span.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server.<br />You can also specify an environment variable as the connection string, e.g. $(MONGO_URI).
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToDbcheck', v-bind:disabled='loading || errors.any("db")') Connect
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToDbcheck', v-bind:disabled='loading || errors.any("db")') Connect
 
             //- ==============================================
             //- DATABASE CHECK
@@ -186,9 +163,9 @@ html(data-logic='configure')
                   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-light-blue.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-light-blue(v-on:click='proceedToPaths', v-if='loading || dbcheck.ok', v-bind:disabled='loading') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
+                  button.button.is-small.is-teal(v-on:click='proceedToDbcheck', v-if='!loading && !dbcheck.ok') Try Again
+                  button.button.is-small.is-light-blue(v-on:click='proceedToPaths', v-if='loading || dbcheck.ok', v-bind:disabled='loading') Continue
 
             //- ==============================================
             //- PATHS
@@ -214,8 +191,8 @@ html(data-logic='configure')
                       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-light-blue.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToGit', v-bind:disabled='loading || errors.any("paths")') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToGit', v-bind:disabled='loading || errors.any("paths")') Continue
 
             //- ==============================================
             //- GIT
@@ -279,9 +256,9 @@ html(data-logic='configure')
                         span.desc The default/fallback email to use when creating commits to the git repository.
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToPaths', v-bind:disabled='loading') Back
-                  button.button.is-light-blue.is-outlined(v-on:click='conf.gitUseRemote = false; proceedToGitCheck()', v-bind:disabled='loading') Skip this step
-                  button.button.is-light-blue(v-on:click='conf.gitUseRemote = true; proceedToGitCheck()', v-bind:disabled='loading || errors.any("git")') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToPaths', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='conf.gitUseRemote = false; proceedToGitCheck()', v-bind:disabled='loading') Skip this step
+                  button.button.is-small.is-light-blue(v-on:click='conf.gitUseRemote = true; proceedToGitCheck()', v-bind:disabled='loading || errors.any("git")') Continue
             
             //- ==============================================
             //- GIT CHECK
@@ -303,9 +280,9 @@ html(data-logic='configure')
                   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-light-blue.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-light-blue(v-on:click='proceedToAdmin', v-if='loading || gitcheck.ok', v-bind:disabled='loading') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
+                  button.button.is-small.is-teal(v-on:click='proceedToGitCheck', v-if='!loading && !gitcheck.ok') Try Again
+                  button.button.is-small.is-light-blue(v-on:click='proceedToAdmin', v-if='loading || gitcheck.ok', v-bind:disabled='loading') Continue
 
             //- ==============================================
             //- ADMINISTRATOR ACCOUNT
@@ -337,8 +314,8 @@ html(data-logic='configure')
                         span.desc Verify your password again.
                 .panel-footer
                   .progress-bar: div(v-bind:style='{width: currentProgress}')
-                  button.button.is-light-blue.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
-                  button.button.is-light-blue(v-on:click='proceedToFinal', v-bind:disabled='loading || errors.any("admin")') Continue
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToGit', v-bind:disabled='loading') Back
+                  button.button.is-small.is-light-blue(v-on:click='proceedToFinal', v-bind:disabled='loading || errors.any("admin")') Continue
 
             //- ==============================================
             //- FINAL
@@ -359,9 +336,9 @@ html(data-logic='configure')
                   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-light-blue.is-outlined(v-on:click='proceedToAdmin', 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
+                  button.button.is-small.is-light-blue.is-outlined(v-on:click='proceedToAdmin', v-bind:disabled='loading') Back
+                  button.button.is-small.is-teal(v-on:click='proceedToFinal', v-if='!loading && !final.ok') Try Again
+                  button.button.is-small.is-green(v-on:click='finish', v-if='loading || final.ok', v-bind:disabled='loading') Start
 
             //- ==============================================
             //- RESTART
@@ -376,11 +353,4 @@ html(data-logic='configure')
                   p #[i.icon-loader.animated.rotateIn.infinite] Restarting Wiki.js in normal mode...
                   p You'll automatically be redirected to the homepage when ready. This usually takes about 30 seconds.
                 .panel-footer
-                  button.button.is-green(disabled='disabled') Start
-
-      footer.footer
-        span
-          | Powered by 
-          a(href='https://github.com/Requarks/wiki') Wiki.js
-          | .
-    block outside
+                  button.button.is-small.is-green(disabled='disabled') Start

+ 1 - 1
server/views/master.pug

@@ -7,7 +7,7 @@ html
     meta(name='theme-color', content='#009688')
     meta(name='msapplication-TileColor', content='#009688')
     meta(name='msapplication-TileImage', content=config.site.path + '/favicons/ms-icon-144x144.png')
-    title= config.title
+    title= config.site.title
 
     //- Favicon
     each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]