Skip to content

Commit 16ca9e7

Browse files
committed
v0.3.111.20210130 - BETA M3 - Numerous bug fixes, performance improvements for HTTP, *CLEAR index to reset list variables, reset access token
2 parents 582b602 + 72534ca commit 16ca9e7

File tree

16 files changed

+306
-158
lines changed

16 files changed

+306
-158
lines changed

.gitignore

-5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@
33
######################
44
*.sh
55

6-
######################
7-
# Visor #
8-
######################
9-
visor*
10-
dist/visor*
116
dashboard/fa*
127
dashboard/mp3*
138
dashboard/js/components/fa*

dashboard/html/modules/dashboard.module.html

+6-6
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@
182182
<table class="table" ng-if="(category.t == 'd') || (category.t == 'dt') || (category.t == 'dm') || (category.t == 'dl')">
183183
<tbody>
184184
<tr ng-repeat="piston in category.p" active="true" ng-if="piston.meta && piston.meta.a" data-toggle="tooltip" title="{{piston.meta.t ? 'Executed ' + timeSince(piston.meta.t) : 'Never executed'}}">
185-
<td ng-click="openPiston(piston.id);"><span><svg star class="sprite-icon fa-xs" symbol="circle" ng-style="{opacity: piston.opacity}"></svg>{{piston.name}}<span state ng-bind-html="renderString(piston.meta.s.new)"></span><!--<span ng-if="piston.meta.s && piston.meta.s.new" state="{{piston.meta.s.new}}">{{piston.meta.s.new}}</span>--></span></td>
185+
<td ng-click="openPiston(piston.id);"><span><svg star class="sprite-icon fa-xs" symbol="circle" ng-style="{opacity: piston.opacity}"></svg>{{piston.name}}<span state ng-bind-html="piston.meta.s.new | renderString"></span><!--<span ng-if="piston.meta.s && piston.meta.s.new" state="{{piston.meta.s.new}}">{{piston.meta.s.new}}</span>--></span></td>
186186
<td ng-click="openPiston(piston.id);" dur class="col-md-1 text-right">{{piston.meta.n ? timeCounter(piston.meta.n) : ''}}</td>
187187
<td ng-if="!mobile" opt><svg class="sprite-icon" symbol="ellipsis-v"></svg><actions class="animated"><action ng-click="pausePiston(piston.id);" data-toggle="tooltip" title="Pause piston">Pause</action><action ng-click="testPiston(piston.id);" data-toggle="tooltip" title="Test piston">Test</action><action ng-click="openPiston(piston.id);" data-toggle="tooltip" title="View/Edit piston">View</action></actions></td>
188188

