setup.vue 8.56 KB
Newer Older
1
<template lang="pug">
2
  v-app.setup
Nick's avatar
Nick committed
3 4 5 6
    v-content
      v-container
        v-layout
          v-flex(xs12, lg6, offset-lg3)
7
            v-card.elevation-20.radius-7.animated.fadeInUp
8 9
              v-alert(v-if='isDevMode', tile, dark, color='red darken-3', icon='mdi-alert', prominent)
                .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 dev 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='/_assets/svg/logo-wikijs-full.svg', alt='Wiki.js Logo')
14
              v-alert(v-model='error', type='error', icon='mdi-alert', tile, dismissible) {{ errorMessage }}
15 16 17
              v-alert(v-if='!error', tile, color='blue lighten-5', :value='true')
                v-icon.mr-3(color='blue') mdi-package-variant
                span.blue--text You are about to install Wiki.js #[strong {{wikiVersion}}].
Nick's avatar
Nick committed
18
              v-card-text
19 20
                .overline.pl-3 Administrator Account
                v-container.pa-3.mt-3(grid-list-xl)
Nick's avatar
Nick committed
21 22 23
                  v-layout(row, wrap)
                    v-flex(xs12)
                      v-text-field(
24
                        outlined
Nick's avatar
Nick committed
25 26
                        v-model='conf.adminEmail',
                        label='Administrator Email',
27
                        hint='The email address of the administrator account.',
Nick's avatar
Nick committed
28
                        persistent-hint
29
                        required
Nick's avatar
Nick committed
30 31 32 33
                        ref='adminEmailInput'
                      )
                    v-flex(xs6)
                      v-text-field(
34
                        outlined
Nick's avatar
Nick committed
35 36 37 38
                        ref='adminPassword',
                        counter='255'
                        v-model='conf.adminPassword',
                        label='Password',
39
                        :append-icon="pwdMode ? 'mdi-eye-off' : 'mdi-eye'"
Nick's avatar
Nick committed
40 41 42 43 44 45 46
                        @click:append="() => (pwdMode = !pwdMode)"
                        :type="pwdMode ? 'password' : 'text'"
                        hint='At least 8 characters long.',
                        persistent-hint
                      )
                    v-flex(xs6)
                      v-text-field(
47
                        outlined
Nick's avatar
Nick committed
48 49 50 51
                        ref='adminPasswordConfirm',
                        counter='255'
                        v-model='conf.adminPasswordConfirm',
                        label='Confirm Password',
52
                        :append-icon="pwdConfirmMode ? 'mdi-eye-off' : 'mdi-eye'"
Nick's avatar
Nick committed
53 54 55 56 57 58
                        @click:append="() => (pwdConfirmMode = !pwdConfirmMode)"
                        :type="pwdConfirmMode ? 'password' : 'text'"
                        hint='Verify your password again.',
                        persistent-hint
                      )
                v-divider.mb-4
59 60 61 62 63 64 65 66 67 68 69 70 71 72
                .overline.pl-3.mb-5 Site URL
                v-text-field.mb-4.mx-3(
                  outlined
                  ref='adminSiteUrl',
                  v-model='conf.siteUrl',
                  label='Site URL',
                  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.',
                  persistent-hint
                  @keyup.enter='install'
                )
                v-divider.mb-4
                .overline.pl-3.mb-3 Telemetry
                v-switch.ml-3(
                  inset
73 74 75 76 77 78
                  color='primary',
                  v-model='conf.telemetry',
                  label='Allow Telemetry',
                  persistent-hint,
                  hint='Help Wiki.js developers improve this app with anonymized telemetry.'
                )
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
Nick's avatar
Nick committed
81
              v-card-actions
82
                v-btn(color='primary', @click='install', :disabled='loading', x-large, depressed, block)
83
                  v-icon(left) mdi-check
Nick's avatar
Nick committed
84 85 86 87
                  span Install

    v-dialog(v-model='loading', width='450', persistent)
      v-card(color='primary', dark).radius-7
88
        v-card-text.text-center.py-5
Nick's avatar
Nick committed
89 90 91 92 93 94 95
          .py-3(style='width: 64px; display:inline-block;')
            breeding-rhombus-spinner(
              :animation-duration='2000'
              :size='64'
              color='#FFF'
              )
          template(v-if='!success')
96
            .subtitle-1.white--text Finalizing your installation...
Nick's avatar
Nick committed
97 98
            .caption Just a moment
          template(v-else)
99
            .subtitle-1.white--text Installation complete!
Nick's avatar
Nick committed
100
            .caption Redirecting...
