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.

259 lines
7.8 KiB

  1. <template lang="pug">
  2. v-app.setup
  3. v-content
  4. v-container
  5. v-layout
  6. v-flex(xs12, lg6, offset-lg3)
  7. v-card.elevation-20.radius-7.animated.fadeInUp
  8. .text-center
  9. img.setup-logo.animated.fadeInUp.wait-p2s(src='/svg/logo-wikijs-full.svg', alt='Wiki.js Logo')
  10. v-alert(v-model='error', type='error', icon='mdi-alert', tile, dismissible) {{ errorMessage }}
  11. v-alert(v-if='!error', tile, color='blue lighten-5', :value='true')
  12. v-icon.mr-3(color='blue') mdi-package-variant
  13. span.blue--text You are about to install Wiki.js #[strong {{wikiVersion}}].
  14. v-card-text
  15. .overline.pl-3 Administrator Account
  16. v-container.pa-3.mt-3(grid-list-xl)
  17. v-layout(row, wrap)
  18. v-flex(xs12)
  19. v-text-field(
  20. outlined
  21. v-model='conf.adminEmail',
  22. label='Administrator Email',
  23. hint='The email address of the administrator account.',
  24. persistent-hint
  25. required
  26. ref='adminEmailInput'
  27. )
  28. v-flex(xs6)
  29. v-text-field(
  30. outlined
  31. ref='adminPassword',
  32. counter='255'
  33. v-model='conf.adminPassword',
  34. label='Password',
  35. :append-icon="pwdMode ? 'mdi-eye-off' : 'mdi-eye'"
  36. @click:append="() => (pwdMode = !pwdMode)"
  37. :type="pwdMode ? 'password' : 'text'"
  38. hint='At least 8 characters long.',
  39. persistent-hint
  40. )
  41. v-flex(xs6)
  42. v-text-field(
  43. outlined
  44. ref='adminPasswordConfirm',
  45. counter='255'
  46. v-model='conf.adminPasswordConfirm',
  47. label='Confirm Password',
  48. :append-icon="pwdConfirmMode ? 'mdi-eye-off' : 'mdi-eye'"
  49. @click:append="() => (pwdConfirmMode = !pwdConfirmMode)"
  50. :type="pwdConfirmMode ? 'password' : 'text'"
  51. hint='Verify your password again.',
  52. persistent-hint
  53. )
  54. v-divider.mb-4
  55. .overline.pl-3.mb-5 Site URL
  56. v-text-field.mb-4.mx-3(
  57. outlined
  58. ref='adminSiteUrl',
  59. v-model='conf.siteUrl',
  60. label='Site URL',
  61. hint='Full URL to your wiki, without the trailing slash (e.g. https://wiki.example.com). This should be the public facing URL, not the internal one if using a reverse-proxy.',
  62. persistent-hint
  63. @keyup.enter='install'
  64. )
  65. v-divider.mb-4
  66. .overline.pl-3.mb-3 Telemetry
  67. v-switch.ml-3(
  68. inset
  69. color='primary',
  70. v-model='conf.telemetry',
  71. label='Allow Telemetry',
  72. persistent-hint,
  73. hint='Help Wiki.js developers improve this app with anonymized telemetry.'
  74. )
  75. a.pl-3(style='font-size: 12px; letter-spacing: initial;', href='https://docs.requarks.io/telemetry', target='_blank') Learn more
  76. v-divider.mt-2
  77. v-card-actions
  78. v-btn(color='primary', @click='install', :disabled='loading', x-large, depressed, block)
  79. v-icon(left) mdi-check
  80. span Install
  81. v-dialog(v-model='loading', width='450', persistent)
  82. v-card(color='primary', dark).radius-7
  83. v-card-text.text-center.py-5
  84. .py-3(style='width: 64px; display:inline-block;')
  85. breeding-rhombus-spinner(
  86. :animation-duration='2000'
  87. :size='64'
  88. color='#FFF'
  89. )
  90. template(v-if='!success')
  91. .subtitle-1.white--text Finalizing your installation...
  92. .caption Just a moment
  93. template(v-else)
  94. .subtitle-1.white--text Installation complete!
  95. .caption Redirecting...
  96. </template>
  97. <script>
  98. import _ from 'lodash'
  99. import validate from 'validate.js'
  100. import { BreedingRhombusSpinner } from 'epic-spinners'
  101. export default {
  102. components: {
  103. BreedingRhombusSpinner
  104. },
  105. props: {
  106. wikiVersion: {
  107. type: String,
  108. required: true
  109. }
  110. },
  111. data() {
  112. return {
  113. loading: false,
  114. success: false,
  115. error: false,
  116. errorMessage: '',
  117. conf: {
  118. adminEmail: '',
  119. adminPassword: '',
  120. adminPasswordConfirm: '',
  121. siteUrl: 'https://wiki.yourdomain.com',
  122. telemetry: true
  123. },
  124. pwdMode: true,
  125. pwdConfirmMode: true
  126. }
  127. },
  128. mounted() {
  129. _.delay(() => {
  130. this.$refs.adminEmailInput.focus()
  131. }, 500)
  132. },
  133. methods: {
  134. async install () {
  135. this.error = false
  136. const validationResults = validate(this.conf, {
  137. adminEmail: {
  138. presence: {
  139. allowEmpty: false
  140. },
  141. email: true
  142. },
  143. adminPassword: {
  144. presence: {
  145. allowEmpty: false
  146. },
  147. length: {
  148. minimum: 6,
  149. maximum: 255
  150. }
  151. },
  152. adminPasswordConfirm: {
  153. equality: 'adminPassword'
  154. },
  155. siteUrl: {
  156. presence: {
  157. allowEmpty: false
  158. },
  159. url: {
  160. schemes: ['http', 'https'],
  161. allowLocal: true,
  162. allowDataUrl: false
  163. },
  164. format: {
  165. pattern: '^(?!.*/$).*$',
  166. flags: 'i',
  167. message: 'must not have a trailing slash'
  168. }
  169. }
  170. }, {
  171. format: 'flat'
  172. })
  173. if (validationResults) {
  174. this.error = true
  175. this.errorMessage = validationResults[0]
  176. this.$forceUpdate()
  177. return
  178. }
  179. this.loading = true
  180. this.success = false
  181. this.$forceUpdate()
  182. _.delay(async () => {
  183. try {
  184. const resp = await fetch('/finalize', {
  185. method: 'POST',
  186. cache: 'no-cache',
  187. headers: {
  188. 'Content-Type': 'application/json'
  189. },
  190. body: JSON.stringify(this.conf)
  191. }).then(res => res.json())
  192. if (resp.ok === true) {
  193. _.delay(() => {
  194. this.success = true
  195. _.delay(() => {
  196. window.location.assign('/login')
  197. }, 3000)
  198. }, 10000)
  199. } else {
  200. this.error = true
  201. this.errorMessage = resp.error
  202. this.loading = false
  203. }
  204. } catch (err) {
  205. window.alert(err.message)
  206. }
  207. }, 1000)
  208. }
  209. }
  210. }
  211. </script>
  212. <style lang='scss'>
  213. .setup {
  214. .v-application--wrap {
  215. padding-top: 10vh;
  216. background-color: #111;
  217. background-image: linear-gradient(45deg, mc('blue', '100'), mc('blue', '700'), mc('indigo', '900'));
  218. background-blend-mode: exclusion;
  219. &::before {
  220. content: '';
  221. position: absolute;
  222. left: 0;
  223. top: 0;
  224. width: 100%;
  225. height: 100vh;
  226. z-index: 0;
  227. background-color: transparent;
  228. background-image: url(/svg/motif-grid.svg) !important;
  229. background-size: 100px;
  230. background-repeat: repeat;
  231. animation: bg-anim 100s linear infinite;
  232. }
  233. }
  234. @keyframes bg-anim {
  235. 0% {
  236. background-position: 0 0;
  237. }
  238. 100% {
  239. background-position: 100% 100%;
  240. }
  241. }
  242. &-logo {
  243. width: 400px;
  244. margin: 2rem 0 2rem 0;
  245. }
  246. }
  247. </style>