diff --git a/src/components/ha-sidebar.html b/src/components/ha-sidebar.html
index d364163c8f..d88730b08f 100644
--- a/src/components/ha-sidebar.html
+++ b/src/components/ha-sidebar.html
@@ -113,6 +113,9 @@
+
diff --git a/src/layouts/home-assistant-main.html b/src/layouts/home-assistant-main.html
index 01920bf39e..1e30f570df 100644
--- a/src/layouts/home-assistant-main.html
+++ b/src/layouts/home-assistant-main.html
@@ -8,6 +8,7 @@
+
@@ -50,6 +51,9 @@
+
+
+
diff --git a/src/layouts/home-assistant-main.js b/src/layouts/home-assistant-main.js
index 84b1b1bb17..1e4cf0c90c 100644
--- a/src/layouts/home-assistant-main.js
+++ b/src/layouts/home-assistant-main.js
@@ -12,6 +12,7 @@ require('../layouts/partial-map');
require('../layouts/partial-dev-call-service');
require('../layouts/partial-dev-fire-event');
require('../layouts/partial-dev-set-state');
+require('../layouts/partial-dev-template');
require('../layouts/partial-dev-info');
require('../managers/notification-manager');
require('../dialogs/more-info-dialog');
@@ -71,6 +72,11 @@ export default new Polymer({
bindNuclear: navigationGetters.isActivePane('devState'),
},
+ isSelectedDevTemplate: {
+ type: Boolean,
+ bindNuclear: navigationGetters.isActivePane('devTemplate'),
+ },
+
isSelectedDevService: {
type: Boolean,
bindNuclear: navigationGetters.isActivePane('devService'),
diff --git a/src/layouts/partial-dev-info.html b/src/layouts/partial-dev-info.html
index b89d61d316..fc71d2ddac 100644
--- a/src/layouts/partial-dev-info.html
+++ b/src/layouts/partial-dev-info.html
@@ -4,8 +4,6 @@
-
-
+
+
+ Template Editor
+
+
+
+
+ Templates are rendered using the Jinja2 template engine with some Home Assistant specific extensions.
+
+
+
+
+
+
+
+
+
+
diff --git a/src/layouts/partial-dev-template.js b/src/layouts/partial-dev-template.js
new file mode 100644
index 0000000000..eaed2ee36c
--- /dev/null
+++ b/src/layouts/partial-dev-template.js
@@ -0,0 +1,94 @@
+import hass from '../util/home-assistant-js-instance';
+
+import Polymer from '../polymer';
+import nuclearObserver from '../util/bound-nuclear-behavior';
+
+require('./partial-base');
+
+const {
+ templateActions,
+} = hass;
+
+export default new Polymer({
+ is: 'partial-dev-template',
+
+ behaviors: [nuclearObserver],
+
+ properties: {
+ narrow: {
+ type: Boolean,
+ value: false,
+ },
+
+ showMenu: {
+ type: Boolean,
+ value: false,
+ },
+
+ error: {
+ type: Boolean,
+ value: false,
+ },
+
+ rendering: {
+ type: Boolean,
+ value: false,
+ },
+
+ template: {
+ type: String,
+ value: '{%- if is_state("device_tracker.paulus", "home") and \n' +
+ ' is_state("device_tracker.anne_therese", "home") -%}\n' +
+ '\n' +
+ ' You are both home, you silly\n' +
+ '\n' +
+ '{%- else -%}\n' +
+ '\n' +
+ ' Anne Therese is at {{ states("device_tracker.anne_therese") }} and ' +
+ 'Paulus is at {{ states("device_tracker.paulus") }}\n' +
+ '\n' +
+ '{%- endif %}\n' +
+ '\n' +
+ 'For loop example:\n' +
+ '\n' +
+ '{% for state in states.sensor -%}\n' +
+ ' {%- if loop.first %}The {% elif loop.last %} and the {% else %}, the {% endif -%}\n' +
+ ' {{ state.name | lower }} is {{state.state}} {{- state.attributes.unit_of_measurement}}\n' +
+ '{%- endfor -%}.',
+ observer: 'templateChanged',
+ },
+
+ processed: {
+ type: String,
+ value: '',
+ },
+ },
+
+ computeFormClasses(narrow) {
+ return 'content fit layout ' + (narrow ? 'vertical' : 'horizontal');
+ },
+
+ computeRenderedClasses(error) {
+ return error ? 'error rendered' : 'rendered';
+ },
+
+ templateChanged() {
+ if (this.error) {
+ this.error = false;
+ }
+ this.debounce('render-template', this.renderTemplate, 500);
+ },
+
+ renderTemplate() {
+ this.rendering = true;
+
+ templateActions.render(this.template).then(processed => {
+ this.processed = processed;
+ this.rendering = false;
+ }, error => {
+ this.processed = error.message;
+ this.error = true;
+ this.rendering = false;
+ });
+ },
+});
diff --git a/src/layouts/partial-zone.html b/src/layouts/partial-zone.html
index ad8d7db5f3..aa20e2d09b 100644
--- a/src/layouts/partial-zone.html
+++ b/src/layouts/partial-zone.html
@@ -31,7 +31,7 @@
on-click="handleListenClick">
-