final structure cleanup, sorry for inconvenience ...
git-svn-id: https://svn.fhem.de/fhem/trunk@4483 2b470e98-0d58-463d-a4d8-8e2adae1ed80
@ -1,9 +0,0 @@
|
||||
This is the readme of the new Webfrontend, based on ExtJS.
|
||||
As there is no full documentation available at the moment,
|
||||
please refer to this thread on the forums of FHEM to get help, ask questions or get updates:
|
||||
|
||||
http://forum.fhem.de/index.php?t=msg&th=10439&start=0&rid=0
|
||||
|
||||
The ExtJS Library as well as the application itself are available under the GPLv3 License - http://www.sencha.com/
|
||||
|
||||
See the license.txt in the lib folder for details
|
@ -1,68 +0,0 @@
|
||||
/**
|
||||
* Setup the application
|
||||
*/
|
||||
|
||||
Ext.Loader.setConfig({
|
||||
enabled: true,
|
||||
disableCaching: false,
|
||||
paths: {
|
||||
'FHEM': 'app'
|
||||
}
|
||||
});
|
||||
|
||||
Ext.application({
|
||||
name: 'FHEM Frontend',
|
||||
requires: [
|
||||
'FHEM.view.Viewport'
|
||||
],
|
||||
|
||||
controllers: [
|
||||
'FHEM.controller.MainController',
|
||||
'FHEM.controller.ChartController',
|
||||
'FHEM.controller.TableDataController'
|
||||
],
|
||||
|
||||
launch: function() {
|
||||
|
||||
// Gather information from FHEM to display status, devices, etc.
|
||||
var me = this,
|
||||
url = '../../../fhem?cmd=jsonlist&XHR=1';
|
||||
|
||||
Ext.Ajax.request({
|
||||
method: 'GET',
|
||||
async: false,
|
||||
disableCaching: false,
|
||||
url: url,
|
||||
success: function(response){
|
||||
Ext.getBody().unmask();
|
||||
FHEM.info = Ext.decode(response.responseText);
|
||||
FHEM.version = FHEM.info.Results[0].devices[0].ATTR.version;
|
||||
Ext.each(FHEM.info.Results, function(result) {
|
||||
if (result.list === "DbLog" && result.devices[0].NAME) {
|
||||
FHEM.dblogname = result.devices[0].NAME;
|
||||
}
|
||||
if (result.list === "FileLog" && result.devices.length > 0) {
|
||||
FHEM.filelogs = result.devices;
|
||||
}
|
||||
});
|
||||
if ((!FHEM.dblogname || Ext.isEmpty(FHEM.dblogname)) && !FHEM.filelogs) {
|
||||
Ext.Msg.alert("Error", "Could not find a DbLog or FileLog Configuration. Do you have them already defined?");
|
||||
} else {
|
||||
Ext.create("FHEM.view.Viewport", {
|
||||
hidden: true
|
||||
});
|
||||
|
||||
//removing the loadingimage
|
||||
var p = Ext.DomQuery.select('p[class=loader]')[0],
|
||||
img = Ext.DomQuery.select('#loading-overlay')[0];
|
||||
p.removeChild(img);
|
||||
// further configuration of viewport starts in maincontroller
|
||||
}
|
||||
},
|
||||
failure: function() {
|
||||
Ext.Msg.alert("Error", "The connection to FHEM could not be established");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
@ -1,577 +0,0 @@
|
||||
/**
|
||||
* The Main Controller handling Main Application Logic
|
||||
*/
|
||||
Ext.define('FHEM.controller.MainController', {
|
||||
extend: 'Ext.app.Controller',
|
||||
requires: [
|
||||
'FHEM.view.DevicePanel'
|
||||
],
|
||||
|
||||
refs: [
|
||||
{
|
||||
selector: 'viewport[name=mainviewport]',
|
||||
ref: 'mainviewport' //this.getMainviewport()
|
||||
},
|
||||
{
|
||||
selector: 'text[name=statustextfield]',
|
||||
ref: 'statustextfield' //this.getStatustextfield()
|
||||
},
|
||||
{
|
||||
selector: 'panel[name=westaccordionpanel]',
|
||||
ref: 'westaccordionpanel' //this.getWestaccordionpanel()
|
||||
},
|
||||
{
|
||||
selector: 'panel[name=maintreepanel]',
|
||||
ref: 'maintreepanel' //this.getMaintreepanel()
|
||||
},
|
||||
{
|
||||
selector: 'textfield[name=commandfield]',
|
||||
ref: 'commandfield' //this.getCommandfield()
|
||||
}
|
||||
],
|
||||
|
||||
/**
|
||||
* init function to register listeners
|
||||
*/
|
||||
init: function() {
|
||||
this.control({
|
||||
'viewport[name=mainviewport]': {
|
||||
afterrender: this.viewportRendered
|
||||
},
|
||||
'panel[name=fhemaccordion]': {
|
||||
expand: this.showFHEMPanel
|
||||
},
|
||||
'panel[name=tabledataaccordionpanel]': {
|
||||
expand: this.showDatabaseTablePanel
|
||||
},
|
||||
'treepanel[name=maintreepanel]': {
|
||||
itemclick: this.showDeviceOrChartPanel,
|
||||
treeupdated: this.setupTree
|
||||
},
|
||||
'textfield[name=commandfield]': {
|
||||
specialkey: this.checkCommand
|
||||
},
|
||||
'button[name=saveconfig]': {
|
||||
click: this.saveConfig
|
||||
},
|
||||
'button[name=executecommand]': {
|
||||
click: this.submitCommand
|
||||
},
|
||||
'button[name=shutdownfhem]': {
|
||||
click: this.shutdownFhem
|
||||
},
|
||||
'button[name=restartfhem]': {
|
||||
click: this.restartFhem
|
||||
},
|
||||
'button[name=unsortedtree]': {
|
||||
click: this.setupTree
|
||||
},
|
||||
'button[name=sortedtree]': {
|
||||
click: this.setupTree
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* fade-in viewport, load the FHEM devices and state on viewport render completion
|
||||
*/
|
||||
viewportRendered: function() {
|
||||
|
||||
var me = this;
|
||||
|
||||
me.createFHEMPanel();
|
||||
me.createDevicePanel();
|
||||
me.createLineChartPanel();
|
||||
me.createDatabaseTablePanel();
|
||||
|
||||
me.getMainviewport().show();
|
||||
me.getMainviewport().getEl().setOpacity(0);
|
||||
me.getMainviewport().getEl().animate({
|
||||
opacity: 1,
|
||||
easing: 'easeIn',
|
||||
duration: 500,
|
||||
remove: false
|
||||
});
|
||||
|
||||
if (Ext.isDefined(FHEM.version)) {
|
||||
var sp = this.getStatustextfield();
|
||||
sp.setText(FHEM.version + "; Frontend Version: 1.0.4 - 2013-12-27");
|
||||
}
|
||||
|
||||
this.setupTree(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* setup west accordion / treepanel
|
||||
*/
|
||||
setupTree: function(unsorted) {
|
||||
var me = this,
|
||||
rootNode = { text:"root", expanded: true, children: []},
|
||||
oldRootNode = me.getMaintreepanel().getRootNode();
|
||||
|
||||
//first cleanup
|
||||
if (oldRootNode) {
|
||||
oldRootNode.removeAll();
|
||||
}
|
||||
if (unsorted && unsorted.name === 'unsortedtree') {
|
||||
//setup the tree "unsorted"
|
||||
Ext.each(FHEM.info.Results, function(result) {
|
||||
if (result.list && !Ext.isEmpty(result.list)) {
|
||||
if (result.devices && result.devices.length > 0) {
|
||||
var blacklist = ['dummy', 'notify', 'Global', 'telnet', 'DbLog', 'FileLog', 'FHEMWEB', 'weblink'];
|
||||
if (Ext.Array.contains(blacklist, result.list)) {
|
||||
node = {text: result.list, expanded: false, children: []};
|
||||
} else {
|
||||
node = {text: result.list, expanded: true, children: []};
|
||||
}
|
||||
Ext.each(result.devices, function(device) {
|
||||
var subnode = {text: device.NAME, leaf: true, data: device};
|
||||
node.children.push(subnode);
|
||||
}, this);
|
||||
} else {
|
||||
node = {text: result.list, leaf: true};
|
||||
}
|
||||
rootNode.children.push(node);
|
||||
}
|
||||
});
|
||||
this.getMaintreepanel().setRootNode(rootNode);
|
||||
this.addChartsToTree();
|
||||
} else {
|
||||
//sort / create items by room
|
||||
me.getMaintreepanel().setRootNode(rootNode);
|
||||
var root = me.getMaintreepanel().getRootNode();
|
||||
Ext.each(FHEM.info.Results, function(result) {
|
||||
if (result.list && !Ext.isEmpty(result.list)) {
|
||||
if (result.devices && result.devices.length > 0) {
|
||||
Ext.each(result.devices, function(device) {
|
||||
if (device.ATTR && device.ATTR.room) {
|
||||
//first we check if we have comma separated multiple rooms
|
||||
var roomArray = device.ATTR.room.split(",");
|
||||
Ext.each(roomArray, function(room) {
|
||||
//check if room exists
|
||||
var resultnode = root.findChild("text", room, true),
|
||||
subnode = {text: device.NAME, leaf: true, data: device};
|
||||
if (!resultnode) {
|
||||
//create roomfolder
|
||||
var roomfolder;
|
||||
if (room !== "hidden") {
|
||||
if (room === "Unsorted") {
|
||||
roomfolder = {text: room, leaf: false, expanded: false, children: []};
|
||||
} else {
|
||||
roomfolder = {text: room, leaf: false, expanded: true, children: []};
|
||||
}
|
||||
roomfolder.children.push(subnode);
|
||||
root.appendChild(roomfolder);
|
||||
}
|
||||
} else {
|
||||
resultnode.appendChild(subnode);
|
||||
root.appendChild(resultnode);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
} else {
|
||||
node = {text: result.list, leaf: true};
|
||||
root.appendChild(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.addChartsToTree();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
addChartsToTree: function() {
|
||||
//load the saved charts store with configured dblog name
|
||||
var me = this,
|
||||
store = Ext.create('FHEM.store.SavedChartsStore', {});
|
||||
store.getProxy().url = '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+""+getcharts&XHR=1';
|
||||
store.load();
|
||||
//add the charts to the tree
|
||||
store.on("load", function() {
|
||||
var rootNode = me.getMaintreepanel().getRootNode(),
|
||||
chartfolder = {text: "Charts", expanded: true, children: []};
|
||||
rootNode.appendChild(chartfolder);
|
||||
var chartfoldernode = rootNode.findChild("text", "Charts", true);
|
||||
|
||||
//add the filelogcharts to the store
|
||||
if (FHEM.filelogcharts) {
|
||||
store.add(FHEM.filelogcharts);
|
||||
}
|
||||
|
||||
store.each(function(rec) {
|
||||
var chartchild,
|
||||
unsortedMode = Ext.ComponentQuery.query('button[name=unsortedtree]')[0].pressed;
|
||||
|
||||
if (!unsortedMode && rec.raw && rec.raw.VALUE && rec.raw.VALUE.parentFolder) {
|
||||
var ownerFolder = rec.raw.VALUE.parentFolder,
|
||||
index = rec.raw.VALUE.treeIndex,
|
||||
parentNode = rootNode.findChild("text", ownerFolder, true);
|
||||
|
||||
chartchild = {text: rec.raw.NAME, leaf: true, data: rec.raw, iconCls:'x-tree-icon-leaf-chart'};
|
||||
if (parentNode === null) {
|
||||
rootNode.insertChild(index, chartchild);
|
||||
} else {
|
||||
parentNode.insertChild(index, chartchild);
|
||||
}
|
||||
} else {
|
||||
chartchild = {text: rec.raw.NAME, leaf: true, data: rec.raw, iconCls:'x-tree-icon-leaf-chart'};
|
||||
chartfoldernode.appendChild(chartchild);
|
||||
}
|
||||
});
|
||||
|
||||
// at last we add a chart template to the folder which wont be saved to db and cannot be deleted
|
||||
chartchild = {text: 'Create new Chart', leaf: true, data: {template: true}, iconCls:'x-tree-icon-leaf-chart'};
|
||||
chartfoldernode.appendChild(chartchild);
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
saveConfig: function() {
|
||||
|
||||
var command = this.getCommandfield().getValue();
|
||||
if (command && !Ext.isEmpty(command)) {
|
||||
this.submitCommand();
|
||||
}
|
||||
|
||||
Ext.Ajax.request({
|
||||
method: 'GET',
|
||||
disableCaching: false,
|
||||
url: '../../../fhem?cmd=save',
|
||||
success: function(response){
|
||||
|
||||
var win = Ext.create('Ext.window.Window', {
|
||||
width: 110,
|
||||
height: 60,
|
||||
html: 'Save successful!',
|
||||
preventHeader: true,
|
||||
border: false,
|
||||
closable: false,
|
||||
plain: true
|
||||
});
|
||||
win.showAt(Ext.getBody().getWidth() / 2 -100, 30);
|
||||
win.getEl().animate({
|
||||
opacity: 0,
|
||||
easing: 'easeOut',
|
||||
duration: 3000,
|
||||
delay: 2000,
|
||||
remove: false,
|
||||
listeners: {
|
||||
afteranimate: function() {
|
||||
win.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
failure: function() {
|
||||
Ext.Msg.alert("Error", "Could not save the current configuration!");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
checkCommand: function(field, e) {
|
||||
if (e.getKey() == e.ENTER && !Ext.isEmpty(field.getValue())) {
|
||||
this.submitCommand();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
submitCommand: function() {
|
||||
|
||||
var command = this.getCommandfield().getValue();
|
||||
|
||||
if (command && !Ext.isEmpty(command)) {
|
||||
Ext.Ajax.request({
|
||||
method: 'GET',
|
||||
disableCaching: false,
|
||||
url: '../../../fhem?cmd=' + command + '&XHR=1',
|
||||
success: function(response){
|
||||
|
||||
if(response.responseText && !Ext.isEmpty(response.responseText)) {
|
||||
Ext.create('Ext.window.Window', {
|
||||
maxWidth: 600,
|
||||
maxHeight: 500,
|
||||
autoScroll: true,
|
||||
layout: 'fit',
|
||||
title: "Response",
|
||||
items: [
|
||||
{
|
||||
xtype: 'panel',
|
||||
autoScroll: true,
|
||||
items:[
|
||||
{
|
||||
xtype: 'displayfield',
|
||||
htmlEncode: true,
|
||||
value: response.responseText
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}).show();
|
||||
} else {
|
||||
var win = Ext.create('Ext.window.Window', {
|
||||
width: 130,
|
||||
height: 60,
|
||||
html: 'Command submitted!',
|
||||
preventHeader: true,
|
||||
border: false,
|
||||
closable: false,
|
||||
plain: true
|
||||
});
|
||||
win.showAt(Ext.getBody().getWidth() / 2 -100, 30);
|
||||
win.getEl().animate({
|
||||
opacity: 0,
|
||||
easing: 'easeOut',
|
||||
duration: 3000,
|
||||
delay: 2000,
|
||||
remove: false,
|
||||
listeners: {
|
||||
afteranimate: function() {
|
||||
win.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
failure: function() {
|
||||
Ext.Msg.alert("Error", "Could not submit the command!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
shutdownFhem: function() {
|
||||
Ext.Ajax.request({
|
||||
method: 'GET',
|
||||
disableCaching: false,
|
||||
url: '../../../fhem?cmd=shutdown&XHR=1'
|
||||
});
|
||||
var win = Ext.create('Ext.window.Window', {
|
||||
width: 130,
|
||||
height: 60,
|
||||
html: 'Shutdown submitted!',
|
||||
preventHeader: true,
|
||||
border: false,
|
||||
closable: false,
|
||||
plain: true
|
||||
});
|
||||
win.showAt(Ext.getBody().getWidth() / 2 -100, 30);
|
||||
win.getEl().animate({
|
||||
opacity: 0,
|
||||
easing: 'easeOut',
|
||||
duration: 3000,
|
||||
delay: 2000,
|
||||
remove: false,
|
||||
listeners: {
|
||||
afteranimate: function() {
|
||||
win.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
restartFhem: function() {
|
||||
Ext.Ajax.request({
|
||||
method: 'GET',
|
||||
disableCaching: false,
|
||||
url: '../../../fhem?cmd=shutdown restart&XHR=1'
|
||||
});
|
||||
Ext.getBody().mask("Please wait while FHEM is restarting...");
|
||||
this.retryConnect();
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
retryConnect: function() {
|
||||
var me = this;
|
||||
|
||||
var task = new Ext.util.DelayedTask(function(){
|
||||
Ext.Ajax.request({
|
||||
method: 'GET',
|
||||
disableCaching: false,
|
||||
url: '../../../fhem?cmd=jsonlist&XHR=1',
|
||||
|
||||
success: function(response){
|
||||
if (response.responseText !== "Unknown command JsonList, try help↵") {
|
||||
//restarting the frontend
|
||||
window.location.reload();
|
||||
} else {
|
||||
me.retryConnect();
|
||||
}
|
||||
|
||||
},
|
||||
failure: function() {
|
||||
me.retryConnect();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
task.delay(1000);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
hideCenterPanels: function() {
|
||||
var panels = Ext.ComponentQuery.query('panel[region=center]');
|
||||
Ext.each(panels, function(panel) {
|
||||
panel.hide();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
showDeviceOrChartPanel: function(treeview, rec) {
|
||||
var me = this;
|
||||
if (rec.raw.data.template === true || rec.get('leaf') === true &&
|
||||
rec.raw.data &&
|
||||
rec.raw.data.TYPE &&
|
||||
(rec.raw.data.TYPE === "savedchart" || rec.raw.data.TYPE === "savedfilelogchart")) {
|
||||
this.showLineChartPanel();
|
||||
} else {
|
||||
this.showDevicePanel(treeview, rec);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
showFHEMPanel: function() {
|
||||
var panel = Ext.ComponentQuery.query('panel[name=fhempanel]')[0];
|
||||
this.hideCenterPanels();
|
||||
panel.show();
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
createFHEMPanel: function() {
|
||||
var panel = {
|
||||
xtype: 'panel',
|
||||
name: 'fhempanel',
|
||||
title: 'FHEM',
|
||||
region: 'center',
|
||||
layout: 'fit',
|
||||
hidden: true,
|
||||
items : [
|
||||
{
|
||||
xtype : 'component',
|
||||
autoEl : {
|
||||
tag : 'iframe',
|
||||
src : '../../fhem?'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
this.getMainviewport().add(panel);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
showDevicePanel: function(view, record) {
|
||||
|
||||
if (record.raw.leaf === true) {
|
||||
var panel = Ext.ComponentQuery.query('devicepanel')[0];
|
||||
var title;
|
||||
if (record.raw.ATTR &&
|
||||
record.raw.ATTR.alias &&
|
||||
!Ext.isEmpty(record.raw.ATTR.alias)) {
|
||||
title = record.raw.data.ATTR.alias;
|
||||
} else {
|
||||
title = record.raw.data.NAME;
|
||||
}
|
||||
panel.setTitle(title);
|
||||
panel.record = record;
|
||||
|
||||
this.hideCenterPanels();
|
||||
panel.show();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
createDevicePanel: function() {
|
||||
var panel = {
|
||||
xtype: 'devicepanel',
|
||||
title: null,
|
||||
region: 'center',
|
||||
layout: 'fit',
|
||||
record: null,
|
||||
hidden: true
|
||||
};
|
||||
this.getMainviewport().add(panel);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
showLineChartPanel: function() {
|
||||
var panel = Ext.ComponentQuery.query('linechartpanel')[0];
|
||||
this.hideCenterPanels();
|
||||
panel.show();
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
createLineChartPanel: function() {
|
||||
var panel = {
|
||||
xtype: 'linechartpanel',
|
||||
name: 'linechartpanel',
|
||||
region: 'center',
|
||||
layout: 'fit',
|
||||
hidden: true
|
||||
};
|
||||
this.getMainviewport().add(panel);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
createDatabaseTablePanel: function() {
|
||||
var panel = {
|
||||
xtype: 'tabledatagridpanel',
|
||||
name: 'tabledatagridpanel',
|
||||
region: 'center',
|
||||
layout: 'fit',
|
||||
hidden: true
|
||||
};
|
||||
this.getMainviewport().add(panel);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
showDatabaseTablePanel: function() {
|
||||
var panel = Ext.ComponentQuery.query('tabledatagridpanel')[0];
|
||||
this.hideCenterPanels();
|
||||
panel.show();
|
||||
}
|
||||
|
||||
});
|
@ -1,137 +0,0 @@
|
||||
/**
|
||||
* The Controller handling Table Data retrieval
|
||||
*/
|
||||
Ext.define('FHEM.controller.TableDataController', {
|
||||
extend: 'Ext.app.Controller',
|
||||
requires: [
|
||||
'FHEM.view.TableDataGridPanel'
|
||||
],
|
||||
|
||||
refs: [
|
||||
{
|
||||
selector: 'button[name=applytablefilter]',
|
||||
ref: 'applytablefilterbtn' //this.getApplytablefilterbtn()
|
||||
}
|
||||
],
|
||||
|
||||
/**
|
||||
* init function to register listeners
|
||||
*/
|
||||
init: function() {
|
||||
this.control({
|
||||
'button[name=applytablefilter]': {
|
||||
click: this.filterTableData
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* function handling the filtering of tabledata, preparing querystring
|
||||
*/
|
||||
filterTableData: function() {
|
||||
|
||||
var me = this,
|
||||
devicecombo = Ext.ComponentQuery.query('combo[name=tddevicecombo]')[0],
|
||||
readingscombo = Ext.ComponentQuery.query('combo[name=tdreadingscombo]')[0],
|
||||
checkedradio = Ext.ComponentQuery.query('radiogroup[name=tddynamictime]')[0],
|
||||
starttimepicker = Ext.ComponentQuery.query('datefield[name=tdstarttimepicker]')[0],
|
||||
endtimepicker = Ext.ComponentQuery.query('datefield[name=tdendtimepicker]')[0],
|
||||
gridpanel = Ext.ComponentQuery.query('gridpanel[name=tabledatagridpanel]')[0];
|
||||
|
||||
//check if timerange or dynamic time should be used
|
||||
checkedradio.eachBox(function(box, idx){
|
||||
var date = new Date();
|
||||
if (box.checked) {
|
||||
if (box.inputValue === "year") {
|
||||
starttime = Ext.Date.parse(date.getUTCFullYear() + "-01-01", "Y-m-d");
|
||||
endtime = Ext.Date.parse(date.getUTCFullYear() + 1 + "-01-01", "Y-m-d");
|
||||
} else if (box.inputValue === "month") {
|
||||
starttime = Ext.Date.getFirstDateOfMonth(date);
|
||||
endtime = Ext.Date.getLastDateOfMonth(date);
|
||||
} else if (box.inputValue === "week") {
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
date.setSeconds(0);
|
||||
//monday starts with 0 till sat with 5, sund with -1
|
||||
var dayoffset = date.getDay() - 1,
|
||||
monday,
|
||||
nextmonday;
|
||||
if (dayoffset >= 0) {
|
||||
monday = Ext.Date.add(date, Ext.Date.DAY, -dayoffset);
|
||||
} else {
|
||||
//we have a sunday
|
||||
monday = Ext.Date.add(date, Ext.Date.DAY, -6);
|
||||
}
|
||||
nextmonday = Ext.Date.add(monday, Ext.Date.DAY, 7);
|
||||
|
||||
starttime = monday;
|
||||
endtime = nextmonday;
|
||||
} else if (box.inputValue === "day") {
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
date.setSeconds(0);
|
||||
starttime = date;
|
||||
endtime = Ext.Date.add(date, Ext.Date.DAY, 1);
|
||||
} else if (box.inputValue === "hour") {
|
||||
date.setMinutes(0);
|
||||
date.setSeconds(0);
|
||||
starttime = date;
|
||||
endtime = Ext.Date.add(date, Ext.Date.HOUR, 1);
|
||||
} else {
|
||||
Ext.Msg.alert("Error", "Could not setup the dynamic time.");
|
||||
}
|
||||
dbstarttime = Ext.Date.format(starttime, 'Y-m-d_H:i:s');
|
||||
dbendtime = Ext.Date.format(endtime, 'Y-m-d_H:i:s');
|
||||
|
||||
starttimepicker.setValue(starttime);
|
||||
endtimepicker.setValue(endtime);
|
||||
} else {
|
||||
dbstarttime = Ext.Date.format(starttimepicker.getValue(), 'Y-m-d_H:i:s');
|
||||
dbendtime = Ext.Date.format(endtimepicker.getValue(), 'Y-m-d_H:i:s');
|
||||
}
|
||||
});
|
||||
|
||||
if (Ext.isEmpty(dbstarttime) || Ext.isEmpty(dbendtime)) {
|
||||
Ext.Msg.alert("Error", "Please select a timerange first!");
|
||||
} else {
|
||||
//cleanup store
|
||||
gridpanel.getStore().clearData();
|
||||
|
||||
var firststart = true;
|
||||
|
||||
gridpanel.getStore().on("beforeprefetch", function(store, operation, eOpts) {
|
||||
|
||||
var url = '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+' + dbstarttime + '+' + dbendtime + '+';
|
||||
if (!Ext.isEmpty(devicecombo.getValue())) {
|
||||
url += devicecombo.getValue();
|
||||
} else {
|
||||
url += '""';
|
||||
}
|
||||
|
||||
url += '+getTableData+""+';
|
||||
if (!Ext.isEmpty(readingscombo.rawValue)) {
|
||||
url += readingscombo.rawValue;
|
||||
} else {
|
||||
url += '""';
|
||||
}
|
||||
url += '+""+""+';
|
||||
if (firststart) {
|
||||
url += "0+";
|
||||
firststart = false;
|
||||
} else {
|
||||
url += operation.start + "+";
|
||||
}
|
||||
url += operation.limit + "&XHR=1";
|
||||
|
||||
if (operation.request) {
|
||||
operation.request.url = url;
|
||||
}
|
||||
|
||||
store.proxy.url = url;
|
||||
});
|
||||
gridpanel.getStore().load();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
});
|
@ -1 +0,0 @@
|
||||
FHEM.filelogcharts = [];
|
@ -1,445 +0,0 @@
|
||||
/**
|
||||
* Model for Charts
|
||||
*/
|
||||
|
||||
Ext.define('FHEM.model.ChartModel', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
{
|
||||
name: 'TIMESTAMP',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'TIMESTAMP2',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'TIMESTAMP3',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'TIMESTAMP4',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'TIMESTAMP5',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'TIMESTAMP6',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'TIMESTAMP7',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'TIMESTAMP8',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'TIMESTAMP9',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'VALUE',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},{
|
||||
name: 'VALUE2',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},{
|
||||
name: 'VALUE3',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},{
|
||||
name: 'VALUE4',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},{
|
||||
name: 'VALUE5',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},{
|
||||
name: 'VALUE6',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},{
|
||||
name: 'VALUE7',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},{
|
||||
name: 'VALUE8',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},{
|
||||
name: 'VALUE9',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM2',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM3',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM4',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM5',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM6',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM7',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM8',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'SUM9',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG2',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG3',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG4',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG5',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG6',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG7',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG8',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'AVG9',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN2',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN3',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN4',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN5',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN6',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN7',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN8',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MIN9',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX2',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX3',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX4',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX5',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX6',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX7',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX8',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'MAX9',
|
||||
type: 'float',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT2',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT3',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT4',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT5',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT6',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT7',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT8',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'COUNT9',
|
||||
type: 'integer',
|
||||
convert: function(v,record) {
|
||||
return record.parseToNumber(v);
|
||||
}
|
||||
}
|
||||
],
|
||||
parseToNumber: function(value) {
|
||||
|
||||
if (value === "") {
|
||||
//we will return nothing
|
||||
} else if (parseFloat(value, 10).toString().toUpperCase() === "NAN") {
|
||||
if (Ext.isDefined(FHEM) && Ext.isDefined(FHEM.userconfig)) {
|
||||
var convertednumber = 0;
|
||||
Ext.iterate(FHEM.userconfig.chartkeys, function(k, v) {
|
||||
if (value === k) {
|
||||
//return the value for the given key from userconfig
|
||||
convertednumber = v;
|
||||
}
|
||||
});
|
||||
return parseFloat(convertednumber, 10);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
} else {
|
||||
return parseFloat(value, 10);
|
||||
}
|
||||
}
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Model for Devices
|
||||
*/
|
||||
Ext.define('FHEM.model.DeviceModel', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
{
|
||||
name: 'DEVICE',
|
||||
type: 'text'
|
||||
}
|
||||
]
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Model for Readings
|
||||
*/
|
||||
Ext.define('FHEM.model.ReadingsModel', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
{
|
||||
name: 'READING',
|
||||
type: 'text'
|
||||
}
|
||||
]
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Model for saved Charts
|
||||
*/
|
||||
Ext.define('FHEM.model.SavedChartsModel', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
{
|
||||
name: 'ID',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'NAME',
|
||||
type: 'text'
|
||||
},{
|
||||
name: 'VALUE',
|
||||
type: 'text'
|
||||
}
|
||||
]
|
||||
});
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Model for DatabaseTables
|
||||
*/
|
||||
Ext.define('FHEM.model.TableDataModel', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
{
|
||||
name: 'TIMESTAMP',
|
||||
type: 'date',
|
||||
dateFormat: "Y-m-d H:i:s"
|
||||
},
|
||||
{
|
||||
name: 'DEVICE',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'TYPE',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'EVENT',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'READING',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'VALUE',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'UNIT',
|
||||
type: 'text'
|
||||
}
|
||||
]
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
.x-tree-icon.x-tree-icon-leaf.x-tree-icon-leaf-chart {
|
||||
background-image: url(icons/chart_bar.png);
|
||||
}
|
Before Width: | Height: | Size: 781 B |
Before Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 345 B |
Before Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 770 B |
Before Width: | Height: | Size: 755 B |
Before Width: | Height: | Size: 715 B |
@ -1,22 +0,0 @@
|
||||
Silk icon set 1.3
|
||||
|
||||
_________________________________________
|
||||
Mark James
|
||||
http://www.famfamfam.com/lab/icons/silk/
|
||||
_________________________________________
|
||||
|
||||
This work is licensed under a
|
||||
Creative Commons Attribution 2.5 License.
|
||||
[ http://creativecommons.org/licenses/by/2.5/ ]
|
||||
|
||||
This means you may use it for any purpose,
|
||||
and make any changes you like.
|
||||
All I ask is that you include a link back
|
||||
to this page in your credits.
|
||||
|
||||
Are you using this icon set? Send me an email
|
||||
(including a link or picture if available) to
|
||||
mjames@gmail.com
|
||||
|
||||
Any other questions about this icon set please
|
||||
contact mjames@gmail.com
|
Before Width: | Height: | Size: 524 B |
Before Width: | Height: | Size: 395 B |
Before Width: | Height: | Size: 389 B |
Before Width: | Height: | Size: 700 B |
Before Width: | Height: | Size: 2.1 KiB |
@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Store for the Charts
|
||||
*/
|
||||
Ext.define('FHEM.store.ChartStore', {
|
||||
extend: 'Ext.data.Store',
|
||||
model: 'FHEM.model.ChartModel',
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
method: 'POST',
|
||||
url: '', //gets set by controller
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: false
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Store for the Devices
|
||||
*/
|
||||
Ext.define('FHEM.store.DeviceStore', {
|
||||
extend: 'Ext.data.Store',
|
||||
model: 'FHEM.model.DeviceModel',
|
||||
id: 'devicestore',
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
method: 'POST',
|
||||
noCache : false,
|
||||
url: '', //gets set by controller
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: false
|
||||
});
|
@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Store for the Readings
|
||||
*/
|
||||
Ext.define('FHEM.store.ReadingsStore', {
|
||||
extend: 'Ext.data.Store',
|
||||
model: 'FHEM.model.ReadingsModel',
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
method: 'POST',
|
||||
url: '', //gets set by controller after device has been selected
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: false
|
||||
});
|
@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Store for the saved Charts
|
||||
*/
|
||||
Ext.define('FHEM.store.SavedChartsStore', {
|
||||
extend: 'Ext.data.Store',
|
||||
model: 'FHEM.model.SavedChartsModel',
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
method: 'POST',
|
||||
url: '', //gets set by controller
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: false
|
||||
});
|
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Store for the TableData from Database
|
||||
*/
|
||||
Ext.define('FHEM.store.TableDataStore', {
|
||||
extend: 'Ext.data.Store',
|
||||
model: 'FHEM.model.TableDataModel',
|
||||
buffered: true,
|
||||
trailingBufferZone: 1000,
|
||||
leadingBufferZone: 1000,
|
||||
//remoteGroup: true,
|
||||
pageSize: 1000,
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
method: 'POST',
|
||||
url: '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+""+getTableData+""+""+""+""+0+100&XHR=1',
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: false
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* This is the user configuration file for the frontend.
|
||||
* You can set your own parameters here, e.g. to set how the charting should
|
||||
* handle non numeric values
|
||||
*/
|
||||
FHEM = {};
|
||||
|
||||
FHEM.userconfig = {
|
||||
|
||||
// Here you can set how non numeric values like "on" or "off" should be interpreted in the charts
|
||||
// you can add your own specific parameter here if needed and give it a numeric value of your choice, e.g.
|
||||
// "an": "100",
|
||||
// "aus": "50"
|
||||
chartkeys: {
|
||||
"on": "1",
|
||||
"off": "0",
|
||||
"open": "10",
|
||||
"closed": "1"
|
||||
}
|
||||
};
|
@ -1,64 +0,0 @@
|
||||
/**
|
||||
* A Panel containing device specific information
|
||||
*/
|
||||
Ext.define('FHEM.view.ChartGridPanel', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias : 'widget.chartgridpanel',
|
||||
|
||||
requires: [
|
||||
'Ext.form.FieldSet',
|
||||
'Ext.layout.container.Column',
|
||||
'Ext.form.field.ComboBox'
|
||||
],
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
title: 'Chart data',
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
jsonrecords: null,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
collapsible: true,
|
||||
|
||||
titleCollapse: true,
|
||||
|
||||
animCollapse: false,
|
||||
|
||||
/**
|
||||
* init function
|
||||
*/
|
||||
initComponent: function() {
|
||||
|
||||
var me = this;
|
||||
|
||||
var chartdatastore = Ext.create('Ext.data.Store', {
|
||||
fields: [],
|
||||
data: [],
|
||||
proxy: {
|
||||
type: 'memory',
|
||||
reader: {
|
||||
type: 'json'
|
||||
}
|
||||
}
|
||||
});
|
||||
var chartdatagrid = {
|
||||
xtype: 'grid',
|
||||
height: 170,
|
||||
name: 'chartdata',
|
||||
columns: [
|
||||
],
|
||||
store: chartdatastore
|
||||
};
|
||||
|
||||
me.items = [chartdatagrid];
|
||||
|
||||
me.callParent(arguments);
|
||||
}
|
||||
|
||||
});
|
@ -1,468 +0,0 @@
|
||||
/**
|
||||
* A Panel containing device specific information
|
||||
*/
|
||||
Ext.define('FHEM.view.DevicePanel', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias : 'widget.devicepanel',
|
||||
|
||||
requires: [
|
||||
'Ext.form.FieldSet',
|
||||
'Ext.layout.container.Column',
|
||||
'Ext.form.field.ComboBox'
|
||||
],
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
title: null,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
region: 'center',
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
record: null,
|
||||
|
||||
/**
|
||||
* init function
|
||||
*/
|
||||
initComponent: function() {
|
||||
|
||||
var me = this;
|
||||
|
||||
me.items = [{
|
||||
xtype: 'panel',
|
||||
autoScroll: true,
|
||||
name: 'container'
|
||||
}];
|
||||
|
||||
me.callParent(arguments);
|
||||
|
||||
var controlFieldset = Ext.create('Ext.form.FieldSet', {
|
||||
title: 'Controls',
|
||||
name: 'controlfieldset',
|
||||
layout: 'column',
|
||||
hidden: true,
|
||||
bodyStyle: 'padding:5px 5px 0',
|
||||
defaults: {
|
||||
margin: '0 10 10 10',
|
||||
height: 65
|
||||
}
|
||||
});
|
||||
me.down('panel[name=container]').add(controlFieldset);
|
||||
|
||||
var devicedatastore = Ext.create('Ext.data.Store', {
|
||||
fields: ['key', 'value'],
|
||||
data: [],
|
||||
proxy: {
|
||||
type: 'memory',
|
||||
reader: {
|
||||
type: 'json'
|
||||
}
|
||||
}
|
||||
});
|
||||
var devicedatagrid = {
|
||||
xtype: 'grid',
|
||||
title: 'Device Data',
|
||||
name: 'devicedata',
|
||||
columns: [
|
||||
{
|
||||
header: 'KEY',
|
||||
dataIndex: 'key',
|
||||
width: '49%'
|
||||
},
|
||||
{
|
||||
header: 'VALUE',
|
||||
dataIndex: 'value',
|
||||
width: '49%'
|
||||
}
|
||||
],
|
||||
store: devicedatastore
|
||||
};
|
||||
me.down('panel[name=container]').add(devicedatagrid);
|
||||
|
||||
var devicereadingsstore = Ext.create('Ext.data.Store', {
|
||||
fields: ['key', 'value', 'measured'],
|
||||
data: [],
|
||||
proxy: {
|
||||
type: 'memory',
|
||||
reader: {
|
||||
type: 'json'
|
||||
}
|
||||
}
|
||||
});
|
||||
var devicereadingsgrid = {
|
||||
xtype: 'grid',
|
||||
title: 'Device Readings',
|
||||
name: 'readingsgrid',
|
||||
columns: [
|
||||
{
|
||||
header: 'KEY',
|
||||
dataIndex: 'key',
|
||||
width: '33%'
|
||||
},
|
||||
{
|
||||
header: 'VALUE',
|
||||
dataIndex: 'value',
|
||||
width: '33%'
|
||||
},
|
||||
{
|
||||
header: 'MEASURED',
|
||||
dataIndex: 'measured',
|
||||
width: '33%'
|
||||
}
|
||||
],
|
||||
store: devicereadingsstore
|
||||
};
|
||||
me.down('panel[name=container]').add(devicereadingsgrid);
|
||||
|
||||
me.on("show", function() {
|
||||
me.setLoading(true);
|
||||
|
||||
// Stop all old tasks
|
||||
Ext.TaskManager.stopAll();
|
||||
|
||||
//remove old controls to rerender them on devicechange
|
||||
me.down('fieldset[name=controlfieldset]').removeAll();
|
||||
me.down('fieldset[name=controlfieldset]').hide();
|
||||
|
||||
// Starting a task to update the device readings
|
||||
var task = {
|
||||
run: function(){
|
||||
me.getDeviceData(me.record.raw.data.NAME);
|
||||
},
|
||||
interval: 5000 //5 seconds
|
||||
};
|
||||
Ext.TaskManager.start(task);
|
||||
});
|
||||
|
||||
me.on("hide", function() {
|
||||
Ext.TaskManager.stopAll();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
sendCommand: function(command, value) {
|
||||
var me = this,
|
||||
url = '../../../fhem?cmd=set ' + me.record.raw.data.NAME + ' '+ command;
|
||||
|
||||
if (value && !Ext.isEmpty(value)) {
|
||||
url += ' ' + value;
|
||||
}
|
||||
url += '&XHR=1';
|
||||
|
||||
Ext.Ajax.request({
|
||||
method: 'GET',
|
||||
disableCaching: false,
|
||||
url: url,
|
||||
success: function(response){
|
||||
if (response.status === 200) {
|
||||
//all ok
|
||||
var win = Ext.create('Ext.window.Window', {
|
||||
width: 130,
|
||||
height: 60,
|
||||
html: 'Command submitted!',
|
||||
preventHeader: true,
|
||||
border: false,
|
||||
closable: false,
|
||||
plain: true
|
||||
});
|
||||
win.showAt(Ext.getBody().getWidth() / 2 -100, 30);
|
||||
win.getEl().animate({
|
||||
opacity: 0,
|
||||
easing: 'easeOut',
|
||||
duration: 3000,
|
||||
delay: 2000,
|
||||
remove: false,
|
||||
listeners: {
|
||||
afteranimate: function() {
|
||||
win.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// trigger an update nearly immediately to set new values
|
||||
var task = new Ext.util.DelayedTask(function(){
|
||||
me.getDeviceData(me.record.raw.data.NAME);
|
||||
});
|
||||
task.delay(1000);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
failure: function() {
|
||||
Ext.Msg.alert("Error", "Could not send command!");
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
updateControls: function(results) {
|
||||
|
||||
var me = this,
|
||||
allSets = results.sets,
|
||||
controlfieldset = me.down('panel[name=container] fieldset[name=controlfieldset]');
|
||||
|
||||
if (controlfieldset.items.length <= 0) {
|
||||
|
||||
if (results.ATTR.webCmd) {
|
||||
Ext.each(results.sets, function(set) {
|
||||
var split = set.split(":");
|
||||
if (split[0] === results.ATTR.webCmd) {
|
||||
// overriding all sets as we only need the user defined webcmd now
|
||||
allSets = set;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ext.each(allSets, function(set) {
|
||||
//check for button / slider
|
||||
if (set.indexOf(":") > 0) {
|
||||
var split = set.split(":");
|
||||
var text = split[0];
|
||||
|
||||
if (split[1].indexOf(",") > 0) { // we currently only use sets that have more than just a text
|
||||
var splitvals = split[1].split(",");
|
||||
|
||||
var subfieldset = Ext.create('Ext.form.FieldSet', {
|
||||
title: text,
|
||||
name: 'subcontrolfieldset'
|
||||
});
|
||||
controlfieldset.add(subfieldset);
|
||||
controlfieldset.setVisible(true);
|
||||
|
||||
if (splitvals.length > 3) { //make a dropdown
|
||||
|
||||
var dataset = [];
|
||||
Ext.each(splitvals, function(val) {
|
||||
var entry = {
|
||||
'name':val
|
||||
};
|
||||
dataset.push(entry);
|
||||
});
|
||||
|
||||
var comboStore = Ext.create('Ext.data.Store', {
|
||||
fields: ['name'],
|
||||
data : dataset
|
||||
});
|
||||
|
||||
var current;
|
||||
Ext.each(results.READINGS, function(reading) {
|
||||
Ext.iterate(reading, function(k,v) {
|
||||
if (k === text) {
|
||||
current = v;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var combo = Ext.create('Ext.form.ComboBox', {
|
||||
store: comboStore,
|
||||
padding: 8,
|
||||
queryMode: 'local',
|
||||
displayField: 'name',
|
||||
valueField: 'name',
|
||||
value: current,
|
||||
listeners: {
|
||||
select: function(combo, records) {
|
||||
var value = records[0].data.name;
|
||||
me.sendCommand(text, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
subfieldset.add(combo);
|
||||
|
||||
} else { // give some buttons
|
||||
|
||||
Ext.each(splitvals, function(val) {
|
||||
|
||||
var pressed = false;
|
||||
Ext.each(results.READINGS, function(reading) {
|
||||
Ext.iterate(reading, function(k,v) {
|
||||
if (k === text && v === val || k === text && val === "0" && v === "null") {
|
||||
pressed = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var control = Ext.create('Ext.button.Button', {
|
||||
text: val,
|
||||
width: 120,
|
||||
height: 40,
|
||||
enableToggle: true,
|
||||
pressed: pressed,
|
||||
listeners: {
|
||||
click: function(btn) {
|
||||
var command = text,
|
||||
value = btn.text;
|
||||
me.sendCommand(command, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
subfieldset.add(control);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else { // we already have controls added, just checkin the state if everything is up2date
|
||||
|
||||
Ext.each(controlfieldset.items.items, function(subfieldset) {
|
||||
|
||||
Ext.each(subfieldset.items.items, function(item) {
|
||||
|
||||
var xtype = item.getXType(),
|
||||
current;
|
||||
|
||||
Ext.each(results.READINGS, function(reading) {
|
||||
Ext.iterate(reading, function(k,v) {
|
||||
if (k === subfieldset.title) {
|
||||
current = v;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (xtype === "combobox") {
|
||||
item.setValue(current);
|
||||
} else if (xtype === "button") {
|
||||
if (item.text === current || item.text === "0" && current === "null") {
|
||||
item.toggle(true);
|
||||
} else {
|
||||
item.toggle(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (controlfieldset.items.length <= 0) {
|
||||
controlfieldset.hide();
|
||||
} else {
|
||||
controlfieldset.show();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
processReadings: function(readings) {
|
||||
|
||||
var me = this,
|
||||
devicedata = [],
|
||||
devicegrid = me.down('panel[name=container] grid[name=devicedata]'),
|
||||
devicestore = devicegrid.getStore(),
|
||||
readingsgrid = me.down('panel[name=container] grid[name=readingsgrid]'),
|
||||
readingsstore = readingsgrid.getStore();
|
||||
|
||||
Ext.iterate(readings, function(key, value) {
|
||||
if (key !== 'ATTR' && key !== 'attrs' &&
|
||||
key !== 'ATTRIBUTES' && key !== 'sets' &&
|
||||
key !== 'READINGS' && key !== 'CHANGETIME') {
|
||||
|
||||
if (typeof value === "object") {
|
||||
Ext.iterate(value, function(k, v) {
|
||||
var obj = {
|
||||
key: k,
|
||||
value: v
|
||||
};
|
||||
devicedata.push(obj);
|
||||
});
|
||||
|
||||
} else {
|
||||
var obj = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
devicedata.push(obj);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
devicestore.loadData(devicedata);
|
||||
|
||||
var readingcollection = readings.READINGS,
|
||||
readingsdata = [];
|
||||
|
||||
Ext.each(readingcollection, function(readings) {
|
||||
Ext.each(readings, function(reading) {
|
||||
Ext.iterate(reading, function(key, value) {
|
||||
|
||||
var obj;
|
||||
if (typeof value === "object") {
|
||||
obj = {
|
||||
key: key,
|
||||
value: value.VAL,
|
||||
measured: value.TIME
|
||||
};
|
||||
readingsdata.push(obj);
|
||||
|
||||
} else if (key !== "measured") {
|
||||
obj = {
|
||||
key: key,
|
||||
value: value,
|
||||
measured: ''
|
||||
};
|
||||
readingsdata.push(obj);
|
||||
} else {
|
||||
// as the measured time belongs to the last dataset, we merge it..
|
||||
readingsdata[readingsdata.length - 1].measured = value;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
readingsstore.loadData(readingsdata);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
getDeviceData: function(name) {
|
||||
var me = this;
|
||||
Ext.Ajax.request({
|
||||
method: 'GET',
|
||||
disableCaching: false,
|
||||
url: '../../../fhem?cmd=jsonlist&XHR=1',
|
||||
scope: me,
|
||||
success: function(response){
|
||||
me.setLoading(false);
|
||||
|
||||
var json = Ext.decode(response.responseText);
|
||||
|
||||
var devicejson;
|
||||
Ext.each(json.Results, function(result) {
|
||||
Ext.each(result.devices, function(device) {
|
||||
if (device.NAME === name) {
|
||||
devicejson = device;
|
||||
}
|
||||
});
|
||||
});
|
||||
if (devicejson && devicejson !== "") {
|
||||
me.updateControls(devicejson);
|
||||
me.processReadings(devicejson);
|
||||
} else {
|
||||
Ext.Msg.alert("Error", "Could not get any devicedata!");
|
||||
Ext.TaskManager.stopAll();
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
failure: function() {
|
||||
me.setLoading(false);
|
||||
Ext.Msg.alert("Error", "Could not get any devicedata!");
|
||||
Ext.TaskManager.stopAll();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
@ -1,727 +0,0 @@
|
||||
/**
|
||||
* The Panel containing the Line Charts
|
||||
*/
|
||||
Ext.define('FHEM.view.LineChartPanel', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias : 'widget.linechartpanel',
|
||||
requires: [
|
||||
'FHEM.store.ChartStore',
|
||||
'FHEM.store.DeviceStore',
|
||||
'FHEM.store.ReadingsStore',
|
||||
'FHEM.view.ChartGridPanel',
|
||||
'Ext.form.Panel',
|
||||
'Ext.form.field.Radio',
|
||||
'Ext.form.field.Date',
|
||||
'Ext.form.RadioGroup',
|
||||
'Ext.chart.Chart',
|
||||
'Ext.chart.axis.Numeric',
|
||||
'Ext.chart.axis.Time',
|
||||
'Ext.chart.series.Line'
|
||||
],
|
||||
|
||||
/**
|
||||
* generating getters and setters
|
||||
*/
|
||||
config: {
|
||||
/**
|
||||
* last max value of Y axis before zoom was applied
|
||||
*/
|
||||
lastYmax: null,
|
||||
|
||||
/**
|
||||
* last min value of Y axis before zoom was applied
|
||||
*/
|
||||
lastYmin: null,
|
||||
|
||||
/**
|
||||
* last max value of Y2 axis before zoom was applied
|
||||
*/
|
||||
lastY2max: null,
|
||||
|
||||
/**
|
||||
* last min value of Y2 axis before zoom was applied
|
||||
*/
|
||||
lastY2min: null,
|
||||
|
||||
/**
|
||||
* last max value of Y axis before zoom was applied
|
||||
*/
|
||||
lastXmax: null,
|
||||
|
||||
/**
|
||||
* last min value of Y axis before zoom was applied
|
||||
*/
|
||||
lastXmin: null,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
axiscounter: 0
|
||||
},
|
||||
|
||||
artifactSeries: [],
|
||||
|
||||
/**
|
||||
* the title
|
||||
*/
|
||||
title: 'Line Chart',
|
||||
|
||||
/**
|
||||
* init function
|
||||
*/
|
||||
initComponent: function(cfg) {
|
||||
|
||||
var me = this;
|
||||
|
||||
me.devicestore = Ext.create('FHEM.store.DeviceStore', {
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
noCache: false,
|
||||
method: 'POST',
|
||||
url: '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+""+getdevices&XHR=1',
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: true
|
||||
});
|
||||
|
||||
var chartSettingPanel = Ext.create('Ext.form.Panel', {
|
||||
title: 'Chart Settings - Click me to edit',
|
||||
name: 'chartformpanel',
|
||||
maxHeight: 345,
|
||||
autoScroll: true,
|
||||
collapsible: true,
|
||||
titleCollapse: true,
|
||||
animCollapse: false,
|
||||
items: [
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
title: 'Select data',
|
||||
name: 'axesfieldset',
|
||||
defaults: {
|
||||
margin: '0 10 10 10'
|
||||
},
|
||||
items: [] //get filled in own function
|
||||
},
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
layout: 'vbox',
|
||||
autoScroll: true,
|
||||
title: 'Select Timerange',
|
||||
defaults: {
|
||||
margin: '0 0 0 10'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
layout: 'hbox',
|
||||
autoScroll: true,
|
||||
border: false,
|
||||
defaults: {
|
||||
margin: '0 0 0 10'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
fieldLabel: 'Timerange',
|
||||
labelWidth: 60,
|
||||
name: 'rb',
|
||||
checked: false,
|
||||
allowBlank: true,
|
||||
inputValue: 'timerange',
|
||||
listeners: {
|
||||
change: function(rb, newval, oldval) {
|
||||
if (newval === false) {
|
||||
rb.up().down('datefield[name=starttimepicker]').setDisabled(true);
|
||||
rb.up().down('datefield[name=endtimepicker]').setDisabled(true);
|
||||
} else {
|
||||
rb.up().down('datefield[name=starttimepicker]').setDisabled(false);
|
||||
rb.up().down('datefield[name=endtimepicker]').setDisabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'datefield',
|
||||
name: 'starttimepicker',
|
||||
format: 'Y-m-d H:i:s',
|
||||
fieldLabel: 'Starttime',
|
||||
allowBlank: false,
|
||||
labelWidth: 70,
|
||||
value: Ext.Date.add(new Date(), Ext.Date.DAY, -1)
|
||||
},
|
||||
{
|
||||
xtype: 'datefield',
|
||||
name: 'endtimepicker',
|
||||
format: 'Y-m-d H:i:s',
|
||||
fieldLabel: 'Endtime',
|
||||
allowBlank: false,
|
||||
labelWidth: 70,
|
||||
value: new Date()
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
layout: 'hbox',
|
||||
autoScroll: true,
|
||||
border: false,
|
||||
defaults: {
|
||||
margin: '0 0 0 10'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'radiogroup',
|
||||
name: 'dynamictime',
|
||||
fieldLabel: 'or select a dynamic time',
|
||||
labelWidth: 140,
|
||||
width: 900,
|
||||
allowBlank: true,
|
||||
defaults: {
|
||||
padding: "0px 0px 0px 18px"
|
||||
},
|
||||
items: [
|
||||
{ fieldLabel: 'yearly', name: 'rb', inputValue: 'year', labelWidth: 38 },
|
||||
{ fieldLabel: 'monthly', name: 'rb', inputValue: 'month', labelWidth: 44 },
|
||||
{ fieldLabel: 'weekly', name: 'rb', inputValue: 'week', labelWidth: 40 },
|
||||
{ fieldLabel: 'daily', name: 'rb', inputValue: 'day', checked: true, labelWidth: 31 },
|
||||
{ fieldLabel: 'hourly', name: 'rb', inputValue: 'hour', labelWidth: 38 },
|
||||
{ fieldLabel: 'last hour', name: 'rb', inputValue: 'lasthour', labelWidth: 50 },
|
||||
{ fieldLabel: 'last 24h', name: 'rb', inputValue: 'last24h', labelWidth: 48 },
|
||||
{ fieldLabel: 'last 7 days', name: 'rb', inputValue: 'last7days', labelWidth: 65 },
|
||||
{ fieldLabel: 'last month', name: 'rb', inputValue: 'lastmonth', labelWidth: 65 }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
xtype: 'fieldset',
|
||||
layout: 'hbox',
|
||||
autoScroll: true,
|
||||
title: 'Axis Configuration',
|
||||
defaults: {
|
||||
margin: '0 0 0 10'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'radiogroup',
|
||||
name: 'leftaxisconfiguration',
|
||||
fieldLabel: 'Left Axis Scalerange',
|
||||
labelWidth: 120,
|
||||
allowBlank: true,
|
||||
width: 310,
|
||||
defaults: {
|
||||
labelWidth: 55,
|
||||
padding: "0 25px 0 0",
|
||||
checked: false
|
||||
},
|
||||
items: [
|
||||
{ fieldLabel: 'automatic', name: 'rb1', inputValue: 'automatic', checked: true },
|
||||
{ fieldLabel: 'manual', name: 'rb1', inputValue: 'manual' }
|
||||
],
|
||||
listeners: {
|
||||
change: function(rb1, newval, oldval) {
|
||||
if (newval.rb1 === "automatic") {
|
||||
rb1.up().down('numberfield[name=leftaxisminimum]').setDisabled(true);
|
||||
rb1.up().down('numberfield[name=leftaxismaximum]').setDisabled(true);
|
||||
} else {
|
||||
rb1.up().down('numberfield[name=leftaxisminimum]').setDisabled(false);
|
||||
rb1.up().down('numberfield[name=leftaxismaximum]').setDisabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: 'Minimum',
|
||||
name: 'leftaxisminimum',
|
||||
allowBlank: false,
|
||||
disabled: true,
|
||||
labelWidth: 60,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: 'Maximum',
|
||||
name: 'leftaxismaximum',
|
||||
allowBlank: false,
|
||||
disabled: true,
|
||||
labelWidth: 60,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
xtype: 'radiogroup',
|
||||
name: 'rightaxisconfiguration',
|
||||
fieldLabel: 'Right Axis Scalerange',
|
||||
labelWidth: 130,
|
||||
width: 310,
|
||||
allowBlank: true,
|
||||
defaults: {
|
||||
labelWidth: 55,
|
||||
padding: "0 25px 0 0",
|
||||
checked: false
|
||||
},
|
||||
items: [
|
||||
{ fieldLabel: 'automatic', name: 'rb2', inputValue: 'automatic', checked: true },
|
||||
{ fieldLabel: 'manual', name: 'rb2', inputValue: 'manual' }
|
||||
],
|
||||
listeners: {
|
||||
change: function(rb2, newval, oldval) {
|
||||
if (newval.rb2 === "automatic") {
|
||||
rb2.up().down('numberfield[name=rightaxisminimum]').setDisabled(true);
|
||||
rb2.up().down('numberfield[name=rightaxismaximum]').setDisabled(true);
|
||||
} else {
|
||||
rb2.up().down('numberfield[name=rightaxisminimum]').setDisabled(false);
|
||||
rb2.up().down('numberfield[name=rightaxismaximum]').setDisabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: 'Minimum',
|
||||
name: 'rightaxisminimum',
|
||||
allowBlank: false,
|
||||
disabled: true,
|
||||
labelWidth: 60,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: 'Maximum',
|
||||
name: 'rightaxismaximum',
|
||||
allowBlank: false,
|
||||
disabled: true,
|
||||
labelWidth: 60,
|
||||
width: 120
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
layout: 'hbox',
|
||||
autoScroll: true,
|
||||
title: 'Axis Title Configuration',
|
||||
defaults: {
|
||||
margin: '0 0 5 10'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Left Axis Title',
|
||||
name: 'leftaxistitle',
|
||||
allowBlank: true,
|
||||
labelWidth: 100,
|
||||
width: 340
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Right Axis Title',
|
||||
name: 'rightaxistitle',
|
||||
allowBlank: true,
|
||||
labelWidth: 100,
|
||||
width: 340
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
layout: 'hbox',
|
||||
autoScroll: true,
|
||||
defaults: {
|
||||
margin: '10 10 10 10'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 100,
|
||||
text: 'Show Chart',
|
||||
name: 'requestchartdata',
|
||||
icon: 'app/resources/icons/accept.png'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 100,
|
||||
text: 'Save Chart',
|
||||
name: 'savechartdata',
|
||||
icon: 'app/resources/icons/database_save.png'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 100,
|
||||
text: 'Reset Fields',
|
||||
name: 'resetchartform',
|
||||
icon: 'app/resources/icons/delete.png'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 110,
|
||||
text: 'Add another Y-Axis',
|
||||
name: 'addyaxisbtn',
|
||||
handler: function(btn) {
|
||||
me.createNewYAxis();
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 90,
|
||||
text: 'Add Baseline',
|
||||
name: 'addbaselinebtn',
|
||||
handler: function(btn) {
|
||||
me.createNewBaseLineFields(btn);
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'radio',
|
||||
width: 160,
|
||||
fieldLabel: 'Generalization',
|
||||
boxLabel: 'active',
|
||||
name: 'generalization',
|
||||
listeners: {
|
||||
change: function(radio, state) {
|
||||
if (state) {
|
||||
radio.up().down('combobox[name=genfactor]').setDisabled(false);
|
||||
} else {
|
||||
radio.up().down('combobox[name=genfactor]').setDisabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'radio',
|
||||
width: 80,
|
||||
boxLabel: 'disabled',
|
||||
checked: true,
|
||||
name: 'generalization'
|
||||
},
|
||||
{
|
||||
xtype: 'combo',
|
||||
width: 120,
|
||||
name: 'genfactor',
|
||||
disabled: true,
|
||||
fieldLabel: 'Factor',
|
||||
labelWidth: 50,
|
||||
store: Ext.create('Ext.data.Store', {
|
||||
fields: ['displayval', 'val'],
|
||||
data : [
|
||||
{"displayval": "10%", "val":"10"},
|
||||
{"displayval": "20%", "val":"20"},
|
||||
{"displayval": "30%", "val":"30"},
|
||||
{"displayval": "40%", "val":"40"},
|
||||
{"displayval": "50%", "val":"50"},
|
||||
{"displayval": "60%", "val":"60"},
|
||||
{"displayval": "70%", "val":"70"},
|
||||
{"displayval": "80%", "val":"80"},
|
||||
{"displayval": "90%", "val":"90"}
|
||||
]
|
||||
}),
|
||||
fields: ['displayval', 'val'],
|
||||
displayField: 'displayval',
|
||||
valueField: 'val',
|
||||
value: '30'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
//add the first yaxis line
|
||||
me.createNewYAxis();
|
||||
|
||||
me.items = [
|
||||
chartSettingPanel
|
||||
];
|
||||
me.callParent(arguments);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* create a new fieldset for a new chart y axis
|
||||
*/
|
||||
createNewYAxis: function() {
|
||||
|
||||
var me = this;
|
||||
|
||||
me.setAxiscounter(me.getAxiscounter() + 1);
|
||||
|
||||
var components =
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
name: 'singlerowfieldset',
|
||||
layout: 'hbox',
|
||||
autoScroll: true,
|
||||
defaults: {
|
||||
margin: '5 5 5 0'
|
||||
},
|
||||
items:
|
||||
[
|
||||
{
|
||||
xtype: 'radiogroup',
|
||||
name: 'datasourceradio',
|
||||
rowCount: me.getAxiscounter(),
|
||||
allowBlank: false,
|
||||
defaults: {
|
||||
labelWidth: 40,
|
||||
padding: "0 5px 0 0"
|
||||
},
|
||||
items: [
|
||||
{
|
||||
fieldLabel: 'DbLog',
|
||||
name: 'logtype' + me.getAxiscounter(),
|
||||
inputValue: 'dblog',
|
||||
checked: true,
|
||||
disabled: !FHEM.dblogname
|
||||
},
|
||||
{
|
||||
fieldLabel: 'FileLog',
|
||||
name: 'logtype' + me.getAxiscounter(),
|
||||
inputValue: 'filelog',
|
||||
checked: false,
|
||||
disabled: !FHEM.filelogs
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'combobox',
|
||||
name: 'devicecombo',
|
||||
fieldLabel: 'Select Device',
|
||||
labelWidth: 90,
|
||||
store: me.devicestore,
|
||||
triggerAction: 'all',
|
||||
allowBlank: false,
|
||||
displayField: 'DEVICE',
|
||||
valueField: 'DEVICE',
|
||||
listeners: {
|
||||
select: function(combo) {
|
||||
|
||||
var device = combo.getValue(),
|
||||
readingscombo = combo.up().down('combobox[name=yaxiscombo]'),
|
||||
readingsstore = readingscombo.getStore();
|
||||
|
||||
if (readingsstore && readingsstore.queryMode !== 'local') {
|
||||
var readingsproxy = readingsstore.getProxy();
|
||||
readingsproxy.url = '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+' + device + '+getreadings&XHR=1';
|
||||
readingsstore.load();
|
||||
}
|
||||
readingscombo.setDisabled(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'combobox',
|
||||
name: 'yaxiscombo',
|
||||
fieldLabel: 'Select Y-Axis',
|
||||
allowBlank: false,
|
||||
disabled: true,
|
||||
labelWidth: 90,
|
||||
inputWidth: 110,
|
||||
store: Ext.create('FHEM.store.ReadingsStore', {
|
||||
queryMode: 'remote',
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
method: 'POST',
|
||||
url: '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+-+getreadings&XHR=1',
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: false
|
||||
}),
|
||||
displayField: 'READING',
|
||||
valueField: 'READING'
|
||||
},
|
||||
{
|
||||
xtype: 'combobox',
|
||||
name: 'yaxiscolorcombo',
|
||||
fieldLabel: 'Y-Color',
|
||||
labelWidth: 50,
|
||||
inputWidth: 70,
|
||||
store: Ext.create('Ext.data.Store', {
|
||||
fields: ['name', 'value'],
|
||||
data : [
|
||||
{'name':'Blue','value':'#2F40FA'},
|
||||
{'name':'Green', 'value':'#46E01B'},
|
||||
{'name':'Orange','value':'#F0A800'},
|
||||
{'name':'Red','value':'#E0321B'},
|
||||
{'name':'Yellow','value':'#F5ED16'}
|
||||
]
|
||||
}),
|
||||
displayField: 'name',
|
||||
valueField: 'value',
|
||||
value: '#2F40FA'
|
||||
},
|
||||
{
|
||||
xtype: 'checkboxfield',
|
||||
name: 'yaxisfillcheck',
|
||||
boxLabel: 'Fill'
|
||||
},
|
||||
{
|
||||
xtype: 'checkboxfield',
|
||||
name: 'yaxisstepcheck',
|
||||
boxLabel: 'Steps',
|
||||
tooltip: 'Check, if the chart should be shown with steps instead of a linear Line'
|
||||
},
|
||||
{
|
||||
xtype: 'radiogroup',
|
||||
name: 'axisside',
|
||||
allowBlank: false,
|
||||
border: true,
|
||||
defaults: {
|
||||
padding: "0 15px 0 0",
|
||||
checked: false
|
||||
},
|
||||
items: [
|
||||
{ labelWidth: 50, fieldLabel: 'Left Axis', name: 'rbc' + me.getAxiscounter(), inputValue: 'left', checked: true },
|
||||
{ labelWidth: 60, fieldLabel: 'Right Axis', name: 'rbc' + me.getAxiscounter(), inputValue: 'right' }
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'combobox',
|
||||
name: 'yaxisstatisticscombo',
|
||||
fieldLabel: 'Statistics',
|
||||
labelWidth: 70,
|
||||
inputWidth: 120,
|
||||
store: Ext.create('Ext.data.Store', {
|
||||
fields: ['name', 'value'],
|
||||
data : [
|
||||
{'name':'None','value':'none'},
|
||||
{'name':'Hour Sum', 'value':'hoursum'},
|
||||
{'name':'Hour Average', 'value':'houraverage'},
|
||||
{'name':'Hour Min','value':'hourmin'},
|
||||
{'name':'Hour Max','value':'hourmax'},
|
||||
{'name':'Hour Count','value':'hourcount'},
|
||||
{'name':'Day Sum', 'value':'daysum'},
|
||||
{'name':'Day Average', 'value':'dayaverage'},
|
||||
{'name':'Day Min','value':'daymin'},
|
||||
{'name':'Day Max','value':'daymax'},
|
||||
{'name':'Day Count','value':'daycount'},
|
||||
{'name':'Week Sum', 'value':'weeksum'},
|
||||
{'name':'Week Average', 'value':'weekaverage'},
|
||||
{'name':'Week Min','value':'weekmin'},
|
||||
{'name':'Week Max','value':'weekmax'},
|
||||
{'name':'Week Count','value':'weekcount'},
|
||||
{'name':'Month Sum', 'value':'monthsum'},
|
||||
{'name':'Month Average', 'value':'monthaverage'},
|
||||
{'name':'Month Min','value':'monthmin'},
|
||||
{'name':'Month Max','value':'monthmax'},
|
||||
{'name':'Month Count','value':'monthcount'},
|
||||
{'name':'Year Sum', 'value':'yearsum'},
|
||||
{'name':'Year Average', 'value':'yearaverage'},
|
||||
{'name':'Year Min','value':'yearmin'},
|
||||
{'name':'Year Max','value':'yearmax'},
|
||||
{'name':'Year Count','value':'yearcount'}
|
||||
]
|
||||
}),
|
||||
displayField: 'name',
|
||||
valueField: 'value',
|
||||
value: 'none'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 60,
|
||||
text: 'Remove',
|
||||
name: 'removerowbtn',
|
||||
handler: function(btn) {
|
||||
me.removeRow(btn);
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
Ext.ComponentQuery.query('fieldset[name=axesfieldset]')[0].add(components);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
createNewBaseLineFields: function(btn) {
|
||||
var me = this;
|
||||
|
||||
var itemsToAdd = [
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
name: 'baselineowfieldset',
|
||||
layout: 'hbox',
|
||||
autoScroll: true,
|
||||
defaults: {
|
||||
margin: '5 5 5 0'
|
||||
},
|
||||
items:
|
||||
[
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: 'Startvalue',
|
||||
name: 'basestart',
|
||||
allowBlank: false,
|
||||
labelWidth: 60,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: 'Endvalue',
|
||||
name: 'baseend',
|
||||
allowBlank: false,
|
||||
labelWidth: 60,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
xtype: 'combobox',
|
||||
name: 'baselinecolorcombo',
|
||||
fieldLabel: 'Baseline Color',
|
||||
labelWidth: 100,
|
||||
inputWidth: 70,
|
||||
store: Ext.create('Ext.data.Store', {
|
||||
fields: ['name', 'value'],
|
||||
data : [
|
||||
{'name':'Blue','value':'#2F40FA'},
|
||||
{'name':'Green', 'value':'#46E01B'},
|
||||
{'name':'Orange','value':'#F0A800'},
|
||||
{'name':'Red','value':'#E0321B'},
|
||||
{'name':'Yellow','value':'#F5ED16'}
|
||||
]
|
||||
}),
|
||||
displayField: 'name',
|
||||
valueField: 'value',
|
||||
value: '#46E01B'
|
||||
},
|
||||
{
|
||||
xtype: 'checkboxfield',
|
||||
name: 'baselinefillcheck',
|
||||
boxLabel: 'Fill'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 60,
|
||||
text: 'Remove',
|
||||
name: 'removebaselinebtn',
|
||||
handler: function(btn) {
|
||||
me.removeRow(btn);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
Ext.ComponentQuery.query('fieldset[name=axesfieldset]')[0].add(itemsToAdd);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* remove the current chart configuration row
|
||||
*/
|
||||
removeRow: function(btn) {
|
||||
var me = this;
|
||||
if (btn.name === "removerowbtn") {
|
||||
me.setAxiscounter(me.getAxiscounter() - 1);
|
||||
}
|
||||
btn.up().destroy();
|
||||
}
|
||||
});
|
@ -1,214 +0,0 @@
|
||||
/**
|
||||
* The GridPanel containing a table with rawdata from Database
|
||||
*/
|
||||
Ext.define('FHEM.view.TableDataGridPanel', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias : 'widget.tabledatagridpanel',
|
||||
requires: [
|
||||
'FHEM.store.TableDataStore'
|
||||
],
|
||||
|
||||
title: 'Table Data',
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
initComponent: function() {
|
||||
|
||||
var me = this;
|
||||
|
||||
me.callParent(arguments);
|
||||
|
||||
me.tablestore = Ext.create('FHEM.store.TableDataStore');
|
||||
|
||||
me.devicestore = Ext.create('FHEM.store.DeviceStore', {
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
noCache: false,
|
||||
method: 'POST',
|
||||
url: '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+""+getdevices&XHR=1',
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: false
|
||||
});
|
||||
|
||||
me.on("afterlayout", function() {
|
||||
|
||||
if (!FHEM.dblogname) {
|
||||
Ext.Msg.alert("Error", "This function is currently only available to users of DbLog!");
|
||||
}
|
||||
|
||||
me.devicestore.load();
|
||||
|
||||
me.add(
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
title: 'Configure Database Query',
|
||||
maxHeight: 165,
|
||||
items: [
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
layout: 'column',
|
||||
defaults: {
|
||||
margin: '5 5 5 10'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'combobox',
|
||||
name: 'tddevicecombo',
|
||||
fieldLabel: 'Select Device',
|
||||
labelWidth: 90,
|
||||
store: me.devicestore,
|
||||
allowBlank: false,
|
||||
queryMode: 'local',
|
||||
displayField: 'DEVICE',
|
||||
valueField: 'DEVICE',
|
||||
listeners: {
|
||||
select: function(combo) {
|
||||
var device = combo.getValue(),
|
||||
readingscombo = combo.up().down('combobox[name=tdreadingscombo]'),
|
||||
readingsstore = readingscombo.getStore(),
|
||||
readingsproxy = readingsstore.getProxy();
|
||||
|
||||
readingsproxy.url = '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+' + device + '+getreadings&XHR=1';
|
||||
readingsstore.load();
|
||||
readingscombo.setDisabled(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'combobox',
|
||||
name: 'tdreadingscombo',
|
||||
fieldLabel: 'Select Reading',
|
||||
allowBlank: false,
|
||||
disabled: true,
|
||||
labelWidth: 90,
|
||||
inputWidth: 110,
|
||||
store: Ext.create('FHEM.store.ReadingsStore', {
|
||||
proxy: {
|
||||
type: 'ajax',
|
||||
method: 'POST',
|
||||
url: '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+-+getreadings&XHR=1',
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: 'data',
|
||||
totalProperty: 'totalCount'
|
||||
}
|
||||
},
|
||||
autoLoad: false
|
||||
}),
|
||||
displayField: 'READING',
|
||||
valueField: 'READING'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'fieldset',
|
||||
layout: 'column',
|
||||
title: 'Select Timerange',
|
||||
defaults: {
|
||||
margin: '0 0 0 10'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
fieldLabel: 'Timerange',
|
||||
labelWidth: 60,
|
||||
name: 'tdrb',
|
||||
checked: true,
|
||||
inputValue: 'timerange',
|
||||
listeners: {
|
||||
change: function(tdrb, newval, oldval) {
|
||||
if (newval === false) {
|
||||
tdrb.up().down('datefield[name=tdstarttimepicker]').setDisabled(true);
|
||||
tdrb.up().down('datefield[name=tdendtimepicker]').setDisabled(true);
|
||||
} else {
|
||||
tdrb.up().down('datefield[name=tdstarttimepicker]').setDisabled(false);
|
||||
tdrb.up().down('datefield[name=tdendtimepicker]').setDisabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'datefield',
|
||||
name: 'tdstarttimepicker',
|
||||
format: 'Y-m-d H:i:s',
|
||||
fieldLabel: 'Starttime',
|
||||
allowBlank: false,
|
||||
labelWidth: 70
|
||||
},
|
||||
{
|
||||
xtype: 'datefield',
|
||||
name: 'tdendtimepicker',
|
||||
format: 'Y-m-d H:i:s',
|
||||
fieldLabel: 'Endtime',
|
||||
allowBlank: false,
|
||||
labelWidth: 70
|
||||
},
|
||||
{
|
||||
xtype: 'radiogroup',
|
||||
name: 'tddynamictime',
|
||||
fieldLabel: 'or select a dynamic time',
|
||||
labelWidth: 140,
|
||||
allowBlank: true,
|
||||
defaults: {
|
||||
labelWidth: 42,
|
||||
padding: "0 25px 0 0",
|
||||
checked: false
|
||||
},
|
||||
items: [
|
||||
{ fieldLabel: 'yearly', name: 'tdrb', inputValue: 'year' },
|
||||
{ fieldLabel: 'monthly', name: 'tdrb', inputValue: 'month' },
|
||||
{ fieldLabel: 'weekly', name: 'tdrb', inputValue: 'week' },
|
||||
{ fieldLabel: 'daily', name: 'tdrb', inputValue: 'day' },
|
||||
{ fieldLabel: 'hourly', name: 'tdrb', inputValue: 'hour' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
text: 'Apply Filter',
|
||||
name: 'applytablefilter',
|
||||
width: '120'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'gridpanel',
|
||||
maxHeight: me.up().getHeight() - 290,
|
||||
name: 'tabledatagridpanel',
|
||||
store: me.tablestore,
|
||||
width: '100%',
|
||||
loadMask: true,
|
||||
selModel: {
|
||||
pruneRemoved: false
|
||||
},
|
||||
multiSelect: true,
|
||||
viewConfig: {
|
||||
trackOver: false
|
||||
},
|
||||
verticalScroller:{
|
||||
//trailingBufferZone: 20, // Keep 200 records buffered in memory behind scroll
|
||||
//leadingBufferZone: 50 // Keep 5000 records buffered in memory ahead of scroll
|
||||
},
|
||||
columns: [
|
||||
{ text: 'TIMESTAMP', dataIndex: 'TIMESTAMP', width: 240, sortable: false },
|
||||
{ text: 'DEVICE', dataIndex: 'DEVICE', width: '10%', sortable: false },
|
||||
{ text: 'TYPE', dataIndex: 'TYPE', width: '7%', sortable: false },
|
||||
{ text: 'EVENT', dataIndex: 'EVENT', width: '20%', sortable: false },
|
||||
{ text: 'READING', dataIndex: 'READING', width: '12%', sortable: false },
|
||||
{ text: 'VALUE', dataIndex: 'VALUE', width: '20%', sortable: false },
|
||||
{ text: 'UNIT', dataIndex: 'UNIT', width: '5%', sortable: false }
|
||||
]
|
||||
}
|
||||
);
|
||||
}, me, {single: true});
|
||||
|
||||
}
|
||||
|
||||
});
|
@ -1,228 +0,0 @@
|
||||
/**
|
||||
* The main application viewport, which displays the whole application
|
||||
* @extends Ext.Viewport
|
||||
*/
|
||||
Ext.define('FHEM.view.Viewport', {
|
||||
extend: 'Ext.Viewport',
|
||||
name: 'mainviewport',
|
||||
layout: 'border',
|
||||
requires: [
|
||||
'FHEM.view.LineChartPanel',
|
||||
'FHEM.view.TableDataGridPanel',
|
||||
'FHEM.controller.ChartController',
|
||||
'FHEM.store.SavedChartsStore',
|
||||
'Ext.layout.container.Border',
|
||||
'Ext.form.field.Text',
|
||||
'Ext.layout.container.Accordion',
|
||||
'Ext.tree.Panel',
|
||||
'Ext.grid.Panel',
|
||||
'Ext.grid.Column',
|
||||
'Ext.grid.column.Action',
|
||||
'Ext.draw.Text'
|
||||
],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
Ext.apply(me, {
|
||||
items: [
|
||||
{
|
||||
region: 'north',
|
||||
height: 45,
|
||||
layout: 'hbox',
|
||||
items: [
|
||||
{
|
||||
xtype: 'container',
|
||||
html: 'FHEM Webfrontend',
|
||||
width: '25%',
|
||||
padding: '15px 0 0 5px',
|
||||
border: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'commandfield',
|
||||
width: '30%',
|
||||
padding: '10px 0 0 0',
|
||||
fieldLabel: 'Send Commands',
|
||||
border: false
|
||||
},
|
||||
{
|
||||
xtype: 'panel',
|
||||
border: false,
|
||||
width: '25%',
|
||||
items: [
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 80,
|
||||
margin: '10px 0 0 5px',
|
||||
text: 'Execute',
|
||||
name: 'executecommand',
|
||||
icon: 'app/resources/icons/arrow_left.png'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 110,
|
||||
margin: '10px 0 0 5px',
|
||||
text: 'Save to Config',
|
||||
name: 'saveconfig',
|
||||
icon: 'app/resources/icons/database_save.png'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'panel',
|
||||
border: false,
|
||||
width: '20%',
|
||||
items: [
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 75,
|
||||
margin: '10px 5px 0 5px',
|
||||
text: 'Shutdown',
|
||||
name: 'shutdownfhem',
|
||||
tooltip: 'Shutdown FHEM',
|
||||
icon: 'app/resources/icons/stop.png'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
width: 70,
|
||||
margin: '10px 5px 0 5px',
|
||||
text: 'Restart',
|
||||
name: 'restartfhem',
|
||||
tooltip: 'Restart FHEM',
|
||||
icon: 'app/resources/icons/database_refresh.png'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
region: 'west',
|
||||
title: 'Navigation',
|
||||
width: 300,
|
||||
autoScroll: true,
|
||||
resizable: true,
|
||||
xtype: 'panel',
|
||||
name: 'westaccordionpanel',
|
||||
layout: {
|
||||
type: 'accordion'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
title: 'FHEM',
|
||||
name: 'fhemaccordion',
|
||||
collapsed: true,
|
||||
bodyPadding: '5 5 5 5',
|
||||
html: 'You can see and use the original FHEM Frontend here. <br> If you make changes to your config, it may be neccessary to reload this page to get the updated information.'
|
||||
},
|
||||
{
|
||||
xtype: 'treepanel',
|
||||
title: 'Charts / Devices / Rooms',
|
||||
name: 'maintreepanel',
|
||||
collapsed: false,
|
||||
border: false,
|
||||
rootVisible: false,
|
||||
viewConfig: {
|
||||
plugins: { ptype: 'treeviewdragdrop' }
|
||||
},
|
||||
root: {
|
||||
"text": "Root",
|
||||
"expanded":
|
||||
"true",
|
||||
"children": []
|
||||
},
|
||||
tbar: [
|
||||
{
|
||||
xtype: 'button',
|
||||
name: 'unsortedtree',
|
||||
toggleGroup: 'treeorder',
|
||||
allowDepress: false,
|
||||
text: 'Unsorted'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
name: 'sortedtree',
|
||||
toggleGroup: 'treeorder',
|
||||
allowDepress: false,
|
||||
text: 'Order by Room',
|
||||
pressed: true
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
'itemcontextmenu': function(scope, rec, item, index, e, eOpts) {
|
||||
e.preventDefault();
|
||||
|
||||
if (rec.raw.data.TYPE &&
|
||||
(rec.raw.data.TYPE === "savedchart" || rec.raw.data.TYPE === "savedfilelogchart")) {
|
||||
var menu = Ext.ComponentQuery.query('menu[id=treecontextmenu]')[0];
|
||||
if (menu) {
|
||||
menu.destroy();
|
||||
}
|
||||
Ext.create('Ext.menu.Menu', {
|
||||
id: 'treecontextmenu',
|
||||
items: [
|
||||
{
|
||||
text: 'Delete Chart',
|
||||
name: 'deletechartfromcontext',
|
||||
record: rec
|
||||
}, '-', {
|
||||
text: 'Rename Chart',
|
||||
name: 'renamechartfromcontext',
|
||||
record: rec
|
||||
}
|
||||
]
|
||||
}).showAt(e.xy);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Database Tables',
|
||||
name: 'tabledataaccordionpanel',
|
||||
autoScroll: true,
|
||||
bodyPadding: '5 5 5 5',
|
||||
html: 'You can search your database here. <br> Specify your queries by selecting a specific device, reading and timerange.'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
region: 'south',
|
||||
title: 'Status',
|
||||
collapsible: true,
|
||||
items: [{
|
||||
xtype: 'text',
|
||||
name: 'statustextfield',
|
||||
text: 'Status...'
|
||||
}],
|
||||
split: true,
|
||||
height: 50,
|
||||
minHeight: 30
|
||||
},
|
||||
{
|
||||
region: 'center',
|
||||
title: 'Welcome',
|
||||
layout: 'hbox',
|
||||
bodyStyle: 'padding:5px 5px 0',
|
||||
items: [
|
||||
{
|
||||
xtype: 'image',
|
||||
src: '../../fhem/images/default/fhemicon.png',
|
||||
height: 132,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
xtype: 'text',
|
||||
name: 'statustextfield',
|
||||
padding: '50 0 0 20',
|
||||
width: 400,
|
||||
height: 130,
|
||||
html: '<br>Welcome to the new FHEM Frontend.<br>For Informations, Problems and discussion, visit the <a href="http://forum.fhem.de/index.php?t=msg&th=10439&start=0&rid=0">FHEM Forums</a>'
|
||||
}
|
||||
],
|
||||
height: '100%'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent(arguments);
|
||||
}
|
||||
});
|
@ -1,32 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Frontend</title>
|
||||
|
||||
<style type="text/css">
|
||||
#loading-overlay {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 50%;
|
||||
left: 43%;
|
||||
}
|
||||
</style>
|
||||
<p class="loader">
|
||||
<img src="app/resources/loading.png" alt="Please wait..." height="31" width="248" id="loading-overlay">
|
||||
</p>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="lib/ext-4.2.0.663/ext-theme-gray-all.css" />
|
||||
<link rel="stylesheet" type="text/css" href="app/resources/application.css" />
|
||||
<script type="text/javascript" src="lib/ext-4.2.0.663/ext-all.js"></script>
|
||||
<script type="text/javascript" src="app/userconfig.js"></script>
|
||||
<script type="text/javascript" src="app/filelogcharts.js"></script>
|
||||
<script type="text/javascript" src="app/app.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1010 B |
Before Width: | Height: | Size: 1005 B |
Before Width: | Height: | Size: 810 B |
Before Width: | Height: | Size: 810 B |
Before Width: | Height: | Size: 810 B |
Before Width: | Height: | Size: 810 B |
Before Width: | Height: | Size: 851 B |
Before Width: | Height: | Size: 839 B |
Before Width: | Height: | Size: 828 B |
Before Width: | Height: | Size: 870 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 861 B |
Before Width: | Height: | Size: 846 B |
Before Width: | Height: | Size: 898 B |
Before Width: | Height: | Size: 937 B |
Before Width: | Height: | Size: 937 B |
Before Width: | Height: | Size: 96 B |
Before Width: | Height: | Size: 116 B |
Before Width: | Height: | Size: 76 B |
Before Width: | Height: | Size: 863 B |
Before Width: | Height: | Size: 137 B |
Before Width: | Height: | Size: 139 B |
Before Width: | Height: | Size: 151 B |
Before Width: | Height: | Size: 937 B |
Before Width: | Height: | Size: 1001 B |
Before Width: | Height: | Size: 949 B |
Before Width: | Height: | Size: 1016 B |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 945 B |
Before Width: | Height: | Size: 929 B |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 996 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 747 B |
Before Width: | Height: | Size: 743 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 819 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 121 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 136 B |
Before Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 962 B |
Before Width: | Height: | Size: 299 B |