@@ -191,10 +191,10 @@
191191
</table>
192192
<ptiles ng-if="(category.t == 't') || (category.t == 'm') || (category.t == 'l') || (category.t == 'dt') || (category.t == 'dm') || (category.t == 'dl') || (category.t == 'td') || (category.t == 'md') || (category.t == 'ld')">
193193
<ptilegroup ng-repeat="piston in category.p" ng-if="piston.meta && piston.meta.a">
194-
<ptile ng-repeat="index in range(16) track by $index" class="{{category.t.indexOf('l') >= 0 ? 'large' : (category.t.indexOf('m') >= 0 ? 'medium' : '')}}" ng-if="piston.meta.s['i' + ($index + 1)] || piston.meta.s['t' + ($index + 1)]" tile-meta="piston.meta.s" tile-index="$index" ng-click="clickPistonTile($event, piston, ($index + 1));" data-toggle="tooltip" title="{{piston.meta.s['p' + ($index +1)] ? renderString(piston.meta.s['p' + ($index + 1)]) : renderString(piston.meta.s.new)}}" ng-style="{color: piston.meta.s['c' + ($index + 1)], backgroundColor: piston.meta.s['b' + ($index + 1)]}" class="{{piston.meta.s['f' + ($index + 1)] ? 'blink' : ''}}" type="{{meta.type ? meta.type : ''}}" ng-attr-wide="{{!!meta && !!meta.options && (meta.options.wide == '1') ? '' : undefined}}">
195-
<div ng-if-start="!meta.type" title data-fittext data-fittext-max="{{category.t.indexOf('l') >= 0 ? 24 : (category.t.indexOf('m') >= 0 ? 18 : 12)}}" ng-model="piston.meta.s" ng-bind-html="piston.meta.s['i' + ($index + 1)] ? renderString(piston.meta.s['i' + ($index + 1)]) : '--'"></div>
196-
<div data-fittext data-fittext-max="{{category.t.indexOf('l') >= 0 ? 72 : (category.t.indexOf('m') >= 0 ? 54 : 36)}}" ng-model="piston.meta.s" ng-bind-html="piston.meta.s['t' + ($index + 1)] ? renderString(piston.meta.s['t' + ($index + 1)]) : '--'"></div>
197-
<div ng-if-end title data-fittext data-fittext-max="{{category.t.indexOf('l') >= 0 ? 24 : (category.t.indexOf('m') >= 0 ? 18 : 12)}}" ng-model="piston.meta.s" ng-bind-html="piston.meta.s['o' + ($index + 1)] ? renderString(piston.meta.s['o' + ($index + 1)]) : (piston.meta.n ? timeCounter(piston.meta.n) : ' ')"></div>
194+
<ptile ng-repeat="index in range(16) track by $index" class="{{category.t.indexOf('l') >= 0 ? 'large' : (category.t.indexOf('m') >= 0 ? 'medium' : '')}}" ng-if="piston.meta.s['i' + ($index + 1)] || piston.meta.s['t' + ($index + 1)]" tile-meta="piston.meta.s" tile-index="$index" ng-click="clickPistonTile($event, piston, ($index + 1));" data-toggle="tooltip" title="{{(piston.meta.s['p' + ($index +1)] ? piston.meta.s['p' + ($index + 1)] : piston.meta.s.new) | renderString}}" ng-style="{color: piston.meta.s['c' + ($index + 1)], backgroundColor: piston.meta.s['b' + ($index + 1)]}" class="{{piston.meta.s['f' + ($index + 1)] ? 'blink' : ''}}" type="{{meta.type ? meta.type : ''}}" ng-attr-wide="{{!!meta && !!meta.options && (meta.options.wide == '1') ? '' : undefined}}">
195+
<div ng-if-start="!meta.type" title data-fittext data-fittext-max="{{category.t.indexOf('l') >= 0 ? 24 : (category.t.indexOf('m') >= 0 ? 18 : 12)}}" ng-model="piston.meta.s" ng-bind-html="piston.meta.s['i' + ($index + 1)] ? (piston.meta.s['i' + ($index + 1)] | renderString) : '--'"></div>
196+
<div data-fittext data-fittext-max="{{category.t.indexOf('l') >= 0 ? 72 : (category.t.indexOf('m') >= 0 ? 54 : 36)}}" ng-model="piston.meta.s" ng-bind-html="piston.meta.s['t' + ($index + 1)] ? (piston.meta.s['t' + ($index + 1)] | renderString) : '--'"></div>
197+
<div ng-if-end title data-fittext data-fittext-max="{{category.t.indexOf('l') >= 0 ? 24 : (category.t.indexOf('m') >= 0 ? 18 : 12)}}" ng-model="piston.meta.s" ng-bind-html="piston.meta.s['o' + ($index + 1)] ? (piston.meta.s['o' + ($index + 1)] | renderString) : (piston.meta.n ? timeCounter(piston.meta.n) : ' ')"></div>
198198
<div ng-if="meta.type == 'gauge'" google-chart chart="getGaugeChart(piston, $index, meta)"></div>
199199
<video ng-if="(meta.type == 'video') && !!meta.options && !!meta.options.src" class="{{meta.className}}" ng-attr-controls="{{meta.options.controls == '0' ? undefined : ''}}" ng-attr-autoplay="{{meta.options.autoplay == '1' ? '' : undefined}}" ng-attr-loop="{{meta.options.loop == '1' ? '' : undefined}}" ng-attr-muted="{{meta.options.muted == '1' ? '' : undefined}}">
200200
<source ng-src="{{meta.options.src}}" />
@@ -206,7 +206,7 @@
206206
<table class="table" ng-if="(category.t == 'td') || (category.t == 'tm') || (category.t == 'tl')">
207207
<tbody>
208208
<tr ng-repeat="piston in category.p" active="true" ng-if="piston.meta && piston.meta.a" data-toggle="tooltip" title="{{piston.meta.t ? 'Executed ' + timeSince(piston.meta.t) : 'Never executed'}}">
209-
<td ng-click="openPiston(piston.id);"><span><svg star class="sprite-icon fa-xs" symbol="circle" ng-style="{opacity: piston.opacity}"></svg>{{piston.name}}<span state ng-bind-html="renderString(piston.meta.s.new)"></span><!--<span ng-if="piston.meta.s && piston.meta.s.new" state="{{piston.meta.s.new}}">{{piston.meta.s.new}}</span>--></span></td>
209+
<td ng-click="openPiston(piston.id);"><span><svg star class="sprite-icon fa-xs" symbol="circle" ng-style="{opacity: piston.opacity}"></svg>{{piston.name}}<span state ng-bind-html="piston.meta.s.new | renderString"></span><!--<span ng-if="piston.meta.s && piston.meta.s.new" state="{{piston.meta.s.new}}">{{piston.meta.s.new}}</span>--></span></td>
210210
<td ng-click="openPiston(piston.id);" dur class="col-md-1 text-right">{{piston.meta.n ? timeCounter(piston.meta.n) : ''}}</td>
211211
<td ng-if="!mobile" opt><svg class="sprite-icon" symbol="ellipsis-v"></svg><actions class="animated"><action ng-click="pausePiston(piston.id);" data-toggle="tooltip" title="Pause piston">Pause</action><action ng-click="testPiston(piston.id);" data-toggle="tooltip" title="Test piston">Test</action><action ng-click="openPiston(piston.id);" data-toggle="tooltip" title="View/Edit piston">View</action></actions></td>
212212

