diff --git a/gulp/tasks/gen-onboarding-html.js b/gulp/tasks/gen-onboarding-html.js new file mode 100644 index 0000000000..3ad18f00ce --- /dev/null +++ b/gulp/tasks/gen-onboarding-html.js @@ -0,0 +1,43 @@ +const gulp = require('gulp'); +const path = require('path'); +const replace = require('gulp-batch-replace'); +const rename = require('gulp-rename'); +const md5 = require('../common/md5'); +const url = require('url'); + +const config = require('../config'); +const minifyStream = require('../common/transform').minifyStream; + +const buildReplaces = { + '/frontend_latest/onboarding.js': 'onboarding.js', +}; + +const es5Extra = ""; + +async function buildOnboarding(es6) { + const targetPath = es6 ? config.output : config.output_es5; + const targetUrl = es6 ? '/frontend_latest/' : '/frontend_es5/'; + const frontendPath = es6 ? 'frontend_latest' : 'frontend_es5'; + const toReplace = [ + ['', es6 ? '' : es5Extra], + ['/home-assistant-polymer/hass_frontend/onboarding.js', `/${frontendPath}/onboarding.js`], + ]; + + for (const [replaceSearch, filename] of Object.entries(buildReplaces)) { + const parsed = path.parse(filename); + const hash = md5(path.resolve(targetPath, filename)); + toReplace.push([ + replaceSearch, + url.resolve(targetUrl, `${parsed.name}-${hash}${parsed.ext}`)]); + } + + const stream = gulp.src(path.resolve(config.polymer_dir, 'src/onboarding.html')) + .pipe(replace(toReplace)); + + return minifyStream(stream, /* es6= */ es6) + .pipe(rename('onboarding.html')) + .pipe(gulp.dest(es6 ? config.output : config.output_es5)); +} + +gulp.task('gen-onboarding-html-es5', () => buildOnboarding(/* es6= */ false)); +gulp.task('gen-onboarding-html', () => buildOnboarding(/* es6= */ true)); diff --git a/script/build_frontend b/script/build_frontend index b7126bd40f..30e05e017e 100755 --- a/script/build_frontend +++ b/script/build_frontend @@ -29,5 +29,5 @@ echo "CREATED_AT = `date +%s`" >> $OUTPUT_DIR_ES5/__init__.py # Generate index.htmls with the MD5 hash of the builds ./node_modules/.bin/gulp \ gen-index-html gen-index-html-es5 \ - gen-authorize-html gen-authorize-html-es5 - + gen-authorize-html gen-authorize-html-es5 \ + gen-onboarding-html gen-onboarding-html-es5 diff --git a/script/develop b/script/develop index d164828f85..e800ee7830 100755 --- a/script/develop +++ b/script/develop @@ -15,5 +15,6 @@ cp -r public/__init__.py $OUTPUT_DIR_ES5/ ./node_modules/.bin/gulp build-translations gen-icons cp src/authorize.html $OUTPUT_DIR +cp src/onboarding.html $OUTPUT_DIR ./node_modules/.bin/webpack --watch --progress diff --git a/src/authorize.html b/src/authorize.html index 106b41c311..4873cb10e0 100644 --- a/src/authorize.html +++ b/src/authorize.html @@ -4,6 +4,17 @@ Home Assistant + Loading diff --git a/src/entrypoints/app.js b/src/entrypoints/app.js index 1c8ebdf801..2ac312c825 100644 --- a/src/entrypoints/app.js +++ b/src/entrypoints/app.js @@ -24,7 +24,7 @@ import '../resources/ha-style.js'; import '../util/ha-pref-storage.js'; import { getActiveTranslation, getTranslation } from '../util/hass-translation.js'; import '../util/legacy-support'; -import '../util/roboto.js'; +import '../resources/roboto.js'; import hassCallApi from '../util/hass-call-api.js'; import makeDialogManager from '../dialogs/dialog-manager.js'; import registerServiceWorker from '../util/register-service-worker.js'; diff --git a/src/entrypoints/authorize.js b/src/entrypoints/authorize.js index b62c78ccd1..4f2c00dec9 100644 --- a/src/entrypoints/authorize.js +++ b/src/entrypoints/authorize.js @@ -5,6 +5,7 @@ import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import '../components/ha-iconset-svg.js'; +import '../resources/roboto.js'; import '../auth/ha-auth-flow.js'; import '../auth/ha-pick-auth-provider.js'; diff --git a/src/entrypoints/onboarding.js b/src/entrypoints/onboarding.js new file mode 100644 index 0000000000..945fbe2e0c --- /dev/null +++ b/src/entrypoints/onboarding.js @@ -0,0 +1,3 @@ +import '../components/ha-iconset-svg.js'; +import '../resources/roboto.js'; +import '../onboarding/ha-onboarding.js'; diff --git a/src/onboarding.html b/src/onboarding.html new file mode 100644 index 0000000000..3ffa72caf6 --- /dev/null +++ b/src/onboarding.html @@ -0,0 +1,34 @@ + + + + + Home Assistant + + + + + Loading + + + + + diff --git a/src/onboarding/ha-onboarding.js b/src/onboarding/ha-onboarding.js new file mode 100644 index 0000000000..58fe8c11af --- /dev/null +++ b/src/onboarding/ha-onboarding.js @@ -0,0 +1,125 @@ +import '@polymer/iron-flex-layout/iron-flex-layout-classes.js'; +import '@polymer/polymer/lib/elements/dom-if.js'; +import '@polymer/polymer/lib/elements/dom-repeat.js'; +import '@polymer/paper-input/paper-input.js'; +import '@polymer/paper-button/paper-button.js'; +import { html } from '@polymer/polymer/lib/utils/html-tag.js'; +import { PolymerElement } from '@polymer/polymer/polymer-element.js'; +import hassCallApi from '../util/hass-call-api.js'; + +const callApi = (method, path, data) => hassCallApi('', {}, method, path, data); + +class HaOnboarding extends PolymerElement { + static get template() { + return html` + + +
+ + +

