Skip to content

Commit

Permalink
Reload web base when addon change
Browse files Browse the repository at this point in the history
  • Loading branch information
javalikescript committed Dec 30, 2024
1 parent a3b002e commit 4ec48ad
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 86 deletions.
32 changes: 19 additions & 13 deletions extensions/web-base/web-base.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ local function onWebSocketClose(webSocket)
List.removeFirst(websockets, webSocket)
end

local function webSocketBroadcast(data)
logger:fine('WebSocket broadcast')
local message = json.encode(data)
for _, websocket in ipairs(websockets) do
if not websocket.lhaEvent or websocket.lhaEvent == data.event then
websocket:sendTextMessage(message)
end
end
end

local batchDataChange = true
local dataChangeEvent = nil

Expand All @@ -82,19 +92,16 @@ local function onDataChange(value, previousValue, path)
if batchDataChange then
if not dataChangeEvent then
event:setTimeout(function()
local message = json.encode(dataChangeEvent)
webSocketBroadcast(dataChangeEvent)
dataChangeEvent = nil
for _, websocket in ipairs(websockets) do
websocket:sendTextMessage(message)
end
end)
dataChangeEvent = {event = 'data-change'}
end
tables.setPath(dataChangeEvent, path, value)
else
local thingId, propertyName = string.match(path, '^data/([^/]+)/([^/]+)$')
if thingId then
local message = json.encode({
webSocketBroadcast({
event = 'data-change',
data = {
[thingId] = {
Expand All @@ -105,9 +112,6 @@ local function onDataChange(value, previousValue, path)
}
}
})
for _, websocket in ipairs(websockets) do
websocket:sendTextMessage(message)
end
end
end
end
Expand All @@ -117,11 +121,13 @@ local addons = {}
function extension:registerAddon(id, addon)
addons[id] = addon
logger:info('Web base add-on "%s" registered', id)
webSocketBroadcast({event = 'addon-change'})
end

function extension:unregisterAddon(name)
addons[name] = nil
logger:info('Web base add-on "%s" unregistered', name)
webSocketBroadcast({event = 'addon-change'})
end

function extension:registerAddonExtension(ext, script)
Expand Down Expand Up @@ -172,11 +178,8 @@ extension:subscribeEvent('startup', function()
else
if not bufferMessages then
event:setTimeout(function()
local content = json.encode(bufferMessages)
webSocketBroadcast(bufferMessages)
bufferMessages = nil
for _, websocket in ipairs(websockets) do
websocket:sendTextMessage(content)
end
end)
bufferMessages = {event = 'logs', logs = {}}
end
Expand Down Expand Up @@ -241,4 +244,7 @@ extension:subscribeEvent('startup', function()
logger:info('WebSocket available on /ws/')
end)

extension:subscribeEvent('shutdown', cleanup)
extension:subscribeEvent('shutdown', function()
webSocketBroadcast({event = 'shutdown'})
cleanup()
end)
173 changes: 100 additions & 73 deletions extensions/web-base/www/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,66 @@ var unitAlias = {
"watt": "W"
};

function callVueFromPage(page, name) {
var parent = page.$parent;
if (parent) {
var fn = parent[name];
if (typeof fn === 'function') {
var args = Array.prototype.slice.call(arguments, 2);
return fn.apply(parent, args);
}
}
}

function getPageFromVue(vue) {
if (vue && vue.$children && (vue.$children.length > 0)) {
var page = vue.$children[0];
if (page.id && page.title) {
return page;
}
}
}

/************************************************************
* Toaster
************************************************************/
var toaster = new Vue({
el: '#toaster',
data: {
message: '',
show: false
},
methods: {
toast: function(message, duration) {
console.log('toast("' + message + '", ' + duration + ')');
if (this.show) {
this.message += '\n' + message;
} else {
this.message = message;
this.show = true;
var self = this;
setTimeout(function () {
self.show = false;
}, duration || 3000)
}
}
}
});

function assertIsOk(response) {
if (response.ok) {
return response;
}
var message;
if (response.status === 403) {
message = 'Sorry you are not authorized';
} else {
message = 'Failed due to ' + response.statusText;
}
toaster.toast(message);
return Promise.reject(message);
}

/************************************************************
* Main application
************************************************************/
Expand Down Expand Up @@ -89,25 +149,17 @@ var app = new Vue({
getPage: function(id) {
return this.pages[id];
},
emitPage: function(id) {
var page = this.pages[id];
var emitArgs = Array.prototype.slice.call(arguments, 1);
if (page.$parent) {
page = page.$parent;
}
page.$emit.apply(page, emitArgs);
return this;
isActivePage: function(vue) {
return this.page && this.pages[this.page] === getPageFromVue(vue);
},
callPage: function(id, name) {
var page = this.pages[id];
var callArgs = Array.prototype.slice.call(arguments, 2);
if (page.$parent) {
page = page.$parent;
}
var fn = page[name];
if (typeof fn === 'function') {
fn.apply(page, callArgs);
if (page) {
return callVueFromPage(page, name);
}
},
emitPage: function(id) {
this.callPage(id, '$emit');
return this;
},
showBack: function() {
Expand Down Expand Up @@ -148,6 +200,24 @@ var app = new Vue({
this.callPage(this.page, 'onLogs', message.logs);
}
break;
case 'addon-change':
if (this.reloadTimeoutId) {
clearTimeout(this.reloadTimeoutId);
this.reloadTimeoutId = undefined;
}
this.reloadTimeoutId = setTimeout(function () {
toaster.toast('Reloading...');
setTimeout(function () {
window.location.reload();
}, 500);
}, 500);
break;
case 'shutdown':
if (this.reloadTimeoutId) {
clearTimeout(this.reloadTimeoutId);
this.reloadTimeoutId = undefined;
}
break;
}
},
clearCache: function() {
Expand Down Expand Up @@ -345,11 +415,10 @@ Vue.component('app-page', {
this.app.pages[this.id] = this;
var page = this;
app.$on('page-selected', function(id, path, previousId) {
if ((page.id === previousId) && (page.$parent) && (typeof page.$parent.onHide === 'function')) {
page.$parent.onHide();
}
if ((page.id === id) && (page.$parent) && (typeof page.$parent.onShow === 'function')) {
page.$parent.onShow(path);
if (page.id === previousId) {
callVueFromPage(page, 'onHide');
} else if (page.id === id) {
callVueFromPage(page, 'onShow', path);
}
});
}
Expand All @@ -376,46 +445,6 @@ var menu = new Vue({
}
});

/************************************************************
* Toaster
************************************************************/
var toaster = new Vue({
el: '#toaster',
data: {
message: '',
show: false
},
methods: {
toast: function(message, duration) {
console.log('toast("' + message + '", ' + duration + ')');
if (this.show) {
this.message += '\n' + message;
} else {
this.message = message;
this.show = true;
var self = this;
setTimeout(function () {
self.show = false;
}, duration || 3000)
}
}
}
});

function assertIsOk(response) {
if (response.ok) {
return response;
}
var message;
if (response.status === 403) {
message = 'Sorry you are not authorized';
} else {
message = 'Failed due to ' + response.statusText;
}
toaster.toast(message);
return Promise.reject(message);
}

/************************************************************
* Confirmation
************************************************************/
Expand Down Expand Up @@ -605,19 +634,17 @@ new Vue({
});

function registerPageVue(vue, icon) {
if (vue && vue.$children && (vue.$children.length > 0)) {
var page = vue.$children[0];
if (page.id && page.title) {
menu.pages.push({
id: page.id,
name: page.title
});
homePage.tiles.push({
id: page.id,
name: page.title,
icon: icon
});
}
var page = getPageFromVue(vue);
if (page) {
menu.pages.push({
id: page.id,
name: page.title
});
homePage.tiles.push({
id: page.id,
name: page.title,
icon: icon
});
}
}

Expand Down

0 comments on commit 4ec48ad

Please sign in to comment.