dashboard/html/modules/piston.module.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ <h2>Status</h2>
160160
<div class="col-md-4">
161161
<div class="columnCards">
162162
<h2>Quick Facts</h2>
163-
<p>Piston state: <span ng-bind-html="renderString(state.new)"></span></p>
163+
<p>Piston state: <span ng-bind-html="state.new | renderString"></span></p>
164164
<p>Last executed: {{lastExecuted ? utcToString(lastExecuted) : 'never'}}</p>
165165
<p>Next scheduled: {{nextSchedule ? utcToString(nextSchedule) : 'never'}}</p>
166166
<p>Subscriptions: {{subscriptions.events ? subscriptions.events : 'no'}} event{{subscriptions.events != 1 ? 's' : ''}}, {{subscriptions.controls ? subscriptions.controls : 'no'}} control{{subscriptions.controls != 1 ? 's' : ''}}</p>
@@ -231,7 +231,7 @@ <h3>
231231
<tr ng-repeat="log in logs" log="{{log.c}}">
232232
<td ng-if="log.t" colspan="2" class="hdr">{{utcToString(log.t) + ' +' + (log.t % 1000) + 'ms'}}</td>
233233
<td ng-if-start="log.o != null">+{{log.o}}ms</td>
234-
<td ng-if-end>{{log.p}}<span ng-bind-html="renderString(log.m)"></span></td>
234+
<td ng-if-end>{{log.p}}<span ng-bind-html="log.m | renderString"></span></td>
235235
</tr>
236236
</tbody>
237237
</table>

dashboard/index.html

+1-2
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,8 @@
4848
<script type="text/javascript" src="js/modules/dashboard.module.js" charset="utf-8"></script><!--dev-->
4949
<script type="text/javascript" src="js/modules/piston.module.js" charset="utf-8"></script><!--dev-->
5050
<script type="text/javascript" src="js/modules/fuel.module.js" charset="utf-8"></script><!--dev-->
51-
<script type="text/javascript" src="js/modules/visors.module.js" charset="utf-8"></script><!--dev-->
5251
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
53-
<script defer src="https://kit.fontawesome.com/3f44ec9dc7.js" crossorigin="anonymous" onerror="loadFontAwesomeFallback()"></script>
52+
<script defer src="https://kit.fontawesome.com/a00a53f405.js" crossorigin="anonymous" onerror="loadFontAwesomeFallback()"></script>
5453
<script defer src="https://pro.fontawesome.com/releases/v5.11.1/js/v4-shims.js" crossorigin="anonymous"></script>
5554
</head>
5655
<body>

dashboard/js/app.js