101 102 103
</template>

<script>
104
import _ from 'lodash'
105
import validate from 'validate.js'
106
import { BreedingRhombusSpinner } from 'epic-spinners'
107
import confetti from 'canvas-confetti'
108

109 110
/* global siteConfig */

111
export default {
112
  components: {
113
    BreedingRhombusSpinner
114
  },
115 116 117 118 119 120 121 122 123
  props: {
    wikiVersion: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      loading: false,
Nick's avatar
Nick committed
124 125 126
      success: false,
      error: false,
      errorMessage: '',
127 128 129 130
      conf: {
        adminEmail: '',
        adminPassword: '',
        adminPasswordConfirm: '',
131
        siteUrl: 'https://wiki.yourdomain.com',
Nick's avatar
Nick committed
132
        telemetry: true
133 134
      },
      pwdMode: true,
135 136
      pwdConfirmMode: true,
      isDevMode: false
137 138
    }
  },
Nick's avatar
Nick committed
139 140 141 142
  mounted() {
    _.delay(() => {
      this.$refs.adminEmailInput.focus()
    }, 500)
143
    this.isDevMode = siteConfig.devMode === true
Nick's avatar
Nick committed
144
  },
145
  methods: {
Nick's avatar
Nick committed
146
    async install () {
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
      this.error = false

      const validationResults = validate(this.conf, {
        adminEmail: {
          presence: {
            allowEmpty: false
          },
          email: true
        },
        adminPassword: {
          presence: {
            allowEmpty: false
          },
          length: {
            minimum: 6,
            maximum: 255
          }
        },
        adminPasswordConfirm: {
          equality: 'adminPassword'
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        },
        siteUrl: {
          presence: {
            allowEmpty: false
          },
          url: {
            schemes: ['http', 'https'],
            allowLocal: true,
            allowDataUrl: false
          },
          format: {
            pattern: '^(?!.*/$).*$',
            flags: 'i',
            message: 'must not have a trailing slash'
          }
182 183 184 185 186 187 188 189
        }
      }, {
        format: 'flat'
      })
      if (validationResults) {
        this.error = true
        this.errorMessage = validationResults[0]
        this.$forceUpdate()
Nick's avatar
Nick committed
190
        return
191 192 193
      }

      this.loading = true
Nick's avatar
Nick committed
194
      this.success = false
195
      this.$forceUpdate()
196

Nick's avatar
Nick committed
197 198
      _.delay(async () => {
        try {
199 200 201 202 203 204 205 206 207 208
          const resp = await fetch('/finalize', {
            method: 'POST',
            cache: 'no-cache',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify(this.conf)
          }).then(res => res.json())

          if (resp.ok === true) {
209
            _.delay(() => {
210 211 212 213 214
              confetti({
                particleCount: 100,
                spread: 70,
                zIndex: 100000
              })
Nick's avatar
Nick committed
215 216 217 218 219
              this.success = true
              _.delay(() => {
                window.location.assign('/login')
              }, 3000)
            }, 10000)
220
          } else {
Nick's avatar
Nick committed
221
            this.error = true
222
            this.errorMessage = resp.error
Nick's avatar
Nick committed
223
            this.loading = false
224
          }
225
        } catch (err) {
226
          window.alert(err.message)
Nick's avatar
Nick committed
227
        }
228 229 230 231 232 233
      }, 1000)
    }
  }
}

</script>
234 235

<style lang='scss'>
Nick's avatar
Nick committed
236
.setup {
237
  .v-application--wrap {
Nick's avatar
Nick committed
238
    padding-top: 10vh;
239 240 241 242 243 244 245 246 247 248 249 250 251
    background-color: #111;
    background-image: linear-gradient(45deg, mc('blue', '100'), mc('blue', '700'), mc('indigo', '900'));
    background-blend-mode: exclusion;

    &::before {
      content: '';
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100vh;
      z-index: 0;
      background-color: transparent;
252
      background-image: url(../static/svg/motif-grid.svg) !important;
253 254 255 256 257 258 259 260 261 262 263 264 265
      background-size: 100px;
      background-repeat: repeat;
      animation: bg-anim 100s linear infinite;
    }
  }

  @keyframes bg-anim {
    0% {
      background-position: 0 0;
    }
    100% {
      background-position: 100% 100%;
    }
Nick's avatar
Nick committed
266
  }
267

Nick's avatar
Nick committed
268
  &-logo {
269 270
    width: 400px;
    margin: 2rem 0 2rem 0;
Nick's avatar
Nick committed
271 272
  }
}
273
</style>