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.

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