+83-39
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,21 @@ app.directive('ngWheel', ['$parse', function($parse) {
5151

5252

5353
app.directive('refresh',['$interval', function($interval){
54-
var refreshTime_=0;
55-
var onRefresh_=null;
56-
var iv_=null;
5754
return {
5855
restrict:'A',
5956
link:function(scope,elem,attrs){
57+
var refreshTime_=0;
58+
var onRefresh_=null;
59+
var iv_=null;
6060
elem.on('$destroy', function(){
6161
if (iv_!=null) $interval.cancel(iv_);
6262
});
6363
if(angular.isDefined(attrs.refresh) && !isNaN(parseInt(attrs.refresh)))
6464
refreshTime_=attrs.refresh;
6565
if(angular.isDefined(attrs.onRefresh) && angular.isFunction(scope[attrs.onRefresh])){
6666
onRefresh_=scope[attrs.onRefresh];
67-
iv_=$interval(function() { onRefresh_(elem[0]) },refreshTime_ * 1000);
67+
if(refreshTime_>0)
68+
iv_=$interval(function() { onRefresh_(elem[0]); console.log('refresh', elem[0]) },refreshTime_ * 1000);
6869
attrs.$observe('refresh',function(new_iv){
6970
if(!angular.equals(new_iv,refreshTime_)){
7071
if(iv_!=null) $interval.cancel(iv_);
@@ -483,11 +484,6 @@ var config = app.config(['$routeProvider', '$locationProvider', '$sceDelegatePro
483484
controller: 'fuel',
484485
css: cdn + theme + 'css/modules/fuel' + ext + '?v=' + version()
485486
}).
486-
when('/visors', {
487-
templateUrl: cdn + theme + 'html/modules/visors.module.html?v=' + version(),
488-
controller: 'visors',
489-
css: cdn + theme + 'css/modules/visors' + ext + '?v=' + version()
490-
}).
491487
when('/init/:instId1/:instId2', {
492488
redirectTo: function(params) {
493489
app.initialInstanceUri = atou(params.instId1 + '/' + params.instId2);
@@ -627,15 +623,19 @@ config.factory('dataService', ['$http', '$location', '$rootScope', '$window', '$
627623
return si;
628624
}
629625

630-
var setInstance = function(inst) {
631-
var initial = (!instance);
632-
if (!instance || (instance.id != inst.id)) instance = inst;
626+
var setSI = function(inst) {
633627
//preserve the token, unless a new one is given
634-
var si = store[instance.id];
628+
var si = store[inst.id];
635629
if (!si) si = {};
636630
si.token = inst.token ? inst.token : si.token;
637631
si.uri = inst.uri ? inst.uri.replace(':443', '') : si.uri;
638-
store[instance.id] = fixSI(si);
632+
store[inst.id] = fixSI(si);
633+
}
634+
635+
var setInstance = function(inst) {
636+
var initial = (!instance);
637+
if (!instance || (instance.id != inst.id)) instance = inst;
638+
setSI(inst);
639639
delete(instance.token);
640640
delete(instance.uri);
641641
if (inst.contacts) {
@@ -680,10 +680,18 @@ config.factory('dataService', ['$http', '$location', '$rootScope', '$window', '$
680680
writeObject('instances', instances);
681681
writeObject('store', store);
682682
writeObject('instance', instance.id, _dk);
683-
if ((instance.coreVersion) && (version() != instance.coreVersion) && !nagged) {
683+
var coreVersionComparison = compareVersions(version(), instance.coreVersion);
684+
if ((instance.coreVersion) && coreVersionComparison !== 0 && !nagged) {
684685
nagged = true;
685-
if (version() > instance.coreVersion) {
686-
status('A newer SmartApp version (' + version() + ') is available, please update and publish all the webCoRE SmartApps in the SmartThings IDE.', true);
686+
if (compareVersions(minCoreVersion, instance.coreVersion) > 0) {
687+
status('A newer SmartApp version (' + version() + ') is available.<br><strong>Please update and publish all the webCoRE SmartApps in the SmartThings IDE.</strong>', true);
688+
} else if (coreVersionComparison > 0) {
689+
localforage.getItem('lastOptionalVersion').then(function(lastOptionalVersion) {
690+
if (lastOptionalVersion !== version()) {
691+
status('A newer SmartApp version (' + version() + ') is available.<br>This is an <strong>optional</strong> update; consider updating the webCoRE SmartApps in the SmartThings IDE.', true);
692+
localforage.setItem('lastOptionalVersion', version());
693+
}
694+
});
687695
} else {
688696
status('A newer UI version (' + instance.coreVersion + ') is available, please hard reload this web page to get the newest version.', true);
689697
}
@@ -935,6 +943,7 @@ config.factory('dataService', ['$http', '$location', '$rootScope', '$window', '$
935943
data.endpoint = si.uri;
936944
data.accessToken = si.accessToken;
937945
if (data.instance && !data.instance.devices && data.instance.deviceVersion !== deviceVersion) {
946+
setSI(data.instance);
938947
return dataService.getDevices(data.instance).then(function(devices) {
939948
data.instance.devices = devices;
940949
return data;
@@ -1003,7 +1012,7 @@ config.factory('dataService', ['$http', '$location', '$rootScope', '$window', '$
10031012
});
10041013
}
10051014

1006-
dataService.getPiston = function (pistonId) {
1015+
dataService.getPiston = function (pistonId, shouldSetInstance) {
10071016
var inst = dataService.getPistonInstance(pistonId);
10081017
if (!inst) { inst = dataService.getInstance() };
10091018
si = store && inst ? store[inst.id] : null;
@@ -1014,18 +1023,19 @@ config.factory('dataService', ['$http', '$location', '$rootScope', '$window', '$
10141023
// Base response is no longer included with the piston
10151024
.then(function(response) {
10161025
var data = response.data;
1017-
if (!data.instance) {
1018-
return dataService.loadInstance(inst).then(function(instData) {
1019-
const mergedData = Object.assign({}, data, instData);
1020-
return Object.assign({}, response, { data: mergedData });
1021-
});
1022-
}
1023-
1024-
if (data.location) {
1025-
setLocation(data.location);
1026-
}
1027-
if (data.instance) {
1028-
data.instance = setInstance(data.instance);
1026+
if (shouldSetInstance) {
1027+
if (data.location) {
1028+
setLocation(data.location);
1029+
}
1030+
data.endpoint = si.uri;
1031+
if (data.instance) {
1032+
data.instance = setInstance(data.instance);
1033+
} else {
1034+
return dataService.loadInstance(inst).then(function(instData) {
1035+
const mergedData = Object.assign({}, data, instData);
1036+
return Object.assign({}, response, { data: mergedData });
1037+
});
1038+
}
10291039
}
10301040
return response;
10311041
})
@@ -1810,17 +1820,17 @@ function fixTime(timestamp) {
18101820
return timestamp;
18111821
}
18121822

1813-
function utcToString(timestamp) {
1823+
var utcToString = nanomemoize(function utcToString(timestamp) {
18141824
return (new Date(fixTime(timestamp))).toLocaleString();
1815-
}
1825+
});
18161826

1817-
function utcToTimeString(timestamp) {
1827+
var utcToTimeString = nanomemoize(function utcToTimeString(timestamp) {
18181828
return (new Date(fixTime(timestamp))).toLocaleTimeString();
1819-
}
1829+
});
18201830

1821-
function utcToDateString(timestamp) {
1831+
var utcToDateString = nanomemoize(function utcToDateString(timestamp) {
18221832
return (new Date(fixTime(timestamp))).toLocaleDateString();
1823-
}
1833+
});
18241834

18251835
function timeSince(time){
18261836
if (!time) return "never";
@@ -1913,7 +1923,10 @@ function adjustTimeOffset(time) {
19131923

19141924

19151925

1916-
function renderString($sce, value) {
1926+
app.filter('renderString', ['$sce', function($sce) {
1927+
return renderString.bind(null, $sce);
1928+
}]);
1929+
var renderString = nanomemoize(function renderString($sce, value) {
19171930
var i = 0;
19181931
if (!value) return '';
19191932
var meta = {type: null, options: {}};
@@ -2055,7 +2068,7 @@ function renderString($sce, value) {
20552068
var result = $sce.trustAsHtml(meta.html);
20562069
result.meta = meta;
20572070
return result;
2058-
};
2071+
});
20592072

20602073
var wuIconForTwcCode = {
20612074
0: 'tstorms', // Tornado
@@ -2221,6 +2234,35 @@ function atou(str) {
22212234
return decodeURIComponent(escape(window.atob(str)));
22222235
}
22232236

2237+
// Split version parts for numeric and lexical comparison (e.g. v0.9.1ff < v0.10.1ff)
2238+
function comparableVersion(version) {
2239+
var parts = version.split('.');
2240+
return [
2241+
// Numeric major version, without v prefix
2242+
+parts[0].substr(1),
2243+
// Numeric minor version
2244+
+parts[1],
2245+
// Hex build number remains a string
2246+
parts[2],
2247+
];
2248+
}
2249+
2250+
// Compare webCoRE version number format for sorting from oldest to newest
2251+
function compareVersions(a, b) {
2252+
var aParts = comparableVersion(a);
2253+
var bParts = comparableVersion(b);
2254+
2255+
for (var i = 0; i < aParts.length; i++) {
2256+
if (aParts[i] < bParts[i]) {
2257+
return -1;
2258+
}
2259+
if (aParts[i] > bParts[i]) {
2260+
return 1;
2261+
}
2262+
}
2263+
return 0;
2264+
}
2265+
22242266
//document.documentElement.addEventListener('touchstart', function (event) {
22252267
// if (event.touches.length > 1) {
22262268
// event.preventDefault();
@@ -2308,4 +2350,6 @@ if (!String.prototype.endsWith) {
23082350
};
23092351
}
23102352

2311-
version = function() { return 'v0.3.110.20191009'; };
2353+
// Minimum version to display as an optional upgrade
2354+
minCoreVersion = 'v0.3.110.20191009';
2355+
version = function() { return 'v0.3.111.20210130'; };

0 commit comments

Comments
 (0)