You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

491 lines
19 KiB

  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. v-icon.mr-2 system_update
  50. span You are about to install Wiki.js #[strong {{wikiVersion}}].
  51. v-divider.mt-3
  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. .pt-3.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. .pt-3.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. outline
  111. background-color='grey lighten-2'
  112. v-model='conf.title',
  113. label='Site Title',
  114. :counter='255',
  115. persistent-hint,
  116. hint='The site title will appear in the top left corner on every page and within the window title bar.',
  117. v-validate='{ required: true, min: 2 }',
  118. data-vv-name='siteTitle',
  119. data-vv-as='Site Title',
  120. data-vv-scope='general',
  121. :error-messages='errors.collect(`siteTitle`)'
  122. )
  123. v-flex.pr-3(xs12, sm6)
  124. v-text-field(
  125. outline
  126. background-color='grey lighten-2'
  127. v-model='conf.port',
  128. label='Server Port',
  129. persistent-hint,
  130. 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.',
  131. v-validate='{ required: true }',
  132. data-vv-name='port',
  133. data-vv-as='Port',
  134. data-vv-scope='general',
  135. :error-messages='errors.collect(`port`)'
  136. )
  137. v-layout(row, wrap).mt-3
  138. v-flex(xs12, sm6).pr-3
  139. v-text-field(
  140. outline
  141. background-color='grey lighten-2'
  142. v-model='conf.pathContent',
  143. label='Content Data Path',
  144. persistent-hint,
  145. hint='The path where content is stored (markdown files, uploads, etc.)',
  146. v-validate='{ required: true, min: 2 }',
  147. data-vv-name='pathContent',
  148. data-vv-as='Content Data Path',
  149. data-vv-scope='general',
  150. :error-messages='errors.collect(`pathContent`)'
  151. )
  152. v-flex(xs12, sm6)
  153. v-text-field(
  154. outline
  155. background-color='grey lighten-2'
  156. v-model='conf.pathData',
  157. label='Temporary Data Path',
  158. persistent-hint,
  159. hint='The path where temporary data is stored (cache, thumbnails, temporary upload files, etc.)',
  160. v-validate='{ required: true, min: 2 }',
  161. data-vv-name='pathData',
  162. data-vv-as='Temporary Data Path',
  163. data-vv-scope='general',
  164. :error-messages='errors.collect(`pathData`)'
  165. )
  166. v-layout(row, wrap).mt-3
  167. v-flex(xs12)
  168. v-checkbox(
  169. color='primary',
  170. v-model='conf.public',
  171. label='Public Access',
  172. persistent-hint,
  173. hint='Should the site be accessible (read only) without login.'
  174. )
  175. v-divider
  176. .pt-3.text-xs-center
  177. v-btn(@click='proceedToSyscheck', :disabled='loading') Back
  178. v-btn(color='primary', @click='proceedToAdmin', :disabled='loading') Continue
  179. //- ==============================================
  180. //- ADMINISTRATOR ACCOUNT
  181. //- ==============================================
  182. v-stepper-content(step='4')
  183. v-card.text-xs-center(flat)
  184. svg.icons.is-64: use(xlink:href='#nc-man-black')
  185. .subheading Administrator Account
  186. .body-2 A root administrator account will be created for local authentication. From this account, you can create or authorize more users.
  187. v-form
  188. v-container
  189. v-layout(row, wrap)
  190. v-flex(xs12)
  191. v-text-field(
  192. outline
  193. background-color='grey lighten-2'
  194. v-model='conf.adminEmail',
  195. label='Administrator Email',
  196. hint='The email address of the administrator account',
  197. v-validate='{ required: true, email: true }',
  198. data-vv-name='adminEmail',
  199. data-vv-as='Administrator Email',
  200. data-vv-scope='admin',
  201. :error-messages='errors.collect(`adminEmail`)'
  202. )
  203. v-flex.pr-3(xs6)
  204. v-text-field(
  205. outline
  206. background-color='grey lighten-2'
  207. ref='adminPassword',
  208. counter='255'
  209. v-model='conf.adminPassword',
  210. label='Password',
  211. :append-icon="pwdMode ? 'visibility' : 'visibility_off'"
  212. :append-icon-cb="() => (pwdMode = !pwdMode)"
  213. :type="pwdMode ? 'password' : 'text'"
  214. hint='At least 8 characters long.',
  215. v-validate='{ required: true, min: 8 }',
  216. data-vv-name='adminPassword',
  217. data-vv-as='Password',
  218. data-vv-scope='admin',
  219. :error-messages='errors.collect(`adminPassword`)'
  220. )
  221. v-flex(xs6)
  222. v-text-field(
  223. outline
  224. background-color='grey lighten-2'
  225. ref='adminPasswordConfirm',
  226. counter='255'
  227. v-model='conf.adminPasswordConfirm',
  228. label='Confirm Password',
  229. :append-icon="pwdConfirmMode ? 'visibility' : 'visibility_off'"
  230. :append-icon-cb="() => (pwdConfirmMode = !pwdConfirmMode)"
  231. :type="pwdConfirmMode ? 'password' : 'text'"
  232. hint='Verify your password again.',
  233. v-validate='{ required: true, min: 8 }',
  234. data-vv-name='adminPasswordConfirm',
  235. data-vv-as='Confirm Password',
  236. data-vv-scope='admin',
  237. :error-messages='errors.collect(`adminPasswordConfirm`)'
  238. )
  239. .pt-3.text-xs-center
  240. v-btn(@click='proceedToGeneral', :disabled='loading') Back
  241. v-btn(color='primary', @click='proceedToUpgrade', :disabled='loading') Continue
  242. //- ==============================================
  243. //- UPGRADE FROM 1.x
  244. //- ==============================================
  245. v-stepper-content(step='5', v-if='conf.upgrade')
  246. v-card.text-xs-center(flat)
  247. svg.icons.is-64: use(xlink:href='#nc-spaceship')
  248. .subheading Upgrade from Wiki.js 1.x
  249. .body-2 Migrating from a Wiki.js 1.x installation is quick and simple.
  250. v-form
  251. v-container
  252. v-layout(row)
  253. v-flex(xs12)
  254. v-text-field(
  255. outline
  256. background-color='grey lighten-2'
  257. v-model='conf.upgMongo',
  258. placeholder='mongodb://',
  259. label='Connection String to Wiki.js 1.x MongoDB database',
  260. persistent-hint,
  261. hint='A MongoDB database connection string where a Wiki.js 1.x installation is located. No alterations will be made to this database.',
  262. v-validate='{ required: true, min: 2 }',
  263. data-vv-name='upgMongo',
  264. data-vv-as='MongoDB Connection String',
  265. data-vv-scope='upgrade',
  266. :error-messages='errors.collect(`upgMongo`)'
  267. )
  268. .pt-3.text-xs-center
  269. v-btn(@click='proceedToAdmin', :disabled='loading') Back
  270. v-btn(color='primary', @click='proceedToFinal', :disabled='loading') Continue
  271. //- ==============================================
  272. //- FINAL
  273. //- ==============================================
  274. v-stepper-content(:step='conf.upgrade ? 6 : 5')
  275. v-card.text-xs-center(flat)
  276. template(v-if='loading')
  277. .mt-3(style='width: 64px; display:inline-block;')
  278. atom-spinner(
  279. :animation-duration='800'
  280. :size='64'
  281. color='#1976d2'
  282. )
  283. .subheading.primary--text.mt-3 Finalizing your installation...
  284. template(v-else-if='final.ok')
  285. svg.icons.is-64: use(xlink:href='#nc-check-bold')
  286. .subheading.green--text Installation complete!
  287. template(v-else)
  288. svg.icons.is-64: use(xlink:href='#nc-square-remove')
  289. .subheading.red--text Something went wrong...
  290. v-container
  291. v-alert(type='success', outline, :value='!loading && final.ok') Wiki.js was configured successfully and is now ready for use.
  292. v-alert(type='error', outline, :value='!loading && !final.ok') {{ final.error }}
  293. v-divider
  294. .pt-3.text-xs-center
  295. v-btn(@click='!conf.upgrade ? proceedToAdmin() : proceedToUpgrade()', :disabled='loading') Back
  296. v-btn(color='primary', @click='proceedToFinal', v-if='!loading && !final.ok') Try Again
  297. v-btn(color='success', @click='finish', v-if='loading || final.ok', :disabled='loading') Continue
  298. v-footer.pa-3(app, absolute, color='grey darken-3', height='auto')
  299. .caption.grey--text Wiki.js
  300. v-spacer
  301. .caption.grey--text(v-if='conf.telemetry') Telemetry Client ID: {{telemetryId}}
  302. </template>
  303. <script>
  304. /* global siteConfig */
  305. import axios from 'axios'
  306. import _ from 'lodash'
  307. import { AtomSpinner } from 'epic-spinners'
  308. export default {
  309. components: {
  310. AtomSpinner
  311. },
  312. props: {
  313. telemetryId: {
  314. type: String,
  315. required: true
  316. },
  317. wikiVersion: {
  318. type: String,
  319. required: true
  320. }
  321. },
  322. data() {
  323. return {
  324. loading: false,
  325. state: 1,
  326. syscheck: {
  327. ok: false,
  328. error: '',
  329. results: []
  330. },
  331. final: {
  332. ok: false,
  333. error: '',
  334. redirectUrl: ''
  335. },
  336. conf: {
  337. adminEmail: '',
  338. adminPassword: '',
  339. adminPasswordConfirm: '',
  340. lang: siteConfig.lang || 'en',
  341. pathData: './data',
  342. pathContent: './content',
  343. port: siteConfig.port || 80,
  344. public: (siteConfig.public === true),
  345. telemetry: true,
  346. title: siteConfig.title || 'Wiki',
  347. upgrade: false,
  348. upgMongo: 'mongodb://'
  349. },
  350. pwdMode: true,
  351. pwdConfirmMode: true
  352. }
  353. },
  354. methods: {
  355. proceedToWelcome () {
  356. this.state = 1
  357. this.loading = false
  358. },
  359. proceedToSyscheck () {
  360. let self = this
  361. this.state = 2
  362. this.loading = true
  363. this.syscheck = {
  364. ok: false,
  365. error: '',
  366. results: []
  367. }
  368. _.delay(() => {
  369. axios.post('/syscheck', self.conf).then(resp => {
  370. if (resp.data.ok === true) {
  371. self.syscheck.ok = true
  372. self.syscheck.results = resp.data.results
  373. } else {
  374. self.syscheck.ok = false
  375. self.syscheck.error = resp.data.error
  376. }
  377. self.loading = false
  378. self.$nextTick()
  379. }).catch(err => {
  380. window.alert(err.message)
  381. })
  382. }, 1000)
  383. },
  384. proceedToGeneral () {
  385. this.state = 3
  386. this.loading = false
  387. },
  388. async proceedToAdmin () {
  389. if (this.state < 4) {
  390. const validationSuccess = await this.$validator.validateAll('general')
  391. if (!validationSuccess) {
  392. this.state = 3
  393. return
  394. }
  395. }
  396. this.state = 4
  397. this.loading = false
  398. },
  399. async proceedToUpgrade () {
  400. if (this.state < 5) {
  401. const validationSuccess = await this.$validator.validateAll('admin')
  402. if (!validationSuccess || this.conf.adminPassword !== this.conf.adminPasswordConfirm) {
  403. this.state = 4
  404. return
  405. }
  406. }
  407. if (this.conf.upgrade) {
  408. this.state = 5
  409. this.loading = false
  410. } else {
  411. this.proceedToFinal()
  412. }
  413. },
  414. async proceedToFinal () {
  415. if (this.conf.upgrade && this.state < 6) {
  416. const validationSuccess = await this.$validator.validateAll('upgrade')
  417. if (!validationSuccess) {
  418. this.state = 5
  419. return
  420. }
  421. }
  422. this.state = this.conf.upgrade ? 6 : 5
  423. this.loading = true
  424. this.final = {
  425. ok: false,
  426. error: '',
  427. redirectUrl: ''
  428. }
  429. this.$forceUpdate()
  430. let self = this
  431. _.delay(() => {
  432. axios.post('/finalize', self.conf).then(resp => {
  433. if (resp.data.ok === true) {
  434. _.delay(() => {
  435. self.final.ok = true
  436. switch (resp.data.redirectPort) {
  437. case 80:
  438. self.final.redirectUrl = `http://${window.location.hostname}${resp.data.redirectPath}/login`
  439. break
  440. case 443:
  441. self.final.redirectUrl = `https://${window.location.hostname}${resp.data.redirectPath}/login`
  442. break
  443. default:
  444. self.final.redirectUrl = `http://${window.location.hostname}:${resp.data.redirectPort}${resp.data.redirectPath}/login`
  445. break
  446. }
  447. self.loading = false
  448. }, 5000)
  449. } else {
  450. self.final.ok = false
  451. self.final.error = resp.data.error
  452. self.loading = false
  453. }
  454. self.$nextTick()
  455. }).catch(err => {
  456. window.alert(err.message)
  457. })
  458. }, 1000)
  459. },
  460. finish () {
  461. window.location.assign(this.final.redirectUrl)
  462. }
  463. }
  464. }
  465. </script>
  466. <style lang='scss'>
  467. </style>