2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-15 22:26:04 +00:00

final structure cleanup, sorry for inconvenience ...

git-svn-id: https://svn.fhem.de/fhem/trunk@4483 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
johannnes 2013-12-27 16:51:17 +00:00
parent 4798248a8d
commit e85b0c84c3
264 changed files with 1 additions and 5520 deletions

View File

@ -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

View File

@ -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");
}
});
}
});

File diff suppressed because it is too large Load Diff

View File

@ -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();
}
});

View File

@ -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();
}
}
});

View File

@ -1 +0,0 @@
FHEM.filelogcharts = [];

View File

@ -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);
}
}
});

View File

@ -1,12 +0,0 @@
/**
* Model for Devices
*/
Ext.define('FHEM.model.DeviceModel', {
extend: 'Ext.data.Model',
fields: [
{
name: 'DEVICE',
type: 'text'
}
]
});

View File

@ -1,12 +0,0 @@
/**
* Model for Readings
*/
Ext.define('FHEM.model.ReadingsModel', {
extend: 'Ext.data.Model',
fields: [
{
name: 'READING',
type: 'text'
}
]
});

View File

@ -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'
}
]
});

View File

@ -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'
}
]
});

View File

@ -1,3 +0,0 @@
.x-tree-icon.x-tree-icon-leaf.x-tree-icon-leaf-chart {
background-image: url(icons/chart_bar.png);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 B

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -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
});

View File

@ -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
});

View File

@ -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
});

View File

@ -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
});

View File

@ -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
});

View File

@ -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"
}
};

View File

@ -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);
}
});

View File

@ -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();
}
});
}
});

View File

@ -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();
}
});

View File

@ -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});
}
});

View File

@ -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);
}
});

View File

@ -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>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 949 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

Some files were not shown because too many files have changed in this diff Show More