diff --git a/src/webui/static/app/servicemapper.js b/src/webui/static/app/servicemapper.js
index f4e8873d..26b2857e 100644
--- a/src/webui/static/app/servicemapper.js
+++ b/src/webui/static/app/servicemapper.js
@@ -4,10 +4,8 @@
tvheadend.service_mapper_status_panel = null;
-tvheadend.service_mapper_status = function()
+tvheadend.service_mapper_status = function(panel, index)
{
- var panel;
-
/* Fields */
var ok = new Ext.form.Label({
fieldLabel: 'Mapped',
@@ -31,7 +29,7 @@ tvheadend.service_mapper_status = function()
});
/* Panel */
- panel = new Ext.FormPanel({
+ var mpanel = new Ext.FormPanel({
method: 'get',
title: 'Service Mapper',
frame: true,
@@ -72,9 +70,9 @@ tvheadend.service_mapper_status = function()
}
});
- tvheadend.service_mapper_status_panel = panel;
- return panel;
-};
+ tvheadend.service_mapper_status_panel = mpanel;
+ tvheadend.paneladd(panel, mpanel, index);
+}
/*
* Start mapping
@@ -182,4 +180,4 @@ tvheadend.service_mapper = function(t, e, store, select)
});
win.show();
-};
+}
diff --git a/src/webui/static/app/status.js b/src/webui/static/app/status.js
index ef77fbc4..13caa2b9 100644
--- a/src/webui/static/app/status.js
+++ b/src/webui/static/app/status.js
@@ -1,44 +1,19 @@
/**
*
*/
-tvheadend.status_subs = function() {
-
- tvheadend.subsStore = new Ext.data.JsonStore({
- root: 'entries',
- totalProperty: 'totalCount',
- fields: [
- { name: 'id' },
- { name: 'hostname' },
- { name: 'username' },
- { name: 'title' },
- { name: 'channel' },
- { name: 'service' },
- { name: 'state' },
- { name: 'errors' },
- { name: 'in' },
- { name: 'out' },
- {
- name: 'start',
- type: 'date',
- dateFormat: 'U' /* unix time */
- }
- ],
- url: 'api/status/subscriptions',
- autoLoad: true,
- id: 'id'
- });
-
-
-
- tvheadend.comet.on('subscriptions', function(m) {
+tvheadend.status_subs = function(panel, index)
+{
+ var subs = null;
+ var store = null;
+ function update(m) {
if (m.reload != null)
- tvheadend.subsStore.reload();
+ store.reload();
if (m.updateEntry != null) {
- r = tvheadend.subsStore.getById(m.id);
+ r = store.getById(m.id);
if (typeof r === 'undefined') {
- tvheadend.subsStore.reload();
+ store.reload();
return;
}
@@ -49,379 +24,495 @@ tvheadend.status_subs = function() {
r.data.in = m.in;
r.data.out = m.out;
- tvheadend.subsStore.afterEdit(r);
- tvheadend.subsStore.fireEvent('updated', tvheadend.subsStore, r,
- Ext.data.Record.COMMIT);
+ store.afterEdit(r);
+ store.fireEvent('updated', store, r, Ext.data.Record.COMMIT);
}
- });
-
- function renderDate(value) {
- var dt = new Date(value);
- return dt.format('D j M H:i');
}
- function renderBw(value, item, store) {
- var txt = parseInt(value / 125);
- var href = 'javascript:tvheadend.subscription_bw_monitor(' + store.id + ');';
- return '' + txt + '';
+ function builder() {
+ if (subs)
+ return;
+
+ store = new Ext.data.JsonStore({
+ root: 'entries',
+ totalProperty: 'totalCount',
+ fields: [
+ { name: 'id' },
+ { name: 'hostname' },
+ { name: 'username' },
+ { name: 'title' },
+ { name: 'channel' },
+ { name: 'service' },
+ { name: 'state' },
+ { name: 'errors' },
+ { name: 'in' },
+ { name: 'out' },
+ {
+ name: 'start',
+ type: 'date',
+ dateFormat: 'U' /* unix time */
+ }
+ ],
+ url: 'api/status/subscriptions',
+ autoLoad: true,
+ id: 'id'
+ });
+ tvheadend.subsStore = store;
+
+ tvheadend.comet.on('subscriptions', update);
+
+ function renderBw(value, item, record) {
+ var txt = parseInt(value / 125);
+ var href = 'javascript:tvheadend.subscription_bw_monitor(' + record.id + ');';
+ return '' + txt + '';
+ }
+
+ var subsCm = new Ext.grid.ColumnModel([
+ {
+ width: 50,
+ id: 'hostname',
+ header: "Hostname",
+ dataIndex: 'hostname'
+ },
+ {
+ width: 50,
+ id: 'username',
+ header: "Username",
+ dataIndex: 'username'
+ },
+ {
+ width: 80,
+ id: 'title',
+ header: "Title",
+ dataIndex: 'title'
+ },
+ {
+ width: 50,
+ id: 'channel',
+ header: "Channel",
+ dataIndex: 'channel'
+ },
+ {
+ width: 200,
+ id: 'service',
+ header: "Service",
+ dataIndex: 'service'
+ },
+ {
+ width: 50,
+ id: 'start',
+ header: "Start",
+ dataIndex: 'start',
+ renderer: function(v) {
+ var dt = new Date(v);
+ return dt.format('D j M H:i');
+ }
+ },
+ {
+ width: 50,
+ id: 'state',
+ header: "State",
+ dataIndex: 'state'
+ },
+ {
+ width: 50,
+ id: 'errors',
+ header: "Errors",
+ dataIndex: 'errors'
+ },
+ {
+ width: 50,
+ id: 'in',
+ header: "Input (kb/s)",
+ dataIndex: 'in',
+ renderer: renderBw,
+ },
+ {
+ width: 50,
+ id: 'out',
+ header: "Output (kb/s)",
+ dataIndex: 'out',
+ renderer: renderBw
+ }
+ ]);
+
+ subs = new Ext.grid.GridPanel({
+ border: false,
+ loadMask: true,
+ stripeRows: true,
+ disableSelection: true,
+ store: store,
+ cm: subsCm,
+ flex: 1,
+ viewConfig: {
+ forceFit: true
+ }
+ });
+
+ dpanel.add(subs);
+ dpanel.doLayout(false, true);
+ }
+
+ function destroyer() {
+ if (subs === null || !tvheadend.dynamic)
+ return;
+ dpanel.removeAll()
+ tvheadend.subsStore = null;
+ store.destroy();
+ store = null;
+ subs = null;
}
- var subsCm = new Ext.grid.ColumnModel([
- {
- width: 50,
- id: 'hostname',
- header: "Hostname",
- dataIndex: 'hostname'
- },
- {
- width: 50,
- id: 'username',
- header: "Username",
- dataIndex: 'username'
- },
- {
- width: 80,
- id: 'title',
- header: "Title",
- dataIndex: 'title'
- },
- {
- width: 50,
- id: 'channel',
- header: "Channel",
- dataIndex: 'channel'
- },
- {
- width: 200,
- id: 'service',
- header: "Service",
- dataIndex: 'service'
- },
- {
- width: 50,
- id: 'start',
- header: "Start",
- dataIndex: 'start',
- renderer: renderDate
- },
- {
- width: 50,
- id: 'state',
- header: "State",
- dataIndex: 'state'
- },
- {
- width: 50,
- id: 'errors',
- header: "Errors",
- dataIndex: 'errors'
- },
- {
- width: 50,
- id: 'in',
- header: "Input (kb/s)",
- dataIndex: 'in',
- renderer: renderBw
- },
- {
- width: 50,
- id: 'out',
- header: "Output (kb/s)",
- dataIndex: 'out',
- renderer: renderBw
- }
- ]);
-
- var subs = new Ext.grid.GridPanel({
+ var dpanel = new Ext.Panel({
border: false,
- loadMask: true,
- stripeRows: true,
- disableSelection: true,
+ header: false,
+ layout: 'fit',
title: 'Subscriptions',
- iconCls: 'eye',
- store: tvheadend.subsStore,
- cm: subsCm,
- flex: 1,
- viewConfig: {
- forceFit: true
- }
+ iconCls: 'eye'
});
- return subs;
+
+ tvheadend.paneladd(panel, dpanel, index);
+ tvheadend.panelreg(panel, dpanel, builder, destroyer);
};
/**
* Streams
*/
-tvheadend.status_streams = function() {
+tvheadend.status_streams = function(panel, index)
+{
+ var grid = null;
+ var store = null;
- tvheadend.streamStatusStore = new Ext.data.JsonStore({
- root: 'entries',
- totalProperty: 'totalCount',
- fields: [
- { name: 'uuid' },
- { name: 'input' },
- { name: 'username' },
- { name: 'stream' },
- { name: 'subs' },
- { name: 'weight' },
- { name: 'signal' },
- { name: 'ber' },
- { name: 'unc' },
- { name: 'snr' },
- { name: 'bps' },
- { name: 'cc' },
- { name: 'te' },
- { name: 'signal_scale' },
- { name: 'snr_scale' },
- { name: 'ec_bit' },
- { name: 'tc_bit' },
- { name: 'ec_block' },
- { name: 'tc_block' }
- ],
- url: 'api/status/inputs',
- autoLoad: true,
- id: 'uuid'
- });
+ function update(m) {
+ if (m.reload != null) {
+ store.reload();
+ return;
+ }
+ if (m.update == null)
+ return;
+ var r = store.getById(m.uuid);
+ if (!r) {
+ store.reload();
+ return;
+ }
+ r.data.subs = m.subs;
+ r.data.weight = m.weight;
+ r.data.signal = m.signal;
+ r.data.ber = m.ber;
+ r.data.unc = m.unc;
+ r.data.snr = m.snr;
+ r.data.bps = m.bps;
+ r.data.cc = m.cc;
+ r.data.te = m.te;
+ r.data.signal_scale = m.signal_scale;
+ r.data.snr_scale = m.snr_scale;
+ r.data.ec_bit = m.ec_bit;
+ r.data.tc_bit = m.tc_bit;
+ r.data.ec_block = m.ec_block;
+ r.data.tc_block = m.tc_block;
- function renderBw(value, item, store) {
- var txt = parseInt(value / 1024);
- var href = "javascript:tvheadend.stream_bw_monitor('" + store.id + "');";
- return '' + txt + '';
+ store.afterEdit(r);
+ store.fireEvent('updated', store, Ext.data.Record.COMMIT);
}
- function renderBer(value, item, store) {
- if (store.data.tc_bit == 0)
- return value; // fallback (driver/vendor dependent ber)
+ function builder() {
+ if (grid)
+ return;
- // ber = error_bit_count / total_bit_count
- var ber = store.data.ec_bit / store.data.tc_bit;
- return ber;
+ store = new Ext.data.JsonStore({
+ root: 'entries',
+ totalProperty: 'totalCount',
+ fields: [
+ { name: 'uuid' },
+ { name: 'input' },
+ { name: 'username' },
+ { name: 'stream' },
+ { name: 'subs' },
+ { name: 'weight' },
+ { name: 'signal' },
+ { name: 'ber' },
+ { name: 'unc' },
+ { name: 'snr' },
+ { name: 'bps' },
+ { name: 'cc' },
+ { name: 'te' },
+ { name: 'signal_scale' },
+ { name: 'snr_scale' },
+ { name: 'ec_bit' },
+ { name: 'tc_bit' },
+ { name: 'ec_block' },
+ { name: 'tc_block' }
+ ],
+ url: 'api/status/inputs',
+ autoLoad: true,
+ id: 'uuid'
+ });
+ tvheadend.streamStatusStore = store;
+
+ tvheadend.comet.on('input_status', update);
+
+ function renderBw(value, item, record) {
+ var txt = parseInt(value / 1024);
+ var href = "javascript:tvheadend.stream_bw_monitor('" + record.id + "');";
+ return '' + txt + '';
+ }
+
+ function renderBer(value, item, store) {
+ if (store.data.tc_bit == 0)
+ return value; // fallback (driver/vendor dependent ber)
+
+ // ber = error_bit_count / total_bit_count
+ var ber = store.data.ec_bit / store.data.tc_bit;
+ return ber;
+ }
+
+ function renderPer(value, item, store) {
+ if (value == 0) // value: total_block_count
+ return 'Unknown';
+
+ // per = error_block_count / total_block_count
+ var per = store.data.ec_block / value;
+ return per;
+ }
+
+ var cm = new Ext.grid.ColumnModel([
+ {
+ width: 120,
+ header: "Input",
+ dataIndex: 'input'
+ },
+ {
+ width: 100,
+ header: "Stream",
+ dataIndex: 'stream'
+ },
+ {
+ width: 50,
+ header: "Subs #",
+ dataIndex: 'subs'
+ },
+ {
+ width: 50,
+ header: "Weight",
+ dataIndex: 'weight'
+ },
+ {
+ width: 50,
+ header: "Bandwidth (kb/s)",
+ dataIndex: 'bps',
+ renderer: renderBw
+ },
+ {
+ width: 50,
+ header: "BER",
+ dataIndex: 'ber',
+ renderer: renderBer
+ },
+ {
+ width: 50,
+ header: "PER",
+ dataIndex: 'tc_block',
+ renderer: renderPer
+ },
+ {
+ width: 50,
+ header: "Uncorrected Blocks",
+ dataIndex: 'unc'
+ },
+ {
+ width: 50,
+ header: "Transport Errors",
+ dataIndex: 'te'
+ },
+ {
+ width: 50,
+ header: "Continuity Errors",
+ dataIndex: 'cc'
+ }
+ ]);
+
+ cm.config.push(new Ext.ux.grid.ProgressColumn({
+ header: "SNR",
+ dataIndex: 'snr',
+ width: 85,
+ colored: true,
+ ceiling: 65535,
+ tvh_renderer: function(v, p, record) {
+ var scale = record.get('snr_scale');
+ if (scale == 1)
+ return v;
+ if (scale == 2 && v > 0) {
+ var snr = v * 0.0001;
+ return snr.toFixed(1) + " dB";
+ }
+ return 'Unknown';
+ },
+ destroy: function() {
+ }
+ }));
+
+ cm.config.push(new Ext.ux.grid.ProgressColumn({
+ header: "Signal Strength",
+ dataIndex: 'signal',
+ width: 85,
+ colored: true,
+ ceiling: 65535,
+ tvh_renderer: function(v, p, record) {
+ var scale = record.get('snr_scale');
+ if (scale == 1)
+ return v;
+ if (scale == 2 && v > 0) {
+ var snr = v * 0.0001;
+ return snr.toFixed(1) + " dBm";
+ }
+ return 'Unknown';
+ },
+ destroy: function() {
+ }
+ }));
+
+ grid = new Ext.grid.GridPanel({
+ border: false,
+ loadMask: true,
+ stripeRows: true,
+ disableSelection: true,
+ store: store,
+ cm: cm,
+ flex: 1,
+ viewConfig: {
+ forceFit: true
+ }
+ });
+
+ dpanel.add(grid);
+ dpanel.doLayout(false, true);
}
- function renderPer(value, item, store) {
- if (value == 0) // value: total_block_count
- return 'Unknown';
-
- // per = error_block_count / total_block_count
- var per = store.data.ec_block / value;
- return per;
+ function destroyer() {
+ if (grid === null || !tvheadend.dynamic)
+ return;
+ dpanel.removeAll()
+ tvheadend.streamStatusStore = null;
+ store.destroy();
+ store = null;
+ grid = null;
}
- var cm = new Ext.grid.ColumnModel([
- {
- width: 120,
- header: "Input",
- dataIndex: 'input'
- },
- {
- width: 100,
- header: "Stream",
- dataIndex: 'stream'
- },
- {
- width: 50,
- header: "Subs #",
- dataIndex: 'subs'
- },
- {
- width: 50,
- header: "Weight",
- dataIndex: 'weight'
- },
- {
- width: 50,
- header: "Bandwidth (kb/s)",
- dataIndex: 'bps',
- renderer: renderBw
- },
- {
- width: 50,
- header: "BER",
- dataIndex: 'ber',
- renderer: renderBer
- },
- {
- width: 50,
- header: "PER",
- dataIndex: 'tc_block',
- renderer: renderPer
- },
- {
- width: 50,
- header: "Uncorrected Blocks",
- dataIndex: 'unc'
- },
- {
- width: 50,
- header: "Transport Errors",
- dataIndex: 'te'
- },
- {
- width: 50,
- header: "Continuity Errors",
- dataIndex: 'cc'
- }
- ]);
-
- cm.config.push(new Ext.ux.grid.ProgressColumn({
- header: "SNR",
- dataIndex: 'snr',
- width: 85,
- colored: true,
- ceiling: 65535,
- tvh_renderer: function(v, p, record) {
- var scale = record.get('snr_scale');
- if (scale == 1)
- return v;
- if (scale == 2 && v > 0) {
- var snr = v * 0.0001;
- return snr.toFixed(1) + " dB";
- }
- return 'Unknown';
- }
- }));
-
- cm.config.push(new Ext.ux.grid.ProgressColumn({
- header: "Signal Strength",
- dataIndex: 'signal',
- width: 85,
- colored: true,
- ceiling: 65535,
- tvh_renderer: function(v, p, record) {
- var scale = record.get('snr_scale');
- if (scale == 1)
- return v;
- if (scale == 2 && v > 0) {
- var snr = v * 0.0001;
- return snr.toFixed(1) + " dBm";
- }
- return 'Unknown';
- }
- }));
-
- tvheadend.comet.on('input_status', function(m) {
- if (m.reload != null)
- tvheadend.streamStatusStore.reload();
- if (m.update != null) {
- var r = tvheadend.streamStatusStore.getById(m.uuid);
- if (r) {
- r.data.subs = m.subs;
- r.data.weight = m.weight;
- r.data.signal = m.signal;
- r.data.ber = m.ber;
- r.data.unc = m.unc;
- r.data.snr = m.snr;
- r.data.bps = m.bps;
- r.data.cc = m.cc;
- r.data.te = m.te;
- r.data.signal_scale = m.signal_scale;
- r.data.snr_scale = m.snr_scale;
- r.data.ec_bit = m.ec_bit;
- r.data.tc_bit = m.tc_bit;
- r.data.ec_block = m.ec_block;
- r.data.tc_block = m.tc_block;
-
- tvheadend.streamStatusStore.afterEdit(r);
- tvheadend.streamStatusStore.fireEvent('updated',
- tvheadend.streamStatusStore,
- r,
- Ext.data.Record.COMMIT);
- } else {
- tvheadend.streamStatusStore.reload();
- }
- }
- });
-
- var panel = new Ext.grid.GridPanel({
+ var dpanel = new Ext.Panel({
border: false,
- loadMask: true,
- stripeRows: true,
- disableSelection: true,
+ header: false,
+ layout: 'fit',
title: 'Stream',
- iconCls: 'hardware',
- store: tvheadend.streamStatusStore,
- cm: cm,
- flex: 1,
- viewConfig: {
- forceFit: true
- }
+ iconCls: 'hardware'
});
- return panel;
+
+ tvheadend.paneladd(panel, dpanel, index);
+ tvheadend.panelreg(panel, dpanel, builder, destroyer);
};
/**
*
*/
-tvheadend.status_conns = function() {
+tvheadend.status_conns = function(panel, index) {
- var store = new Ext.data.JsonStore({
- root: 'entries',
- totalProperty: 'totalCount',
- fields: [
- { name: 'id' },
- { name: 'type' },
- { name: 'peer' },
- { name: 'user' },
- {
- name: 'started',
- type: 'date',
- dateFormat: 'U' /* unix time */
- }
- ],
- url: 'api/status/connections',
- autoLoad: true,
- id: 'id'
- });
+ var grid = null;
+ var store = null;
- tvheadend.comet.on('connections', function(m) {
+ function update(m) {
if (m.reload != null)
store.reload();
- });
-
- function renderDate(value) {
- var dt = new Date(value);
- return dt.format('Y-m-d H:i:s');
}
- var cm = new Ext.grid.ColumnModel([{
- width: 50,
- id: 'type',
- header: "Type",
- dataIndex: 'type'
- }, {
- width: 50,
- id: 'peer',
- header: "IP Address",
- dataIndex: 'peer'
- }, {
- width: 50,
- id: 'user',
- header: "Username",
- dataIndex: 'user'
- }, {
- width: 50,
- id: 'started',
- header: "Started",
- dataIndex: 'started',
- renderer: renderDate
- }]);
+ function builder() {
+ if (grid)
+ return;
- var panel = new Ext.grid.GridPanel({
- border: false,
- loadMask: true,
- stripeRows: true,
- disableSelection: true,
- title: 'Connections',
- iconCls: 'eye',
- store: store,
- cm: cm,
- flex: 1,
- viewConfig: {
- forceFit: true
+ store = new Ext.data.JsonStore({
+ root: 'entries',
+ totalProperty: 'totalCount',
+ fields: [
+ { name: 'id' },
+ { name: 'type' },
+ { name: 'peer' },
+ { name: 'user' },
+ {
+ name: 'started',
+ type: 'date',
+ dateFormat: 'U' /* unix time */
+ }
+ ],
+ url: 'api/status/connections',
+ autoLoad: true,
+ id: 'id'
+ });
+
+ tvheadend.comet.on('connections', update);
+
+ function renderDate(value) {
+ var dt = new Date(value);
+ return dt.format('Y-m-d H:i:s');
}
+
+ var cm = new Ext.grid.ColumnModel([{
+ width: 50,
+ id: 'type',
+ header: "Type",
+ dataIndex: 'type'
+ }, {
+ width: 50,
+ id: 'peer',
+ header: "IP Address",
+ dataIndex: 'peer'
+ }, {
+ width: 50,
+ id: 'user',
+ header: "Username",
+ dataIndex: 'user'
+ }, {
+ width: 50,
+ id: 'started',
+ header: "Started",
+ dataIndex: 'started',
+ renderer: renderDate
+ }]);
+
+ grid = new Ext.grid.GridPanel({
+ border: false,
+ loadMask: true,
+ stripeRows: true,
+ disableSelection: true,
+ store: store,
+ cm: cm,
+ flex: 1,
+ viewConfig: {
+ forceFit: true
+ }
+ });
+
+ dpanel.add(grid);
+ dpanel.doLayout(false, true);
+ }
+
+ function destroyer() {
+ if (grid === null || !tvheadend.dynamic)
+ return;
+ dpanel.removeAll()
+ store.destroy();
+ store = null;
+ grid = null;
+ }
+
+ var dpanel = new Ext.Panel({
+ border: false,
+ header: false,
+ layout: 'fit',
+ title: 'Connections',
+ iconCls: 'eye'
});
- return panel;
+
+ tvheadend.paneladd(panel, dpanel, index);
+ tvheadend.panelreg(panel, dpanel, builder, destroyer);
};
tvheadend.status = function() {
@@ -430,13 +521,12 @@ tvheadend.status = function() {
autoScroll: true,
activeTab: 0,
iconCls: 'eye',
- items: [
- new tvheadend.status_streams,
- new tvheadend.status_subs,
- new tvheadend.status_conns,
- new tvheadend.service_mapper_status
- ]
+ items: [],
});
+ tvheadend.status_streams(panel);
+ tvheadend.status_subs(panel);
+ tvheadend.status_conns(panel);
+ tvheadend.service_mapper_status(panel);
return panel;
};
@@ -510,8 +600,9 @@ tvheadend.subscription_bw_monitor = function(id) {
var task = {
interval: 1000,
run: function() {
- r = tvheadend.subsStore.getById(id);
- if (typeof r === 'undefined') {
+ var store = tvheadend.subsStore;
+ var r = store ? store.getById(id) : null;
+ if (!store || typeof r === 'undefined') {
chart.stop();
Ext.TaskMgr.stop(task);
return;
@@ -600,10 +691,11 @@ tvheadend.stream_bw_monitor = function(id) {
});
var task = {
- interval: 1000,
+ interval: 10000,
run: function() {
- r = tvheadend.streamStatusStore.getById(id);
- if (typeof r === 'undefined') {
+ var store = tvheadend.streamStatusStore;
+ var r = store ? store.getById(id) : null;
+ if (!store || typeof r === 'undefined') {
chart.stop();
Ext.TaskMgr.stop(task);
return;