Create your owner user account.

+

It is not possible yet to change your password. Coming soon!

+ + + + + + + + + + +
+`; + } + + static get properties() { + return { + _name: String, + _username: String, + _password: String, + _loading: { + type: Boolean, + value: false, + } + }; + } + + async ready() { + super.ready(); + this.addEventListener('keypress', (ev) => { + if (ev.keyCode === 13) { + this._submitForm(); + } + }); + const steps = await callApi('get', 'onboarding'); + if (steps.every(step => step.done)) { + // Onboarding is done! + document.location = '/'; + } + } + + _maybePopulateUsername() { + if (!this._username) { + this._username = this._name.toLowerCase().replace(/ /g, ''); + } + } + + async _submitForm() { + if (!this._name || !this._username || !this._password) return; + + try { + await callApi('post', 'onboarding/users', { + name: this._name, + username: this._username, + password: this._password, + }); + + document.location = '/'; + } catch (err) { + // eslint-disable-next-line + console.error(err); + this.setProperties({ + _loading: false, + _error: err.message, + }); + } + } +} +customElements.define('ha-onboarding', HaOnboarding); diff --git a/src/util/roboto.js b/src/resources/roboto.js similarity index 100% rename from src/util/roboto.js rename to src/resources/roboto.js diff --git a/webpack.config.js b/webpack.config.js index 0ffec03254..920fcd0880 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,6 +20,7 @@ function createConfig(isProdBuild, latestBuild) { const entry = { app: './src/entrypoints/app.js', authorize: './src/entrypoints/authorize.js', + onboarding: './src/entrypoints/onboarding.js', core: './src/entrypoints/core.js', compatibility: './src/entrypoints/compatibility.js', 'custom-panel': './src/entrypoints/custom-panel.js',