Update frontend to use NuclearJS
This commit is contained in:
parent
4221eef428
commit
7ef0dec185
34 changed files with 1691 additions and 1542 deletions
|
@ -102,8 +102,8 @@ def setup(hass, config):
|
|||
{
|
||||
"auto": True,
|
||||
ATTR_ENTITY_ID: [
|
||||
"device_tracker.Paulus",
|
||||
"device_tracker.Anne_Therese"
|
||||
"device_tracker.paulus",
|
||||
"device_tracker.anne_therese"
|
||||
]
|
||||
})
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
""" DO NOT MODIFY. Auto-generated by build_frontend script """
|
||||
VERSION = "010d9683fa9d210abd199b3cde4edbc0"
|
||||
VERSION = "18d02dc9820b907ac4159da09cd20c4b"
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -37,7 +37,8 @@
|
|||
"layout": "Polymer/layout",
|
||||
"color-picker-element": "~0.0.3",
|
||||
"paper-styles": "polymerelements/paper-styles#^1.0.0",
|
||||
"paper-date-picker": "vsimonian/paper-date-picker#master"
|
||||
"paper-date-picker": "vsimonian/paper-date-picker#master",
|
||||
"lodash": "~3.9.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"polymer": "^1.0.0",
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>
|
||||
(function(){
|
||||
var uiActions = window.hass.uiActions;
|
||||
var moreInfoActions = window.hass.moreInfoActions;
|
||||
|
||||
Polymer({
|
||||
is: 'state-card',
|
||||
|
@ -44,7 +44,7 @@
|
|||
cardTapped: function(ev) {
|
||||
ev.stopPropagation();
|
||||
this.debounce('show-more-info-dialog', function() {
|
||||
uiActions.showMoreInfoDialog(this.stateObj.entityId);
|
||||
moreInfoActions.selectEntity(this.stateObj.entityId);
|
||||
}.bind(this), 100);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<template>
|
||||
<ul>
|
||||
<template is='dom-repeat' items='[[entities]]' as='entity'>
|
||||
<li><a href='#' on-click='entitySelected'>[[entity]]</a></li>
|
||||
<li><a href='#' on-click='entitySelected'>[[entity.entityId]]</a></li>
|
||||
</template>
|
||||
</ul>
|
||||
</template>
|
||||
|
@ -28,25 +28,30 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var entityGetters = window.hass.entityGetters;
|
||||
|
||||
Polymer({
|
||||
is: 'entity-list',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
entities: {
|
||||
type: Array,
|
||||
value: [],
|
||||
bindNuclear: [
|
||||
entityGetters.entityMap,
|
||||
function(map) {
|
||||
return map.valueSeq().
|
||||
sortBy(function(entity) { return entity.entityId; })
|
||||
.toArray();
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
stateStoreChanged: function(stateStore) {
|
||||
this.entities = stateStore.entityIDs.toArray();
|
||||
},
|
||||
|
||||
entitySelected: function(ev) {
|
||||
ev.preventDefault();
|
||||
this.fire('entity-selected', {entityId: ev.model.entity});
|
||||
this.fire('entity-selected', {entityId: ev.model.entity.entityId});
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -31,22 +31,27 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var eventGetters = window.hass.eventGetters;
|
||||
|
||||
Polymer({
|
||||
is: 'events-list',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
events: {
|
||||
type: Array,
|
||||
value: [],
|
||||
bindNuclear: [
|
||||
eventGetters.entityMap,
|
||||
function(map) {
|
||||
return map.valueSeq()
|
||||
.sortBy(function(event) { return event.event; })
|
||||
.toArray();
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
eventStoreChanged: function(eventStore) {
|
||||
this.events = eventStore.all.toArray();
|
||||
},
|
||||
|
||||
eventSelected: function(ev) {
|
||||
ev.preventDefault();
|
||||
this.fire('event-selected', {eventType: ev.model.event.event});
|
||||
|
|
|
@ -54,14 +54,14 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var uiActions = window.hass.uiActions;
|
||||
var moreInfoActions = window.hass.moreInfoActions;
|
||||
|
||||
Polymer({
|
||||
is: 'logbook-entry',
|
||||
|
||||
entityClicked: function(ev) {
|
||||
ev.preventDefault();
|
||||
uiActions.showMoreInfoDialog(this.entryObj.entityId);
|
||||
moreInfoActions.selectEntity(this.entryObj.entityId);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -23,10 +23,10 @@
|
|||
|
||||
<template>
|
||||
<ul>
|
||||
<template is='dom-repeat' items="[[domains]]" as="domain">
|
||||
<template is='dom-repeat' items="[[computeServices(domain)]]" as="service">
|
||||
<template is='dom-repeat' items="[[serviceDomains]]" as="domain">
|
||||
<template is='dom-repeat' items="[[domain.services]]" as="service">
|
||||
<li><a href='#' on-click='serviceClicked'>
|
||||
<span>[[domain]]</span>/<span>[[service]]</span>
|
||||
<span>[[domain.domain]]</span>/<span>[[service]]</span>
|
||||
</a></li>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -36,19 +36,24 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var serviceGetters = window.hass.serviceGetters;
|
||||
|
||||
Polymer({
|
||||
is: 'services-list',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
domains: {
|
||||
serviceDomains: {
|
||||
type: Array,
|
||||
value: [],
|
||||
},
|
||||
|
||||
services: {
|
||||
type: Object,
|
||||
bindNuclear: [
|
||||
serviceGetters.entityMap,
|
||||
function(map) {
|
||||
return map.valueSeq()
|
||||
.sortBy(function(domain) { return domain.domain; })
|
||||
.toJS();
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -56,15 +61,10 @@
|
|||
return this.services.get(domain).toArray();
|
||||
},
|
||||
|
||||
serviceStoreChanged: function(serviceStore) {
|
||||
this.services = serviceStore.all;
|
||||
this.domains = this.services.keySeq().sort().toArray();
|
||||
},
|
||||
|
||||
serviceClicked: function(ev) {
|
||||
ev.preventDefault();
|
||||
this.fire(
|
||||
'service-selected', {domain: ev.model.domain, service: ev.model.service});
|
||||
'service-selected', {domain: ev.model.domain.domain, service: ev.model.service});
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
|
||||
<link rel="import" href="../resources/lodash.html">
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
Polymer({
|
||||
|
|
|
@ -39,12 +39,11 @@
|
|||
if (!this.isAttached) {
|
||||
return;
|
||||
}
|
||||
|
||||
var root = Polymer.dom(this);
|
||||
var stateHistory = this.data;
|
||||
|
||||
while (root.lastChild) {
|
||||
root.removeChild(root.lastChild);
|
||||
while (root.node.lastChild) {
|
||||
root.node.removeChild(root.node.lastChild);
|
||||
}
|
||||
|
||||
if (!stateHistory || stateHistory.length === 0) {
|
||||
|
@ -64,11 +63,12 @@
|
|||
dataTable.addRow([entityDisplay, stateStr, start, end]);
|
||||
};
|
||||
|
||||
var startTime = new Date(stateHistory.map(function(stateInfo) {
|
||||
return stateInfo[0].lastChangedAsDate;
|
||||
}).reduce(function(prev, cur) {
|
||||
return Math.min(prev, cur);
|
||||
}, new Date()));
|
||||
var startTime = new Date(
|
||||
stateHistory.reduce(function(minTime, stateInfo) {
|
||||
return Math.min(
|
||||
minTime, stateInfo[0].lastChangedAsDate);
|
||||
}, new Date())
|
||||
);
|
||||
|
||||
// end time is Math.min(curTime, start time + 1 day)
|
||||
var endTime = new Date(startTime);
|
||||
|
|
|
@ -34,8 +34,9 @@
|
|||
No state history found.
|
||||
</template>
|
||||
|
||||
<state-history-chart-timeline data='[[groupedStateHistory.timeline]]'
|
||||
is-single-device='[[isSingleDevice]]'>
|
||||
<state-history-chart-timeline
|
||||
data='[[groupedStateHistory.timeline]]'
|
||||
is-single-device='[[isSingleDevice]]'>
|
||||
</state-history-chart-timeline>
|
||||
|
||||
<template is='dom-repeat' items='[[groupedStateHistory.line]]'>
|
||||
|
@ -84,36 +85,35 @@
|
|||
},
|
||||
|
||||
computeIsSingleDevice: function(stateHistory) {
|
||||
return stateHistory && stateHistory.length == 1;
|
||||
return stateHistory && stateHistory.size == 1;
|
||||
},
|
||||
|
||||
computeGroupedStateHistory: function(isLoading, stateHistory) {
|
||||
if (isLoading || !stateHistory) {
|
||||
return {line: [], timeline: []};
|
||||
}
|
||||
|
||||
var lineChartDevices = {};
|
||||
var timelineDevices = [];
|
||||
|
||||
if (isLoading || !stateHistory) {
|
||||
return {line: unitStates, timeline: timelineDevices};
|
||||
}
|
||||
|
||||
stateHistory.forEach(function(stateInfo) {
|
||||
if (!stateInfo || stateInfo.length === 0) {
|
||||
if (!stateInfo || stateInfo.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var unit;
|
||||
var stateWithUnit = stateInfo.find(function(state) {
|
||||
return 'unit_of_measurement' in state.attributes;
|
||||
});
|
||||
|
||||
for (var i = 0; i < stateInfo.length && !unit; i++) {
|
||||
unit = stateInfo[i].attributes.unit_of_measurement;
|
||||
}
|
||||
var unit = stateWithUnit ?
|
||||
stateWithUnit.attributes.unit_of_measurement : false;
|
||||
|
||||
if (unit) {
|
||||
if (!(unit in lineChartDevices)) {
|
||||
lineChartDevices[unit] = [stateInfo];
|
||||
} else {
|
||||
lineChartDevices[unit].push(stateInfo);
|
||||
}
|
||||
if (!unit) {
|
||||
timelineDevices.push(stateInfo.toArray());
|
||||
} else if(unit in lineChartDevices) {
|
||||
lineChartDevices[unit].push(stateInfo.toArray());
|
||||
} else {
|
||||
timelineDevices.push(stateInfo);
|
||||
lineChartDevices[unit] = [stateInfo.toArray()];
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -143,7 +143,7 @@
|
|||
},
|
||||
|
||||
computeIsEmpty: function(stateHistory) {
|
||||
return stateHistory && stateHistory.length === 0;
|
||||
return stateHistory && stateHistory.size === 0;
|
||||
},
|
||||
|
||||
extractUnit: function(arr) {
|
||||
|
|
|
@ -17,42 +17,37 @@
|
|||
}
|
||||
</style>
|
||||
<template>
|
||||
<iron-icon icon="warning" hidden$="{{!hasError}}"></iron-icon>
|
||||
<paper-toggle-button id="toggle" on-change='toggleChanged' hidden$="{{hasError}}"></paper-toggle-button>
|
||||
<iron-icon icon="warning" hidden$="[[!hasError]]"></iron-icon>
|
||||
<paper-toggle-button id="toggle" on-change='toggleChanged' checked$='[[isStreaming]]' hidden$="[[hasError]]"></paper-toggle-button>
|
||||
</template>
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
var streamGetters = window.hass.streamGetters;
|
||||
var streamActions = window.hass.streamActions;
|
||||
var authStore = window.hass.authStore;
|
||||
|
||||
Polymer({
|
||||
is: 'stream-status',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
isStreaming: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: streamGetters.isStreamingEvents,
|
||||
},
|
||||
|
||||
hasError: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: streamGetters.hasStreamingEventsError,
|
||||
},
|
||||
},
|
||||
|
||||
streamStoreChanged: function(streamStore) {
|
||||
this.hasError = streamStore.hasError;
|
||||
this.$.toggle.checked = this.isStreaming = streamStore.isStreaming;
|
||||
},
|
||||
|
||||
toggleChanged: function(ev) {
|
||||
toggleChanged: function() {
|
||||
if (this.isStreaming) {
|
||||
streamActions.stop();
|
||||
} else {
|
||||
streamActions.start(authStore.authToken);
|
||||
streamActions.start();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -49,36 +49,51 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var stateStore = window.hass.stateStore;
|
||||
var stateHistoryStore = window.hass.stateHistoryStore;
|
||||
var stateHistoryActions = window.hass.stateHistoryActions;
|
||||
|
||||
var configGetters = window.hass.configGetters;
|
||||
var entityHistoryGetters = window.hass.entityHistoryGetters;
|
||||
|
||||
var entityHistoryActions = window.hass.entityHistoryActions;
|
||||
var moreInfoGetters = window.hass.moreInfoGetters;
|
||||
var moreInfoActions = window.hass.moreInfoActions;
|
||||
|
||||
Polymer({
|
||||
is: 'more-info-dialog',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
entityId: {
|
||||
type: String,
|
||||
},
|
||||
|
||||
stateObj: {
|
||||
type: Object,
|
||||
bindNuclear: moreInfoGetters.currentEntity,
|
||||
observer: 'fetchHistoryData',
|
||||
},
|
||||
|
||||
stateHistory: {
|
||||
type: Object,
|
||||
bindNuclear: [
|
||||
moreInfoGetters.currentEntityHistory,
|
||||
function(history) {
|
||||
return history ? [history] : false;
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
isLoadingHistoryData: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: entityHistoryGetters.isLoadingEntityHistory,
|
||||
},
|
||||
|
||||
hasHistoryComponent: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: configGetters.isComponentLoaded('history'),
|
||||
observer: 'fetchHistoryData',
|
||||
},
|
||||
|
||||
shouldFetchHistory: {
|
||||
type: Boolean,
|
||||
bindNuclear: moreInfoGetters.isCurrentEntityHistoryStale,
|
||||
observer: 'fetchHistoryData',
|
||||
},
|
||||
|
||||
dialogOpen: {
|
||||
|
@ -92,31 +107,10 @@
|
|||
'iron-overlay-closed': 'onIronOverlayClosed'
|
||||
},
|
||||
|
||||
componentStoreChanged: function(componentStore) {
|
||||
this.hasHistoryComponent = componentStore.isLoaded('history');
|
||||
},
|
||||
|
||||
stateStoreChanged: function() {
|
||||
var newState = this.entityId ? stateStore.get(this.entityId) : null;
|
||||
|
||||
if (newState !== this.stateObj) {
|
||||
this.stateObj = newState;
|
||||
}
|
||||
},
|
||||
|
||||
stateHistoryStoreChanged: function() {
|
||||
var newHistory;
|
||||
|
||||
if (this.hasHistoryComponent && this.entityId) {
|
||||
newHistory = [stateHistoryStore.get(this.entityId)];
|
||||
} else {
|
||||
newHistory = null;
|
||||
}
|
||||
|
||||
this.isLoadingHistoryData = false;
|
||||
|
||||
if (newHistory !== this.stateHistory) {
|
||||
this.stateHistory = newHistory;
|
||||
fetchHistoryData: function(newVal) {
|
||||
if (this.stateObj && this.hasHistoryComponent &&
|
||||
this.shouldFetchHistory) {
|
||||
entityHistoryActions.fetchRecent(this.stateObj.entityId);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -126,30 +120,13 @@
|
|||
|
||||
onIronOverlayClosed: function() {
|
||||
this.dialogOpen = false;
|
||||
moreInfoActions.deselectEntity();
|
||||
},
|
||||
|
||||
changeEntityId: function(entityId) {
|
||||
if (entityId == this.entityId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.entityId = entityId;
|
||||
|
||||
this.stateStoreChanged();
|
||||
this.stateHistoryStoreChanged();
|
||||
|
||||
if (this.hasHistoryComponent && stateHistoryStore.shouldFetchEntity(entityId)) {
|
||||
this.isLoadingHistoryData = true;
|
||||
stateHistoryActions.fetch(entityId);
|
||||
}
|
||||
},
|
||||
|
||||
show: function(entityId) {
|
||||
this.changeEntityId(entityId);
|
||||
|
||||
show: function() {
|
||||
this.debounce('showDialogAfterRender', function() {
|
||||
this.$.dialog.toggle();
|
||||
}.bind(this));
|
||||
this.$.dialog.open();
|
||||
}.bind(this), 1);
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 5a7165b272fe2ed3e1b1432e2e621c3b971cc4bf
|
||||
Subproject commit 53941ad076fa5d453370cb6922cf6770202dc76e
|
|
@ -21,9 +21,8 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<home-assistant-icons></home-assistant-icons>
|
||||
|
||||
<template>
|
||||
<home-assistant-icons></home-assistant-icons>
|
||||
<template is='dom-if' if='[[!loaded]]'>
|
||||
<login-form></login-form>
|
||||
</template>
|
||||
|
@ -37,10 +36,10 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
var storeListenerMixIn = window.hass.storeListenerMixIn,
|
||||
uiActions = window.hass.uiActions,
|
||||
preferenceStore = window.hass.preferenceStore;
|
||||
var uiActions = window.hass.uiActions;
|
||||
var authGetters = window.hass.authGetters;
|
||||
var syncGetters = window.hass.syncGetters;
|
||||
var uiPreferences = window.hass.uiPreferences;
|
||||
|
||||
Polymer({
|
||||
is: 'home-assistant',
|
||||
|
@ -49,15 +48,24 @@
|
|||
auth: null,
|
||||
},
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
auth: {
|
||||
type: String,
|
||||
},
|
||||
loaded: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: 'loadedChanged',
|
||||
bindNuclear: syncGetters.isDataLoaded,
|
||||
},
|
||||
},
|
||||
|
||||
loadedChanged: function(newVal, oldVal) {
|
||||
console.log("Loaded changed", newVal);
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
// remove the HTML init message
|
||||
document.getElementById('init').remove();
|
||||
|
@ -65,13 +73,11 @@
|
|||
// if auth was given, tell the backend
|
||||
if(this.auth) {
|
||||
uiActions.validateAuth(this.auth, false);
|
||||
} else if (preferenceStore.hasAuthToken) {
|
||||
uiActions.validateAuth(preferenceStore.authToken, false);
|
||||
} else if (uiPreferences.authToken) {
|
||||
uiActions.validateAuth(uiPreferences.authToken, false);
|
||||
}
|
||||
},
|
||||
|
||||
syncStoreChanged: function(syncStore) {
|
||||
this.loaded = syncStore.initialLoadDone;
|
||||
uiPreferences.startSync();
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
<iron-icon item-icon icon='apps'></iron-icon> States
|
||||
</paper-icon-item>
|
||||
|
||||
<template is='dom-repeat' items='{{activeFilters}}'>
|
||||
<template is='dom-repeat' items='{{possibleFilters}}'>
|
||||
<paper-icon-item data-panel$='[[filterType(item)]]'>
|
||||
<iron-icon item-icon icon='[[filterIcon(item)]]'></iron-icon>
|
||||
<span>[[filterName(item)]]</span>
|
||||
|
@ -110,25 +110,22 @@
|
|||
<div class='text label divider'>Developer Tools</div>
|
||||
<div class='dev-tools layout horizontal justified'>
|
||||
<paper-icon-button
|
||||
icon='settings-remote' data-panel$='[[selectedDevService]]'
|
||||
icon='settings-remote' data-panel='devService'
|
||||
on-click='handleDevClick'></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon='settings-ethernet' data-panel$='[[selectedDevState]]'
|
||||
icon='settings-ethernet' data-panel='devState'
|
||||
on-click='handleDevClick'></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon='settings-input-antenna' data-panel$='[[selectedDevEvent]]'
|
||||
icon='settings-input-antenna' data-panel='devEvent'
|
||||
on-click='handleDevClick'></paper-icon-button>
|
||||
</div>
|
||||
</paper-menu>
|
||||
</paper-header-panel>
|
||||
|
||||
<template is='dom-if' if='[[!hideStates]]'>
|
||||
<partial-states
|
||||
main narrow='[[narrow]]'
|
||||
filter='[[stateFilter]]'>
|
||||
<template is='dom-if' if='[[isSelectedStates]]'>
|
||||
<partial-states main narrow='[[narrow]]'>
|
||||
</partial-states>
|
||||
</template>
|
||||
|
||||
<template is='dom-if' if='[[isSelectedLogbook]]'>
|
||||
<partial-logbook main narrow='[[narrow]]'></partial-logbook>
|
||||
</template>
|
||||
|
@ -151,117 +148,86 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var configGetters = window.hass.configGetters;
|
||||
var entityGetters = window.hass.entityGetters;
|
||||
var navigationGetters = window.hass.navigationGetters;
|
||||
|
||||
var authActions = window.hass.authActions;
|
||||
var navigationActions = window.hass.navigationActions;
|
||||
|
||||
var uiUtil = window.hass.uiUtil;
|
||||
var uiConstants = window.hass.uiConstants;
|
||||
var entityDomainFilters = window.hass.util.entityDomainFilters;
|
||||
|
||||
Polymer({
|
||||
is: 'home-assistant-main',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
selected: {
|
||||
type: String,
|
||||
value: 'states',
|
||||
},
|
||||
|
||||
stateFilter: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
|
||||
narrow: {
|
||||
type: Boolean,
|
||||
},
|
||||
|
||||
activeFilters: {
|
||||
selected: {
|
||||
type: String,
|
||||
bindNuclear: [
|
||||
navigationGetters.activePane,
|
||||
navigationGetters.activeFilter,
|
||||
function(pane, filter) {
|
||||
return filter ? pane + '/' + filter : pane;
|
||||
},
|
||||
],
|
||||
observer: 'selectedChanged',
|
||||
},
|
||||
|
||||
possibleFilters: {
|
||||
type: Array,
|
||||
value: [],
|
||||
bindNuclear: [
|
||||
navigationGetters.possibleEntityDomainFilters,
|
||||
function(domains) { return domains.toArray(); }
|
||||
],
|
||||
},
|
||||
|
||||
hasHistoryComponent: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: configGetters.isComponentLoaded('history'),
|
||||
},
|
||||
|
||||
hasLogbookComponent: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: configGetters.isComponentLoaded('logbook'),
|
||||
},
|
||||
|
||||
isStreaming: {
|
||||
isSelectedStates: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
hasStreamError: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
hideStates: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
selectedHistory: {
|
||||
type: String,
|
||||
value: 'history',
|
||||
readOnly: true,
|
||||
bindNuclear: navigationGetters.isActivePane('states'),
|
||||
},
|
||||
|
||||
isSelectedHistory: {
|
||||
type: Boolean,
|
||||
computed: 'computeIsSelected(selected, selectedHistory)',
|
||||
},
|
||||
|
||||
selectedLogbook: {
|
||||
type: String,
|
||||
value: 'logbook',
|
||||
readOnly: true,
|
||||
bindNuclear: navigationGetters.isActivePane('history'),
|
||||
},
|
||||
|
||||
isSelectedLogbook: {
|
||||
type: Boolean,
|
||||
computed: 'computeIsSelected(selected, selectedLogbook)',
|
||||
},
|
||||
|
||||
selectedDevEvent: {
|
||||
type: String,
|
||||
value: 'devEvent',
|
||||
readOnly: true,
|
||||
bindNuclear: navigationGetters.isActivePane('logbook'),
|
||||
},
|
||||
|
||||
isSelectedDevEvent: {
|
||||
type: Boolean,
|
||||
computed: 'computeIsSelected(selected, selectedDevEvent)',
|
||||
},
|
||||
|
||||
selectedDevState: {
|
||||
type: String,
|
||||
value: 'devState',
|
||||
readOnly: true,
|
||||
bindNuclear: navigationGetters.isActivePane('devEvent'),
|
||||
},
|
||||
|
||||
isSelectedDevState: {
|
||||
type: Boolean,
|
||||
computed: 'computeIsSelected(selected, selectedDevState)',
|
||||
},
|
||||
|
||||
selectedDevService: {
|
||||
type: String,
|
||||
value: 'devService',
|
||||
readOnly: true,
|
||||
bindNuclear: navigationGetters.isActivePane('devState'),
|
||||
},
|
||||
|
||||
isSelectedDevService: {
|
||||
type: Boolean,
|
||||
computed: 'computeIsSelected(selected, selectedDevService)',
|
||||
bindNuclear: navigationGetters.isActivePane('devService'),
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
listeners: {
|
||||
|
@ -269,17 +235,6 @@
|
|||
'open-menu': 'openDrawer',
|
||||
},
|
||||
|
||||
stateStoreChanged: function(stateStore) {
|
||||
this.activeFilters = stateStore.domains.filter(function(domain) {
|
||||
return domain in uiConstants.STATE_FILTERS;
|
||||
}).toArray();
|
||||
},
|
||||
|
||||
componentStoreChanged: function(componentStore) {
|
||||
this.hasHistoryComponent = componentStore.isLoaded('history');
|
||||
this.hasLogbookComponent = componentStore.isLoaded('logbook');
|
||||
},
|
||||
|
||||
menuSelect: function(ev, detail, sender) {
|
||||
this.selectPanel(this.$.menu.selected);
|
||||
},
|
||||
|
@ -299,15 +254,9 @@
|
|||
}
|
||||
|
||||
this.closeDrawer();
|
||||
this.selected = newChoice;
|
||||
|
||||
if (newChoice.substr(0, 7) === 'states_') {
|
||||
this.hideStates = false;
|
||||
this.stateFilter = newChoice.substr(7);
|
||||
} else {
|
||||
this.hideStates = newChoice !== 'states';
|
||||
this.stateFilter = null;
|
||||
}
|
||||
navigationActions.navigate.apply(
|
||||
null, newChoice.split('/'));
|
||||
},
|
||||
|
||||
openDrawer: function() {
|
||||
|
@ -322,21 +271,41 @@
|
|||
authActions.logOut();
|
||||
},
|
||||
|
||||
computeIsSelected: function(selected, selectedType) {
|
||||
return selected === selectedType;
|
||||
},
|
||||
|
||||
filterIcon: function(filter) {
|
||||
return uiUtil.domainIcon(filter);
|
||||
},
|
||||
|
||||
filterName: function(filter) {
|
||||
return uiConstants.STATE_FILTERS[filter];
|
||||
return entityDomainFilters[filter];
|
||||
},
|
||||
|
||||
filterType: function(filter) {
|
||||
return 'states_' + filter;
|
||||
}
|
||||
return 'states/' + filter;
|
||||
},
|
||||
|
||||
hashChanged: function(ev) {
|
||||
var parts = ev.newURL.split('#');
|
||||
if (parts[1]) {
|
||||
this.selectPanel(parts[1]);
|
||||
}
|
||||
},
|
||||
|
||||
selectedChanged: function(newVal) {
|
||||
window.location.hash = newVal;
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
this.hashChanged({newURL: window.location.toString()});
|
||||
},
|
||||
|
||||
attached: function() {
|
||||
this.hashChanged = this.hashChanged.bind(this);
|
||||
window.addEventListener('hashchange', this.hashChanged);
|
||||
},
|
||||
|
||||
detached: function() {
|
||||
window.removeEventListener('hashchange', this.hashChanged);
|
||||
},
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
|
|
@ -86,27 +86,29 @@
|
|||
<script>
|
||||
(function() {
|
||||
var uiActions = window.hass.uiActions;
|
||||
var authGetters = window.hass.authGetters;
|
||||
|
||||
Polymer({
|
||||
is: 'login-form',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
isValidating: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: 'isValidatingChanged',
|
||||
bindNuclear: authGetters.isValidating,
|
||||
},
|
||||
|
||||
isInvalid: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: authGetters.isInvalidAttempt,
|
||||
},
|
||||
|
||||
errorMessage: {
|
||||
type: String,
|
||||
value: '',
|
||||
}
|
||||
bindNuclear: authGetters.attemptErrorMessage,
|
||||
},
|
||||
},
|
||||
|
||||
listeners: {
|
||||
|
@ -114,19 +116,12 @@
|
|||
'loginButton.click': 'validatePassword',
|
||||
},
|
||||
|
||||
attached: function() {
|
||||
this.focusPassword();
|
||||
},
|
||||
// attached: function() {
|
||||
// this.focusPassword();
|
||||
// },
|
||||
|
||||
authStoreChanged: function(authStore) {
|
||||
this.isValidating = authStore.isValidating;
|
||||
|
||||
if (authStore.lastAttemptInvalid) {
|
||||
this.errorMessage = authStore.lastAttemptMessage;
|
||||
this.isInvalid = true;
|
||||
}
|
||||
|
||||
if (!this.isValidating) {
|
||||
isValidatingChanged: function(newVal) {
|
||||
if (!newVal) {
|
||||
setTimeout(this.focusPassword.bind(this), 0);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
eventActions.fire(this.eventType, eventData);
|
||||
eventActions.fireEvent(this.eventType, eventData);
|
||||
},
|
||||
|
||||
computeFormClasses: function(narrow) {
|
||||
|
|
|
@ -50,8 +50,9 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var stateStore = window.hass.stateStore;
|
||||
var stateActions = window.hass.stateActions;
|
||||
var reactor = window.hass.reactor;
|
||||
var entityGetters = window.hass.entityGetters;
|
||||
var entityActions = window.hass.entityActions;
|
||||
|
||||
Polymer({
|
||||
is: 'partial-dev-set-state',
|
||||
|
@ -83,7 +84,7 @@
|
|||
},
|
||||
|
||||
entitySelected: function(ev) {
|
||||
var state = stateStore.get(ev.detail.entityId);
|
||||
var state = reactor.evaluate(entityGetters.byId(ev.detail.entityId));
|
||||
|
||||
this.entityId = state.entityId;
|
||||
this.state = state.state;
|
||||
|
@ -99,7 +100,11 @@
|
|||
return;
|
||||
}
|
||||
|
||||
stateActions.set(this.entityId, this.state, attr);
|
||||
entityActions.save({
|
||||
entityId: this.entityId,
|
||||
state: this.state,
|
||||
attributes: attr,
|
||||
});
|
||||
},
|
||||
|
||||
computeFormClasses: function(narrow) {
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
<div class$="[[computeContentClasses(narrow)]]">
|
||||
<paper-input label='Showing entries for' on-click='handleShowDatePicker'
|
||||
value='[[computeDateCaption(selectedDate)]]'></paper-input>
|
||||
value='[[selectedDate]]'></paper-input>
|
||||
|
||||
<state-history-charts state-history="[[stateHistory]]"
|
||||
is-loading-data="[[isLoadingData]]"></state-history-charts>
|
||||
|
@ -43,68 +43,57 @@
|
|||
</dom-module>
|
||||
<script>
|
||||
(function() {
|
||||
var stateHistoryActions = window.hass.stateHistoryActions;
|
||||
var stateHistoryStore = window.hass.stateHistoryStore;
|
||||
var entityHistoryGetters = window.hass.entityHistoryGetters;
|
||||
var entityHistoryActions = window.hass.entityHistoryActions;
|
||||
var uiActions = window.hass.uiActions;
|
||||
|
||||
function date_to_str(date) {
|
||||
return date.getFullYear() + '-' + (date.getMonth()+1) + '-' + date.getDate();
|
||||
}
|
||||
|
||||
Polymer({
|
||||
is: 'partial-history',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
narrow: {
|
||||
type: Boolean,
|
||||
},
|
||||
|
||||
isDataLoaded: {
|
||||
type: Boolean,
|
||||
bindNuclear: entityHistoryGetters.hasDataForCurrentDate,
|
||||
observer: 'isDataLoadedChanged',
|
||||
},
|
||||
|
||||
stateHistory: {
|
||||
type: Object,
|
||||
bindNuclear: entityHistoryGetters.entityHistoryForCurrentDate,
|
||||
},
|
||||
|
||||
isLoadingData: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: entityHistoryGetters.isLoadingEntityHistory,
|
||||
},
|
||||
|
||||
selectedDate: {
|
||||
type: String,
|
||||
value: null,
|
||||
observer: 'fetchIfNeeded',
|
||||
bindNuclear: entityHistoryGetters.currentDate,
|
||||
},
|
||||
},
|
||||
|
||||
stateHistoryStoreChanged: function() {
|
||||
this.isLoadingData = this.fetchIfNeeded();
|
||||
this.stateHistory = this.isLoadingData ?
|
||||
[] : stateHistoryStore.all(this.selectedDate);
|
||||
},
|
||||
|
||||
computeDateCaption: function(selectedDate) {
|
||||
return selectedDate || 'today';
|
||||
},
|
||||
|
||||
fetchIfNeeded: function() {
|
||||
if (stateHistoryStore.shouldFetch(this.selectedDate)) {
|
||||
this.isLoadingData = true;
|
||||
stateHistoryActions.fetchAll(this.selectedDate);
|
||||
return true;
|
||||
isDataLoadedChanged: function(newVal) {
|
||||
if (!newVal) {
|
||||
entityHistoryActions.fetchSelectedDate();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
handleRefreshClick: function() {
|
||||
this.isLoadingData = true;
|
||||
stateHistoryActions.fetchAll(this.selectedDate);
|
||||
entityHistoryActions.fetchSelectedDate();
|
||||
},
|
||||
|
||||
handleShowDatePicker: function() {
|
||||
uiActions.showDatePicker(function(selectedDate) {
|
||||
this.selectedDate = date_to_str(selectedDate);
|
||||
}.bind(this), this.selectedDate);
|
||||
uiActions.showDatePicker(
|
||||
entityHistoryActions.changeCurrentDate,
|
||||
this.selectedDate);
|
||||
},
|
||||
|
||||
computeContentClasses: function(narrow) {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<div>
|
||||
<div class='selected-date-container'>
|
||||
<paper-input label='Showing entries for' on-click='handleShowDatePicker'
|
||||
value='[[computeDateCaption(selectedDate)]]'></paper-input>
|
||||
value='[[selectedDate]]'></paper-input>
|
||||
|
||||
<loading-box hidden$='[[!isLoading]]'>Loading logbook entries</loading-box>
|
||||
</div>
|
||||
|
@ -40,19 +40,15 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var storeListenerMixIn = window.hass.storeListenerMixIn;
|
||||
var logbookGetters = window.hass.logbookGetters;
|
||||
var logbookActions = window.hass.logbookActions;
|
||||
var logbookStore = window.hass.logbookStore;
|
||||
var uiActions = window.hass.uiActions;
|
||||
|
||||
function date_to_str(date) {
|
||||
return date.getFullYear() + '-' + (date.getMonth()+1) + '-' + date.getDate();
|
||||
}
|
||||
var dateToStr = window.hass.util.dateToStr;
|
||||
|
||||
Polymer({
|
||||
is: 'partial-logbook',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
narrow: {
|
||||
|
@ -62,48 +58,46 @@
|
|||
|
||||
selectedDate: {
|
||||
type: String,
|
||||
value: null,
|
||||
observer: 'fetchIfNeeded',
|
||||
bindNuclear: logbookGetters.currentDate,
|
||||
},
|
||||
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
bindNuclear: logbookGetters.isLoadingEntries,
|
||||
},
|
||||
|
||||
isStale: {
|
||||
type: Boolean,
|
||||
bindNuclear: logbookGetters.isCurrentStale,
|
||||
observer: 'isStaleChanged',
|
||||
},
|
||||
|
||||
entries: {
|
||||
type: Array,
|
||||
value: null,
|
||||
bindNuclear: [
|
||||
logbookGetters.currentEntries,
|
||||
function(entries) { return entries.toArray(); },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
logbookStoreChanged: function() {
|
||||
this.isLoading = this.fetchIfNeeded();
|
||||
var entries = logbookStore.all.toArray();
|
||||
this.entries = entries.length > 0 ? entries : false;
|
||||
},
|
||||
|
||||
computeDateCaption: function(selectedDate) {
|
||||
return selectedDate || 'today';
|
||||
},
|
||||
|
||||
fetchIfNeeded: function() {
|
||||
if (logbookStore.shouldFetch(this.selectedDate)) {
|
||||
this.isLoading = true;
|
||||
logbookActions.fetch(this.selectedDate);
|
||||
return true;
|
||||
isStaleChanged: function(newVal) {
|
||||
if (newVal) {
|
||||
// isLoading wouldn't update without debounce <_<
|
||||
this.debounce('fetch-logbook-entries', function() {
|
||||
logbookActions.fetchDate(this.selectedDate);
|
||||
}, 0);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
handleShowDatePicker: function() {
|
||||
uiActions.showDatePicker(function(selectedDate) {
|
||||
this.selectedDate = date_to_str(selectedDate);
|
||||
}.bind(this), this.selectedDate);
|
||||
uiActions.showDatePicker(
|
||||
logbookActions.changeCurrentDate,
|
||||
this.selectedDate);
|
||||
},
|
||||
|
||||
handleRefresh: function() {
|
||||
logbookActions.fetch(this.selectedDate);
|
||||
logbookActions.fetchDate(this.selectedDate);
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -41,12 +41,17 @@
|
|||
|
||||
<template>
|
||||
<partial-base narrow="[[narrow]]">
|
||||
<span header-title>{{headerTitle}}</span>
|
||||
<span header-title>[[computeHeaderTitle(filter)]]</span>
|
||||
|
||||
<span header-buttons>
|
||||
<paper-icon-button icon="refresh" class$="[[computeRefreshButtonClass(isFetching)]]"
|
||||
on-click="handleRefresh" hidden$="[[isStreaming]]"></paper-icon-button>
|
||||
<paper-icon-button icon="[[listenButtonIcon]]" hidden$={{!canListen}}
|
||||
<paper-icon-button
|
||||
icon="refresh"
|
||||
class$="[[computeRefreshButtonClass(isFetching)]]"
|
||||
on-click="handleRefresh" hidden$="[[isStreaming]]"
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon="[[computeListenButtonIcon(isListening)]]"
|
||||
hidden$='[[!canListen]]'
|
||||
on-click="handleListenClick"></paper-icon-button>
|
||||
</span>
|
||||
|
||||
|
@ -75,139 +80,93 @@
|
|||
|
||||
<script>
|
||||
(function(){
|
||||
var configGetters = window.hass.configGetters;
|
||||
var entityGetters = window.hass.entityGetters;
|
||||
var navigationGetters = window.hass.navigationGetters;
|
||||
var voiceGetters = window.hass.voiceGetters;
|
||||
var streamGetters = window.hass.streamGetters;
|
||||
var serviceGetters = window.hass.serviceGetters;
|
||||
var syncGetters = window.hass.syncGetters;
|
||||
|
||||
var syncActions = window.hass.syncActions;
|
||||
var voiceActions = window.hass.voiceActions;
|
||||
var stateStore = window.hass.stateStore;
|
||||
var uiConstants = window.hass.uiConstants;
|
||||
|
||||
var entityDomainFilters = window.hass.util.entityDomainFilters;
|
||||
|
||||
Polymer({
|
||||
is: 'partial-states',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
/**
|
||||
* Title to show in the header
|
||||
*/
|
||||
headerTitle: {
|
||||
type: String,
|
||||
value: 'States',
|
||||
},
|
||||
|
||||
/**
|
||||
* If header is to be shown in narrow mode.
|
||||
*/
|
||||
narrow: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
filter: {
|
||||
type: String,
|
||||
value: null,
|
||||
observer: 'filterChanged',
|
||||
},
|
||||
|
||||
voiceSupported: {
|
||||
type: Boolean,
|
||||
value: voiceActions.isSupported(),
|
||||
},
|
||||
|
||||
isFetching: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: syncGetters.isFetching,
|
||||
},
|
||||
|
||||
isStreaming: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: streamGetters.isStreamingEvents,
|
||||
},
|
||||
|
||||
canListen: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: [
|
||||
voiceGetters.isVoiceSupported,
|
||||
configGetters.isComponentLoaded('conversation'),
|
||||
function(isVoiceSupported, componentLoaded) {
|
||||
return isVoiceSupported && componentLoaded;
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
isListening: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: voiceGetters.isListening,
|
||||
},
|
||||
|
||||
isTransmitting: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: voiceGetters.isTransmitting,
|
||||
},
|
||||
|
||||
interimTranscript: {
|
||||
type: String,
|
||||
value: '',
|
||||
bindNuclear: voiceGetters.extraInterimTranscript,
|
||||
},
|
||||
|
||||
finalTranscript: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
|
||||
listenButtonIcon: {
|
||||
type: String,
|
||||
computed: 'computeListenButtonIcon(isListening)'
|
||||
bindNuclear: voiceGetters.finalTranscript,
|
||||
},
|
||||
|
||||
showListenInterface: {
|
||||
type: Boolean,
|
||||
computed: 'computeShowListenInterface(isListening,isTransmitting)'
|
||||
}
|
||||
},
|
||||
bindNuclear: [
|
||||
voiceGetters.isListening,
|
||||
voiceGetters.isTransmitting,
|
||||
function(isListening, isTransmitting) {
|
||||
return isListening || isTransmitting;
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
componentStoreChanged: function(componentStore) {
|
||||
this.canListen = this.voiceSupported &&
|
||||
componentStore.isLoaded('conversation');
|
||||
},
|
||||
|
||||
stateStoreChanged: function() {
|
||||
this.refreshStates();
|
||||
},
|
||||
|
||||
syncStoreChanged: function(syncStore) {
|
||||
this.isFetching = syncStore.isFetching;
|
||||
},
|
||||
|
||||
streamStoreChanged: function(streamStore) {
|
||||
this.isStreaming = streamStore.isStreaming;
|
||||
},
|
||||
|
||||
voiceStoreChanged: function(voiceStore) {
|
||||
this.isListening = voiceStore.isListening;
|
||||
this.isTransmitting = voiceStore.isTransmitting;
|
||||
this.finalTranscript = voiceStore.finalTranscript;
|
||||
this.interimTranscript = voiceStore.interimTranscript.slice(
|
||||
this.finalTranscript.length);
|
||||
},
|
||||
|
||||
filterChanged: function() {
|
||||
this.refreshStates();
|
||||
|
||||
this.headerTitle = uiConstants.STATE_FILTERS[this.filter] || 'States';
|
||||
},
|
||||
|
||||
refreshStates: function() {
|
||||
var states;
|
||||
|
||||
if (this.filter) {
|
||||
var filter = this.filter;
|
||||
states = stateStore.all.filter(function(state) {
|
||||
return state.domain === filter;
|
||||
});
|
||||
|
||||
} else {
|
||||
// all but the STATE_FILTER keys
|
||||
states = stateStore.all.filter(function(state) {
|
||||
return !(state.domain in uiConstants.STATE_FILTERS);
|
||||
});
|
||||
}
|
||||
|
||||
this.states = states.toArray().filter(
|
||||
function (el) {return !el.attributes.hidden;});
|
||||
states: {
|
||||
type: Array,
|
||||
bindNuclear: [
|
||||
navigationGetters.filteredStates,
|
||||
// are here so a change to services causes a re-render.
|
||||
// we need this to decide if we show toggles for states.
|
||||
serviceGetters.entityMap,
|
||||
function(states) { return states.toArray(); },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
handleRefresh: function() {
|
||||
|
@ -222,12 +181,12 @@
|
|||
}
|
||||
},
|
||||
|
||||
computeListenButtonIcon: function(isListening) {
|
||||
return isListening ? 'av:mic-off' : 'av:mic';
|
||||
computeHeaderTitle: function(filter) {
|
||||
return filter ? entityDomainFilters[filter] : 'States';
|
||||
},
|
||||
|
||||
computeShowListenInterface: function(isListening,isTransmitting) {
|
||||
return isListening || isTransmitting;
|
||||
computeListenButtonIcon: function(isListening) {
|
||||
return isListening ? 'av:mic-off' : 'av:mic';
|
||||
},
|
||||
|
||||
computeRefreshButtonClass: function(isFetching) {
|
||||
|
|
|
@ -14,33 +14,38 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var uiConstants = window.hass.uiConstants,
|
||||
dispatcher = window.hass.dispatcher;
|
||||
var moreInfoGetters = window.hass.moreInfoGetters;
|
||||
var uiActions = window.hass.uiActions;
|
||||
|
||||
Polymer({
|
||||
is: 'modal-manager',
|
||||
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
moreInfoEntityId: {
|
||||
type: String,
|
||||
observer: 'moreInfoEntityIdChanged',
|
||||
bindNuclear: moreInfoGetters.currentEntityId,
|
||||
},
|
||||
datePickerCallback: {
|
||||
type: Function,
|
||||
value: null,
|
||||
},
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
dispatcher.register(function(payload) {
|
||||
switch (payload.actionType) {
|
||||
case uiConstants.ACTION_SHOW_DIALOG_MORE_INFO:
|
||||
this.$.moreInfoDialog.show(payload.entityId);
|
||||
break;
|
||||
moreInfoEntityIdChanged: function(newVal) {
|
||||
if (newVal) {
|
||||
this.$.moreInfoDialog.show(newVal);
|
||||
}
|
||||
},
|
||||
|
||||
case uiConstants.ACTION_SHOW_DATE_PICKER:
|
||||
this.datePickerCallback = payload.dateSelectedCallback;
|
||||
this.$.date = payload.date;
|
||||
this.$.datePicker.toggle();
|
||||
break;
|
||||
}
|
||||
}.bind(this));
|
||||
ready: function() {
|
||||
uiActions.showDatePicker = function(dateSelectedCallback, startDate) {
|
||||
this.datePickerCallback = dateSelectedCallback;
|
||||
this.$.date = startDate;
|
||||
this.$.datePicker.toggle();
|
||||
}.bind(this);
|
||||
},
|
||||
|
||||
datePickerValueChanged: function(ev) {
|
||||
|
|
|
@ -15,33 +15,26 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var notificationGetters = window.hass.notificationGetters;
|
||||
|
||||
Polymer({
|
||||
is: 'notification-manager',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
text: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
|
||||
lastId: {
|
||||
type: Number,
|
||||
bindNuclear: notificationGetters.lastNotificationMessage,
|
||||
observer: 'showNotification',
|
||||
},
|
||||
},
|
||||
|
||||
notificationStoreChanged: function(notificationStore) {
|
||||
if (notificationStore.hasNewNotifications(this.lastId)) {
|
||||
var notification = notificationStore.lastNotification;
|
||||
|
||||
this.lastId = notification.id;
|
||||
this.text = notification.message;
|
||||
|
||||
showNotification: function(newText) {
|
||||
if (newText) {
|
||||
this.$.toast.show();
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
var authGetters = window.hass.authGetters;
|
||||
var streamGetters = window.hass.streamGetters;
|
||||
|
||||
Polymer({
|
||||
is: 'preferences-manager',
|
||||
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
authToken: {
|
||||
type: String,
|
||||
bindNuclear: authGetters.currentAuthToken,
|
||||
observer: 'updateStorage',
|
||||
},
|
||||
useStreaming: {
|
||||
type: String,
|
||||
bindNuclear: ,
|
||||
observer: 'updateStorage',
|
||||
},
|
||||
},
|
||||
|
||||
updateStorage: function() {
|
||||
if (!('localStorage' in window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var storage = localStorage;
|
||||
|
||||
Object.keys(this.properties).forEach(function(prop) {
|
||||
storage[prop] = this.prop;
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
|
@ -52,13 +52,14 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var streamGetters = window.hass.streamGetters;
|
||||
var syncActions = window.hass.syncActions;
|
||||
var serviceActions = window.hass.serviceActions;
|
||||
|
||||
Polymer({
|
||||
is: 'more-info-configurator',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
stateObj: {
|
||||
|
@ -72,7 +73,7 @@
|
|||
|
||||
isStreaming: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
bindNuclear: streamGetters.isStreamingEvents,
|
||||
},
|
||||
|
||||
isConfigurable: {
|
||||
|
@ -99,10 +100,6 @@
|
|||
return stateObj.attributes.submit_caption || 'Set configuration';
|
||||
},
|
||||
|
||||
streamStoreChanged: function(streamStore) {
|
||||
this.isStreaming = streamStore.isStreaming;
|
||||
},
|
||||
|
||||
submitClicked: function() {
|
||||
this.isConfiguring = true;
|
||||
|
||||
|
|
|
@ -23,28 +23,36 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var stateStore = window.hass.stateStore;
|
||||
var entityGetters = window.hass.entityGetters;
|
||||
var moreInfoGetters = window.hass.moreInfoGetters;
|
||||
|
||||
Polymer({
|
||||
is: 'more-info-group',
|
||||
|
||||
behaviors: [StoreListenerBehavior],
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
stateObj: {
|
||||
type: Object,
|
||||
observer: 'updateStates',
|
||||
},
|
||||
|
||||
states: {
|
||||
type: Array,
|
||||
value: [],
|
||||
bindNuclear: [
|
||||
moreInfoGetters.currentEntity,
|
||||
entityGetters.entityMap,
|
||||
function(currentEntity, entities) {
|
||||
// weird bug??
|
||||
if (!currentEntity) {
|
||||
return;
|
||||
}
|
||||
return currentEntity.attributes.entity_id.map(
|
||||
entities.get.bind(entities));
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
stateStoreChanged: function() {
|
||||
this.updateStates();
|
||||
},
|
||||
|
||||
updateStates: function() {
|
||||
this.states = this.stateObj && this.stateObj.attributes.entity_id ?
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
<script>
|
||||
(function() {
|
||||
var constants = window.hass.constants;
|
||||
var temperatureUnits = window.hass.util.temperatureUnits;
|
||||
var serviceActions = window.hass.serviceActions;
|
||||
var uiUtil = window.hass.uiUtil;
|
||||
var ATTRIBUTE_CLASSES = ['away_mode'];
|
||||
|
@ -76,7 +76,8 @@
|
|||
this.targetTemperatureSliderValue = this.stateObj.state;
|
||||
this.awayToggleChecked = this.stateObj.attributes.away_mode == 'on';
|
||||
|
||||
if (this.stateObj.attributes.unit_of_measurement === constants.UNIT_TEMP_F) {
|
||||
if (this.stateObj.attributes.unit_of_measurement ===
|
||||
temperatureUnits.UNIT_TEMP_F) {
|
||||
this.tempMin = 45;
|
||||
this.tempMax = 95;
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<script>
|
||||
(function() {
|
||||
var reactor = window.hass.reactor;
|
||||
var authGetters = window.hass.authGetters;
|
||||
var streamGetters = window.hass.streamGetters;
|
||||
|
||||
var storage = 'localStorage' in window ? localStorage : {};
|
||||
|
||||
var observe = {
|
||||
authToken: {
|
||||
bindNuclear: [
|
||||
authGetters.currentAuthToken,
|
||||
authGetters.rememberAuth,
|
||||
function(authToken, rememberAuth) {
|
||||
return rememberAuth ? authToken : null;
|
||||
},
|
||||
],
|
||||
defaultValue: null,
|
||||
},
|
||||
useStreaming: {
|
||||
bindNuclear: streamGetters.useStreaming,
|
||||
defaultValue: true,
|
||||
},
|
||||
};
|
||||
|
||||
var uiPreferences = {};
|
||||
|
||||
Object.keys(observe).forEach(function(prop) {
|
||||
if (!(prop in storage)) {
|
||||
storage[prop] = observe[prop].defaultValue;
|
||||
}
|
||||
|
||||
Object.defineProperty(uiPreferences, prop, {
|
||||
get: function() { return JSON.parse(storage[prop]); }
|
||||
});
|
||||
});
|
||||
|
||||
uiPreferences.startSync = function startSync() {
|
||||
Object.keys(observe).forEach(function(prop) {
|
||||
var getter = observe[prop].bindNuclear;
|
||||
var valueChanged = function valueChanged(value) {
|
||||
storage[prop] = JSON.stringify(value);
|
||||
};
|
||||
reactor.observe(getter, valueChanged);
|
||||
valueChanged(reactor.evaluate(getter));
|
||||
});
|
||||
};
|
||||
|
||||
window.hass.uiPreferences = uiPreferences;
|
||||
})();
|
||||
</script>
|
|
@ -1,4 +1,5 @@
|
|||
<script src="../home-assistant-js/dist/homeassistant.min.js"></script>
|
||||
<link rel="import" href="./ha-preferences.html">
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
|
@ -10,63 +11,16 @@
|
|||
'sensor',
|
||||
];
|
||||
|
||||
// Add some frontend specific helpers to the models
|
||||
Object.defineProperties(window.hass.stateModel.prototype, {
|
||||
// how to render the card for this state
|
||||
cardType: {
|
||||
get: function() {
|
||||
console.warn('Deprecated method. Please use hass.uiUtil.stateCardType');
|
||||
return window.hass.uiUtil.stateCardType(this);
|
||||
}
|
||||
},
|
||||
|
||||
// how to render the more info of this state
|
||||
moreInfoType: {
|
||||
get: function() {
|
||||
console.warn('Deprecated method. Please use hass.uiUtil.stateMoreInfoType');
|
||||
return window.hass.uiUtil.stateMoreInfoType(this);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var dispatcher = window.hass.dispatcher,
|
||||
constants = window.hass.constants,
|
||||
preferenceStore = window.hass.preferenceStore,
|
||||
authActions = window.hass.authActions;
|
||||
|
||||
window.hass.uiConstants = {
|
||||
ACTION_SHOW_DIALOG_MORE_INFO: 'ACTION_SHOW_DIALOG_MORE_INFO',
|
||||
ACTION_SHOW_DATE_PICKER: 'ACTION_SHOW_DATE_PICKER',
|
||||
|
||||
STATE_FILTERS: {
|
||||
'group': 'Groups',
|
||||
'script': 'Scripts',
|
||||
'scene': 'Scenes',
|
||||
},
|
||||
};
|
||||
var reactor = window.hass.reactor;
|
||||
var serviceGetters = window.hass.serviceGetters;
|
||||
var authActions = window.hass.authActions;
|
||||
var uiPreferences = window.hass.uiPreferences;
|
||||
|
||||
window.hass.uiActions = {
|
||||
showMoreInfoDialog: function(entityId) {
|
||||
dispatcher.dispatch({
|
||||
actionType: window.hass.uiConstants.ACTION_SHOW_DIALOG_MORE_INFO,
|
||||
entityId: entityId,
|
||||
});
|
||||
},
|
||||
|
||||
showDatePicker: function(dateSelectedCallback, startDate) {
|
||||
startDate = startDate || null;
|
||||
|
||||
dispatcher.dispatch({
|
||||
actionType: window.hass.uiConstants.ACTION_SHOW_DATE_PICKER,
|
||||
dateSelectedCallback: dateSelectedCallback,
|
||||
startDate: startDate,
|
||||
});
|
||||
},
|
||||
|
||||
validateAuth: function(authToken, rememberLogin) {
|
||||
validateAuth: function(authToken, rememberAuth) {
|
||||
authActions.validate(authToken, {
|
||||
useStreaming: preferenceStore.useStreaming,
|
||||
rememberLogin: rememberLogin,
|
||||
useStreaming: uiPreferences.useStreaming,
|
||||
rememberAuth: rememberAuth,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@ -76,7 +30,7 @@
|
|||
stateCardType: function(state) {
|
||||
if(DOMAINS_WITH_CARD.indexOf(state.domain) !== -1) {
|
||||
return state.domain;
|
||||
} else if(state.canToggle) {
|
||||
} else if(reactor.evaluate(serviceGetters.canToggle(state.entityId))) {
|
||||
return "toggle";
|
||||
} else {
|
||||
return "display";
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<!--
|
||||
Wrapping JS in an HTML file will prevent it from being loaded twice.
|
||||
-->
|
||||
|
||||
<script src="../bower_components/lodash/lodash.min.js"></script>
|
|
@ -1,21 +1,42 @@
|
|||
<script>
|
||||
|
||||
(function() {
|
||||
var NuclearObserver = function NuclearObserver(reactor) {
|
||||
return {
|
||||
|
||||
var StoreListenerMixIn = window.hass.storeListenerMixIn;
|
||||
attached: function() {
|
||||
var component = this;
|
||||
this.__unwatchFns = Object.keys(component.properties).reduce(
|
||||
function(unwatchFns, key) {
|
||||
if (!('bindNuclear' in component.properties[key])) {
|
||||
return unwatchFns;
|
||||
}
|
||||
var getter = component.properties[key].bindNuclear;
|
||||
|
||||
window.StoreListenerBehavior = {
|
||||
if (!getter) {
|
||||
throw 'Undefined getter specified for key ' + key;
|
||||
}
|
||||
|
||||
attached: function() {
|
||||
StoreListenerMixIn.listenToStores(true, this);
|
||||
},
|
||||
// console.log(key, getter);
|
||||
|
||||
detached: function() {
|
||||
StoreListenerMixIn.stopListeningToStores(this);
|
||||
},
|
||||
component[key] = reactor.evaluate(getter);
|
||||
|
||||
return unwatchFns.concat(reactor.observe(getter, function(val) {
|
||||
// console.log('New value for', key, val);
|
||||
component[key] = val;
|
||||
}));
|
||||
}, []);
|
||||
},
|
||||
|
||||
detached: function() {
|
||||
while (this.__unwatchFns.length) {
|
||||
this.__unwatchFns.shift()();
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
window.nuclearObserver = NuclearObserver(window.hass.reactor);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue