setup.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. <template lang="pug">
  2. v-app.setup
  3. v-toolbar(color='blue darken-2', dark, app, clipped-left, fixed, flat)
  4. v-spacer
  5. v-toolbar-title
  6. span.subheading Wiki.js Setup
  7. v-spacer
  8. v-content
  9. v-progress-linear.ma-0(indeterminate, height='4', :active='loading')
  10. v-stepper.elevation-0(v-model='state')
  11. v-stepper-header
  12. v-stepper-step(step='1' :complete='state > 1')
  13. | Welcome
  14. small Wiki.js Installation Wizard
  15. v-divider
  16. v-stepper-step(step='2' :complete='state > 2')
  17. | System Check
  18. small Checking your system for compatibility
  19. v-divider
  20. v-stepper-step(step='3' :complete='state > 3')
  21. | General Information
  22. small Site Title, Language and Access
  23. v-divider
  24. v-stepper-step(step='4' :complete='state > 4')
  25. | Administration Account
  26. small Create the admin account
  27. v-divider(v-if='this.conf.upgrade')
  28. v-stepper-step(step='5' :complete='state > 5', v-if='this.conf.upgrade')
  29. | Upgrade from Wiki.js 1.x
  30. small Migrate your existing installation
  31. v-divider
  32. v-stepper-step(:step='this.conf.upgrade ? 6 : 5' :complete='this.conf.upgrade ? state > 5 : state > 6')
  33. | Final Steps
  34. small Finalizing your installation
  35. v-stepper-items
  36. //- ==============================================
  37. //- WELCOME
  38. //- ==============================================
  39. v-stepper-content(step='1')
  40. v-card.text-xs-center.pa-3(flat)
  41. img(src='/svg/logo-wikijs.svg', alt='Wiki.js Logo', style='width: 300px;')
  42. v-container
  43. .body-2.py-2 This installation wizard will guide you through the steps needed to get your wiki up and running in no time!
  44. .body-1
  45. | Detailed information about installation and usage can be found on the #[a(href='https://wiki.requarks.io/docs') official documentation site].
  46. br
  47. | 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].
  48. .body-1.pt-3
  49. svg.icons.is-18.is-outlined.has-right-pad.is-text: use(xlink:href='#nc-cd-reader')
  50. span You are about to install Wiki.js #[strong {{wikiVersion}}].
  51. v-divider
  52. v-form
  53. v-checkbox(
  54. color='primary',
  55. v-model='conf.telemetry',
  56. label='Allow Telemetry',
  57. persistent-hint,
  58. hint='Help Wiki.js developers improve this app with anonymized telemetry.'
  59. )
  60. v-checkbox.mt-3(
  61. color='primary',
  62. v-model='conf.upgrade',
  63. label='Upgrade from Wiki.js 1.x',
  64. persistent-hint,
  65. hint='Check this box if you are upgrading from Wiki.js 1.x and wish to migrate your existing data.'
  66. )
  67. v-divider
  68. .text-xs-center
  69. v-btn(color='primary', @click='proceedToSyscheck', :disabled='loading') Start
  70. //- ==============================================
  71. //- SYSTEM CHECK
  72. //- ==============================================
  73. v-stepper-content(step='2')
  74. v-card.text-xs-center(flat)
  75. svg.icons.is-64: use(xlink:href='#nc-metrics')
  76. .subheading System Check
  77. v-container
  78. v-layout(row, align-center, v-if='loading')
  79. v-progress-circular(v-if='loading', indeterminate, color='blue')
  80. .body-2.blue--text.ml-3 Checking your system for compatibility...
  81. v-alert(type='success', outline, :value='!loading && syscheck.ok') Looks good! No issues so far.
  82. v-alert(type='error', outline, :value='!loading && !syscheck.ok') {{ syscheck.error }}
  83. v-list.mt-3(two-line, v-if='!loading && syscheck.ok', dense)
  84. template(v-for='(rs, n) in syscheck.results')
  85. v-divider(v-if='n > 0', inset)
  86. v-list-tile
  87. v-list-tile-avatar(color='green lighten-5')
  88. v-icon(color='green') check
  89. v-list-tile-content
  90. v-list-tile-title {{rs.title}}
  91. v-list-tile-sub-title {{rs.subtitle}}
  92. v-divider
  93. .text-xs-center
  94. v-btn(@click='proceedToWelcome', :disabled='loading') Back
  95. v-btn(color='primary', @click='proceedToSyscheck', v-if='!loading && !syscheck.ok') Check Again
  96. v-btn(color='red', dark, @click='proceedToGeneral', v-if='!loading && !syscheck.ok') Continue Anyway
  97. v-btn(color='primary', @click='proceedToGeneral', v-if='loading || syscheck.ok', :disabled='loading') Continue
  98. //- ==============================================
  99. //- GENERAL
  100. //- ==============================================
  101. v-stepper-content(step='3')
  102. v-card.text-xs-center(flat)
  103. svg.icons.is-64: use(xlink:href='#nc-webpage')
  104. .subheading General Information
  105. v-form
  106. v-container
  107. v-layout(row, wrap)
  108. v-flex(xs12, sm6).pr-3
  109. v-text-field(
  110. v-model='conf.title',
  111. label='Site Title',
  112. :counter='255',
  113. persistent-hint,
  114. hint='The site title will appear in the top left corner on every page and within the window title bar.',
  115. v-validate='{ required: true, min: 2 }',
  116. data-vv-name='siteTitle',
  117. data-vv-as='Site Title',
  118. data-vv-scope='general',
  119. :error-messages='errors.collect(`siteTitle`)'
  120. )
  121. v-flex.pr-3(xs12, sm6)
  122. v-text-field(
  123. v-model='conf.port',
  124. label='Server Port',
  125. persistent-hint,
  126. hint='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. Set $(PORT) to use the PORT environment variable.',
  127. v-validate='{ required: true }',
  128. data-vv-name='port',
  129. data-vv-as='Port',
  130. data-vv-scope='general',
  131. :error-messages='errors.collect(`port`)'
  132. )
  133. v-layout(row, wrap).mt-3
  134. v-flex(xs12, sm6).pr-3
  135. v-text-field(
  136. v-model='conf.pathContent',
  137. label='Content Data Path',
  138. persistent-hint,
  139. hint='The path where content is stored (markdown files, uploads, etc.)',
  140. v-validate='{ required: true, min: 2 }',
  141. data-vv-name='pathContent',
  142. data-vv-as='Content Data Path',
  143. data-vv-scope='general',
  144. :error-messages='errors.collect(`pathContent`)'
  145. )
  146. v-flex(xs12, sm6)
  147. v-text-field(
  148. v-model='conf.pathData',
  149. label='Temporary Data Path',
  150. persistent-hint,
  151. hint='The path where temporary data is stored (cache, thumbnails, temporary upload files, etc.)',
  152. v-validate='{ required: true, min: 2 }',
  153. data-vv-name='pathData',
  154. data-vv-as='Temporary Data Path',
  155. data-vv-scope='general',
  156. :error-messages='errors.collect(`pathData`)'
  157. )
  158. v-layout(row, wrap).mt-3
  159. v-flex(xs12)
  160. v-checkbox(
  161. color='primary',
  162. v-model='conf.public',
  163. label='Public Access',
  164. persistent-hint,
  165. hint='Should the site be accessible (read only) without login.'
  166. )
  167. v-checkbox.mt-2(
  168. color='primary',
  169. v-model='conf.selfRegister',
  170. label='Allow Self-Registration',
  171. persistent-hint,
  172. hint='Can users create their own account to gain access?'
  173. )
  174. v-divider
  175. .text-xs-center
  176. v-btn(@click='proceedToSyscheck', :disabled='loading') Back
  177. v-btn(color='primary', @click='proceedToAdmin', :disabled='loading') Continue
  178. //- ==============================================
  179. //- ADMINISTRATOR ACCOUNT
  180. //- ==============================================
  181. v-stepper-content(step='4')
  182. v-card.text-xs-center(flat)
  183. svg.icons.is-64: use(xlink:href='#nc-man-black')
  184. .subheading Administrator Account
  185. .body-2 A root administrator account will be created for local authentication. From this account, you can create or authorize more users.
  186. v-form
  187. v-container
  188. v-layout(row, wrap)
  189. v-flex(xs12)
  190. v-text-field(
  191. autofocus
  192. v-model='conf.adminEmail',
  193. label='Administrator Email',
  194. hint='The email address of the administrator account',
  195. v-validate='{ required: true, email: true }',
  196. data-vv-name='adminEmail',
  197. data-vv-as='Administrator Email',
  198. data-vv-scope='admin',
  199. :error-messages='errors.collect(`adminEmail`)'
  200. )
  201. v-flex.pr-3(xs6)
  202. v-text-field(
  203. ref='adminPassword',
  204. counter='255'
  205. v-model='conf.adminPassword',
  206. label='Password',
  207. :append-icon="pwdMode ? 'visibility' : 'visibility_off'"
  208. :append-icon-cb="() => (pwdMode = !pwdMode)"
  209. :type="pwdMode ? 'password' : 'text'"
  210. hint='At least 8 characters long.',
  211. v-validate='{ required: true, min: 8 }',
  212. data-vv-name='adminPassword',
  213. data-vv-as='Password',
  214. data-vv-scope='admin',
  215. :error-messages='errors.collect(`adminPassword`)'
  216. )
  217. v-flex(xs6)
  218. v-text-field(
  219. ref='adminPasswordConfirm',
  220. counter='255'
  221. v-model='conf.adminPasswordConfirm',
  222. label='Confirm Password',
  223. :append-icon="pwdConfirmMode ? 'visibility' : 'visibility_off'"
  224. :append-icon-cb="() => (pwdConfirmMode = !pwdConfirmMode)"
  225. :type="pwdConfirmMode ? 'password' : 'text'"
  226. hint='Verify your password again.',
  227. v-validate='{ required: true, min: 8 }',
  228. data-vv-name='adminPasswordConfirm',
  229. data-vv-as='Confirm Password',
  230. data-vv-scope='admin',
  231. :error-messages='errors.collect(`adminPasswordConfirm`)'
  232. )
  233. .text-xs-center
  234. v-btn(@click='proceedToGeneral', :disabled='loading') Back
  235. v-btn(color='primary', @click='proceedToUpgrade', :disabled='loading') Continue
  236. //- ==============================================
  237. //- UPGRADE FROM 1.x
  238. //- ==============================================
  239. v-stepper-content(step='5', v-if='conf.upgrade')
  240. v-card.text-xs-center(flat)
  241. svg.icons.is-64: use(xlink:href='#nc-spaceship')
  242. .subheading Upgrade from Wiki.js 1.x
  243. .body-2 Migrating from a Wiki.js 1.x installation is quick and simple.
  244. v-form
  245. v-container
  246. v-layout(row)
  247. v-flex(xs12)
  248. v-text-field(
  249. v-model='conf.upgMongo',
  250. placeholder='mongodb://',
  251. label='Connection String to Wiki.js 1.x MongoDB database',
  252. persistent-hint,
  253. hint='A MongoDB database connection string where a Wiki.js 1.x installation is located. No alterations will be made to this database.',
  254. v-validate='{ required: true, min: 2 }',
  255. data-vv-name='upgMongo',
  256. data-vv-as='MongoDB Connection String',
  257. data-vv-scope='upgrade',
  258. :error-messages='errors.collect(`upgMongo`)'
  259. )
  260. .text-xs-center
  261. v-btn(@click='proceedToAdmin', :disabled='loading') Back
  262. v-btn(color='primary', @click='proceedToFinal', :disabled='loading') Continue
  263. //- ==============================================
  264. //- FINAL
  265. //- ==============================================
  266. v-stepper-content(:step='conf.upgrade ? 6 : 5')
  267. v-card.text-xs-center(flat)
  268. template(v-if='loading')
  269. v-progress-circular(size='64', indeterminate, color='blue')
  270. .subheading Finalizing your installation...
  271. template(v-else-if='final.ok')
  272. svg.icons.is-64: use(xlink:href='#nc-check-bold')
  273. .subheading Installation complete!
  274. template(v-else)
  275. svg.icons.is-64: use(xlink:href='#nc-square-remove')
  276. .subheading Something went wrong...
  277. v-container
  278. v-alert(type='success', outline, :value='!loading && final.ok') Wiki.js was configured successfully and is now ready for use.
  279. v-alert(type='error', outline, :value='!loading && !final.ok') {{ final.error }}
  280. v-divider
  281. .text-xs-center
  282. v-btn(@click='!conf.upgrade ? proceedToAdmin() : proceedToUpgrade()', :disabled='loading') Back
  283. v-btn(color='primary', @click='proceedToFinal', v-if='!loading && !final.ok') Try Again
  284. v-btn(color='success', @click='finish', v-if='loading || final.ok', :disabled='loading') Continue
  285. v-footer.pa-3(app, absolute, color='grey darken-3', height='auto')
  286. .caption.grey--text Wiki.js
  287. v-spacer
  288. .caption.grey--text(v-if='conf.telemetry') Telemetry Client ID: {{telemetryId}}
  289. </template>
  290. <script>
  291. /* global siteConfig */
  292. import axios from 'axios'
  293. import _ from 'lodash'
  294. export default {
  295. props: {
  296. telemetryId: {
  297. type: String,
  298. required: true
  299. },
  300. wikiVersion: {
  301. type: String,
  302. required: true
  303. }
  304. },
  305. data() {
  306. return {
  307. loading: false,
  308. state: 1,
  309. syscheck: {
  310. ok: false,
  311. error: '',
  312. results: []
  313. },
  314. final: {
  315. ok: false,
  316. error: '',
  317. redirectUrl: ''
  318. },
  319. conf: {
  320. adminEmail: '',
  321. adminPassword: '',
  322. adminPasswordConfirm: '',
  323. lang: siteConfig.lang || 'en',
  324. pathData: './data',
  325. pathContent: './content',
  326. port: siteConfig.port || 80,
  327. public: (siteConfig.public === true),
  328. selfRegister: (siteConfig.selfRegister === true),
  329. telemetry: true,
  330. title: siteConfig.title || 'Wiki',
  331. upgrade: false,
  332. upgMongo: 'mongodb://'
  333. },
  334. pwdMode: true,
  335. pwdConfirmMode: true
  336. }
  337. },
  338. methods: {
  339. proceedToWelcome () {
  340. this.state = 1
  341. this.loading = false
  342. },
  343. proceedToSyscheck () {
  344. let self = this
  345. this.state = 2
  346. this.loading = true
  347. this.syscheck = {
  348. ok: false,
  349. error: '',
  350. results: []
  351. }
  352. _.delay(() => {
  353. axios.post('/syscheck', self.conf).then(resp => {
  354. if (resp.data.ok === true) {
  355. self.syscheck.ok = true
  356. self.syscheck.results = resp.data.results
  357. } else {
  358. self.syscheck.ok = false
  359. self.syscheck.error = resp.data.error
  360. }
  361. self.loading = false
  362. self.$nextTick()
  363. }).catch(err => {
  364. window.alert(err.message)
  365. })
  366. }, 1000)
  367. },
  368. proceedToGeneral () {
  369. this.state = 3
  370. this.loading = false
  371. },
  372. async proceedToAdmin () {
  373. if (this.state < 4) {
  374. const validationSuccess = await this.$validator.validateAll('general')
  375. if (!validationSuccess) {
  376. this.state = 3
  377. return
  378. }
  379. }
  380. this.state = 4
  381. this.loading = false
  382. },
  383. async proceedToUpgrade () {
  384. if (this.state < 5) {
  385. const validationSuccess = await this.$validator.validateAll('admin')
  386. if (!validationSuccess || this.conf.adminPassword !== this.conf.adminPasswordConfirm) {
  387. this.state = 4
  388. return
  389. }
  390. }
  391. if (this.conf.upgrade) {
  392. this.state = 5
  393. this.loading = false
  394. } else {
  395. this.proceedToFinal()
  396. }
  397. },
  398. async proceedToFinal () {
  399. if (this.conf.upgrade && this.state < 6) {
  400. const validationSuccess = await this.$validator.validateAll('upgrade')
  401. if (!validationSuccess) {
  402. this.state = 5
  403. return
  404. }
  405. }
  406. this.state = this.conf.upgrade ? 6 : 5
  407. this.loading = true
  408. this.final = {
  409. ok: false,
  410. error: '',
  411. redirectUrl: ''
  412. }
  413. this.$forceUpdate()
  414. let self = this
  415. _.delay(() => {
  416. axios.post('/finalize', self.conf).then(resp => {
  417. if (resp.data.ok === true) {
  418. _.delay(() => {
  419. self.final.ok = true
  420. switch (resp.data.redirectPort) {
  421. case 80:
  422. self.final.redirectUrl = `http://${window.location.hostname}${resp.data.redirectPath}/login`
  423. break
  424. case 443:
  425. self.final.redirectUrl = `https://${window.location.hostname}${resp.data.redirectPath}/login`
  426. break
  427. default:
  428. self.final.redirectUrl = `http://${window.location.hostname}:${resp.data.redirectPort}${resp.data.redirectPath}/login`
  429. break
  430. }
  431. self.loading = false
  432. }, 5000)
  433. } else {
  434. self.final.ok = false
  435. self.final.error = resp.data.error
  436. self.loading = false
  437. }
  438. self.$nextTick()
  439. }).catch(err => {
  440. window.alert(err.message)
  441. })
  442. }, 1000)
  443. },
  444. finish () {
  445. window.location.assign(this.final.redirectUrl)
  446. }
  447. }
  448. }
  449. </script>
  450. <style lang='scss'>
  451. </style>