iot-dashboard
Version:
A generic dashboard application based on JavaScript, HTML and CSS. http://iot-dashboard.org
1,388 lines (1,266 loc) • 226 kB
JavaScript
webpackJsonp([0],[
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
__webpack_require__(2);
__webpack_require__(12);
__webpack_require__(15);
__webpack_require__(17);
__webpack_require__(21);
__webpack_require__(22);
__webpack_require__(25);
__webpack_require__(26);
__webpack_require__(28);
__webpack_require__(29);
__webpack_require__(31);
var es6promise = __webpack_require__(33);
var Renderer = __webpack_require__(36);
var Store = __webpack_require__(106);
var Persist = __webpack_require__(104);
var dashboard_1 = __webpack_require__(51);
var $ = __webpack_require__(13);
var loadPredefinedState = $.get('./dashboard.json');
es6promise.polyfill();
loadPredefinedState.then(function (data) {
console.log("Starting dashboard with predefined state");
runWithState(data);
}).fail(function (error) {
if (error.status === 404) {
// When the file is not available just start the dashboard in devMode
console.warn("There is no ./dashboard.json - The Dashboard will be loaded in Developer Mode and everything can be edited.\n" +
"To run the board with a predefined configuration go to 'Board > Import / Export'\n" +
"and save the exported content in a file named 'dashboard.json' next to the index.html (i.e. './dist/dashboard.json')");
runWithState();
}
else if (confirm("Failed to load Dashboard from dashboard.json\n" +
"\n" +
"Try to load in developer mode instated?")) {
runWithState();
}
});
function runWithState(configuredState) {
var initialState = configuredState;
var storeOptions = Store.defaultStoreOptions();
if (!initialState) {
initialState = Persist.loadFromLocalStorage();
}
else {
var devMode = false;
if (configuredState.config) {
devMode = configuredState.config.devMode;
}
if (devMode) {
console.log("Dashboard running in devMode. Set config.devMode = false to deliver dashboard as 'view only'");
}
storeOptions.persist = devMode;
initialState.global = {
isReadOnly: !devMode
};
}
var dashboardStore = Store.create(initialState, storeOptions);
var appElement = document.getElementById('app');
if (!appElement) {
throw new Error("Can not get element '#app' from DOM. Okay for headless execution.");
}
function handleError(dashboard, error) {
console.warn("Fatal error. Asking user to wipe data and retry. The error will be printed below...");
if (confirm("Fatal error. Reset all Data?\n\nPress cancel and check the browser console for more details.")) {
dashboardStore.dispatch(Store.clearState());
dashboard.dispose();
start();
}
else {
dashboard.dispose();
window.onerror = function () { return false; };
throw error;
}
}
function start() {
var dashboard = new dashboard_1.default(dashboardStore);
window.onerror = function errorHandler(message, filename, lineno, colno, error) {
handleError(dashboard, error);
return false;
};
dashboard.init();
try {
renderDashboard(appElement, dashboardStore);
}
catch (error) {
handleError(dashboard, error);
}
}
start();
function renderDashboard(element, store) {
Renderer.render(element, store);
}
}
/***/ },
/* 2 */,
/* 3 */,
/* 4 */,
/* 5 */,
/* 6 */,
/* 7 */,
/* 8 */,
/* 9 */,
/* 10 */,
/* 11 */,
/* 12 */,
/* 13 */,
/* 14 */,
/* 15 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["$"] = __webpack_require__(16);
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 16 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["jQuery"] = __webpack_require__(13);
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 17 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["React"] = __webpack_require__(18);
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 18 */,
/* 19 */,
/* 20 */,
/* 21 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["_"] = __webpack_require__(19);
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 22 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var FreeboardDatasource = __webpack_require__(23);
var PluginCache = __webpack_require__(24);
function mapSettings(settings) {
return settings.map(function (setting) {
return {
id: setting["name"],
name: setting["display_name"],
description: setting["description"],
type: setting["type"],
defaultValue: setting["default_value"],
required: setting["required"]
};
});
}
var freeboardPluginApi = {
/**
* Method to register a DatasourcePlugin as you would with the IoT-Dashboard API
* But supporting the Freeboard syntax
* @param plugin A Freeboard Datasource Plugin.
* See: https://freeboard.github.io/freeboard/docs/plugin_example.html
*/
loadDatasourcePlugin: function (plugin) {
console.log("Loading freeboard Plugin: ", plugin);
var typeName = plugin["type_name"];
var displayName = plugin["display_name"];
var description = plugin["description"];
var externalScripts = plugin["external_scripts"];
var settings = plugin["settings"];
var newInstance = plugin["newInstance"];
var TYPE_INFO = {
type: typeName,
name: displayName,
description: description,
dependencies: externalScripts,
settings: mapSettings(settings)
};
var dsPlugin = {
TYPE_INFO: TYPE_INFO,
Datasource: FreeboardDatasource.create(newInstance, TYPE_INFO)
};
PluginCache.registerDatasourcePlugin(dsPlugin.TYPE_INFO, dsPlugin.Datasource);
}
};
window.freeboard = freeboardPluginApi;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = freeboardPluginApi;
/***/ },
/* 23 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var _ = __webpack_require__(19);
// **newInstance(settings, newInstanceCallback, updateCallback)** (required) : A function that will be called when a new instance of this plugin is requested.
// * **settings** : A javascript object with the initial settings set by the user. The names of the properties in the object will correspond to the setting names defined above.
// * **newInstanceCallback** : A callback function that you'll call when the new instance of the plugin is ready. This function expects a single argument, which is the new instance of your plugin object.
// * **updateCallback** : A callback function that you'll call if and when your datasource has an update for freeboard to recalculate. This function expects a single parameter which is a javascript object with the new, updated data. You should hold on to this reference and call it when needed.
function create(newInstance, TYPE_INFO) {
return function FreeboardDatasource(props) {
if (props === void 0) { props = {}; }
this.instance = null;
this.data = history;
this.fetchData = function (resolve, reject) {
if (!this.data) {
resolve();
return;
}
var data = this.data;
this.data = null;
if (_.isArray(data)) {
resolve(data);
}
else {
return resolve([data]);
}
}.bind(this);
this.dispose = function () {
this.instance.onDispose();
}.bind(this);
this.datasourceWillReceiveProps = function (newProps) {
if (newProps.settings !== this.props.settings) {
console.log("Updating Datasource settings");
this.instance.onSettingsChanged(newProps);
}
}.bind(this);
var newInstanceCallback = function (instance) {
this.instance = instance;
instance.updateNow();
}.bind(this);
var updateCallback = function (newData) {
this.data = newData;
}.bind(this);
createNewInstance();
function createNewInstance() {
newInstance(props, newInstanceCallback, updateCallback);
}
}.bind(this);
}
exports.create = create;
/***/ },
/* 24 */
/***/ function(module, exports) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* When a Plugin is loaded via the UI, an action is called to do so.
* The action will load an external script, containing the plugin code, which calls one of the API methods here.
* By calling the API method the plugin is put to the pluginCache where it can be fetched by the application to initialize it
*
* The application can not call the Plugin since it could (and should) be wrapped into a module.
* @type {null}
*/
var pluginCache = null;
function popLoadedPlugin() {
var plugin = pluginCache;
pluginCache = null;
return plugin;
}
exports.popLoadedPlugin = popLoadedPlugin;
function hasPlugin() {
return pluginCache !== null;
}
exports.hasPlugin = hasPlugin;
function registerDatasourcePlugin(typeInfo, datasource) {
console.assert(!hasPlugin(), "Plugin must be finished loading before another can be registered", pluginCache);
pluginCache = ({
TYPE_INFO: typeInfo,
Datasource: datasource
});
pluginCache.TYPE_INFO.kind = "datasource";
}
exports.registerDatasourcePlugin = registerDatasourcePlugin;
function registerWidgetPlugin(typeInfo, widget) {
console.assert(!hasPlugin(), "Plugin must be finished loading before another can be registered", pluginCache);
pluginCache = ({
TYPE_INFO: typeInfo,
Widget: widget
});
pluginCache.TYPE_INFO.kind = "widget";
}
exports.registerWidgetPlugin = registerWidgetPlugin;
/***/ },
/* 25 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var PluginCache = __webpack_require__(24);
var pluginApi = {
registerDatasourcePlugin: PluginCache.registerDatasourcePlugin,
registerWidgetPlugin: PluginCache.registerWidgetPlugin
};
// TO be robust during tests in node and server side rendering
if (window) {
window.iotDashboardApi = pluginApi;
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = pluginApi;
/***/ },
/* 26 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 27 */,
/* 28 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__.p + "index.html";
/***/ },
/* 29 */,
/* 30 */,
/* 31 */
/***/ function(module, exports, __webpack_require__) {
// the whatwg-fetch polyfill installs the fetch() function
// on the global object (window or self)
//
// Return that as the export for use in Webpack, Browserify etc.
__webpack_require__(32);
module.exports = self.fetch.bind(self);
/***/ },
/* 32 */
/***/ function(module, exports) {
(function(self) {
'use strict';
if (self.fetch) {
return
}
var support = {
searchParams: 'URLSearchParams' in self,
iterable: 'Symbol' in self && 'iterator' in Symbol,
blob: 'FileReader' in self && 'Blob' in self && (function() {
try {
new Blob()
return true
} catch(e) {
return false
}
})(),
formData: 'FormData' in self,
arrayBuffer: 'ArrayBuffer' in self
}
function normalizeName(name) {
if (typeof name !== 'string') {
name = String(name)
}
if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
throw new TypeError('Invalid character in header field name')
}
return name.toLowerCase()
}
function normalizeValue(value) {
if (typeof value !== 'string') {
value = String(value)
}
return value
}
// Build a destructive iterator for the value list
function iteratorFor(items) {
var iterator = {
next: function() {
var value = items.shift()
return {done: value === undefined, value: value}
}
}
if (support.iterable) {
iterator[Symbol.iterator] = function() {
return iterator
}
}
return iterator
}
function Headers(headers) {
this.map = {}
if (headers instanceof Headers) {
headers.forEach(function(value, name) {
this.append(name, value)
}, this)
} else if (headers) {
Object.getOwnPropertyNames(headers).forEach(function(name) {
this.append(name, headers[name])
}, this)
}
}
Headers.prototype.append = function(name, value) {
name = normalizeName(name)
value = normalizeValue(value)
var list = this.map[name]
if (!list) {
list = []
this.map[name] = list
}
list.push(value)
}
Headers.prototype['delete'] = function(name) {
delete this.map[normalizeName(name)]
}
Headers.prototype.get = function(name) {
var values = this.map[normalizeName(name)]
return values ? values[0] : null
}
Headers.prototype.getAll = function(name) {
return this.map[normalizeName(name)] || []
}
Headers.prototype.has = function(name) {
return this.map.hasOwnProperty(normalizeName(name))
}
Headers.prototype.set = function(name, value) {
this.map[normalizeName(name)] = [normalizeValue(value)]
}
Headers.prototype.forEach = function(callback, thisArg) {
Object.getOwnPropertyNames(this.map).forEach(function(name) {
this.map[name].forEach(function(value) {
callback.call(thisArg, value, name, this)
}, this)
}, this)
}
Headers.prototype.keys = function() {
var items = []
this.forEach(function(value, name) { items.push(name) })
return iteratorFor(items)
}
Headers.prototype.values = function() {
var items = []
this.forEach(function(value) { items.push(value) })
return iteratorFor(items)
}
Headers.prototype.entries = function() {
var items = []
this.forEach(function(value, name) { items.push([name, value]) })
return iteratorFor(items)
}
if (support.iterable) {
Headers.prototype[Symbol.iterator] = Headers.prototype.entries
}
function consumed(body) {
if (body.bodyUsed) {
return Promise.reject(new TypeError('Already read'))
}
body.bodyUsed = true
}
function fileReaderReady(reader) {
return new Promise(function(resolve, reject) {
reader.onload = function() {
resolve(reader.result)
}
reader.onerror = function() {
reject(reader.error)
}
})
}
function readBlobAsArrayBuffer(blob) {
var reader = new FileReader()
reader.readAsArrayBuffer(blob)
return fileReaderReady(reader)
}
function readBlobAsText(blob) {
var reader = new FileReader()
reader.readAsText(blob)
return fileReaderReady(reader)
}
function Body() {
this.bodyUsed = false
this._initBody = function(body) {
this._bodyInit = body
if (typeof body === 'string') {
this._bodyText = body
} else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
this._bodyBlob = body
} else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
this._bodyFormData = body
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
this._bodyText = body.toString()
} else if (!body) {
this._bodyText = ''
} else if (support.arrayBuffer && ArrayBuffer.prototype.isPrototypeOf(body)) {
// Only support ArrayBuffers for POST method.
// Receiving ArrayBuffers happens via Blobs, instead.
} else {
throw new Error('unsupported BodyInit type')
}
if (!this.headers.get('content-type')) {
if (typeof body === 'string') {
this.headers.set('content-type', 'text/plain;charset=UTF-8')
} else if (this._bodyBlob && this._bodyBlob.type) {
this.headers.set('content-type', this._bodyBlob.type)
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')
}
}
}
if (support.blob) {
this.blob = function() {
var rejected = consumed(this)
if (rejected) {
return rejected
}
if (this._bodyBlob) {
return Promise.resolve(this._bodyBlob)
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as blob')
} else {
return Promise.resolve(new Blob([this._bodyText]))
}
}
this.arrayBuffer = function() {
return this.blob().then(readBlobAsArrayBuffer)
}
this.text = function() {
var rejected = consumed(this)
if (rejected) {
return rejected
}
if (this._bodyBlob) {
return readBlobAsText(this._bodyBlob)
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as text')
} else {
return Promise.resolve(this._bodyText)
}
}
} else {
this.text = function() {
var rejected = consumed(this)
return rejected ? rejected : Promise.resolve(this._bodyText)
}
}
if (support.formData) {
this.formData = function() {
return this.text().then(decode)
}
}
this.json = function() {
return this.text().then(JSON.parse)
}
return this
}
// HTTP methods whose capitalization should be normalized
var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
function normalizeMethod(method) {
var upcased = method.toUpperCase()
return (methods.indexOf(upcased) > -1) ? upcased : method
}
function Request(input, options) {
options = options || {}
var body = options.body
if (Request.prototype.isPrototypeOf(input)) {
if (input.bodyUsed) {
throw new TypeError('Already read')
}
this.url = input.url
this.credentials = input.credentials
if (!options.headers) {
this.headers = new Headers(input.headers)
}
this.method = input.method
this.mode = input.mode
if (!body) {
body = input._bodyInit
input.bodyUsed = true
}
} else {
this.url = input
}
this.credentials = options.credentials || this.credentials || 'omit'
if (options.headers || !this.headers) {
this.headers = new Headers(options.headers)
}
this.method = normalizeMethod(options.method || this.method || 'GET')
this.mode = options.mode || this.mode || null
this.referrer = null
if ((this.method === 'GET' || this.method === 'HEAD') && body) {
throw new TypeError('Body not allowed for GET or HEAD requests')
}
this._initBody(body)
}
Request.prototype.clone = function() {
return new Request(this)
}
function decode(body) {
var form = new FormData()
body.trim().split('&').forEach(function(bytes) {
if (bytes) {
var split = bytes.split('=')
var name = split.shift().replace(/\+/g, ' ')
var value = split.join('=').replace(/\+/g, ' ')
form.append(decodeURIComponent(name), decodeURIComponent(value))
}
})
return form
}
function headers(xhr) {
var head = new Headers()
var pairs = (xhr.getAllResponseHeaders() || '').trim().split('\n')
pairs.forEach(function(header) {
var split = header.trim().split(':')
var key = split.shift().trim()
var value = split.join(':').trim()
head.append(key, value)
})
return head
}
Body.call(Request.prototype)
function Response(bodyInit, options) {
if (!options) {
options = {}
}
this.type = 'default'
this.status = options.status
this.ok = this.status >= 200 && this.status < 300
this.statusText = options.statusText
this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers)
this.url = options.url || ''
this._initBody(bodyInit)
}
Body.call(Response.prototype)
Response.prototype.clone = function() {
return new Response(this._bodyInit, {
status: this.status,
statusText: this.statusText,
headers: new Headers(this.headers),
url: this.url
})
}
Response.error = function() {
var response = new Response(null, {status: 0, statusText: ''})
response.type = 'error'
return response
}
var redirectStatuses = [301, 302, 303, 307, 308]
Response.redirect = function(url, status) {
if (redirectStatuses.indexOf(status) === -1) {
throw new RangeError('Invalid status code')
}
return new Response(null, {status: status, headers: {location: url}})
}
self.Headers = Headers
self.Request = Request
self.Response = Response
self.fetch = function(input, init) {
return new Promise(function(resolve, reject) {
var request
if (Request.prototype.isPrototypeOf(input) && !init) {
request = input
} else {
request = new Request(input, init)
}
var xhr = new XMLHttpRequest()
function responseURL() {
if ('responseURL' in xhr) {
return xhr.responseURL
}
// Avoid security warnings on getResponseHeader when not allowed by CORS
if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) {
return xhr.getResponseHeader('X-Request-URL')
}
return
}
xhr.onload = function() {
var options = {
status: xhr.status,
statusText: xhr.statusText,
headers: headers(xhr),
url: responseURL()
}
var body = 'response' in xhr ? xhr.response : xhr.responseText
resolve(new Response(body, options))
}
xhr.onerror = function() {
reject(new TypeError('Network request failed'))
}
xhr.ontimeout = function() {
reject(new TypeError('Network request failed'))
}
xhr.open(request.method, request.url, true)
if (request.credentials === 'include') {
xhr.withCredentials = true
}
if ('responseType' in xhr && support.blob) {
xhr.responseType = 'blob'
}
request.headers.forEach(function(value, name) {
xhr.setRequestHeader(name, value)
})
xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
})
}
self.fetch.polyfill = true
})(typeof self !== 'undefined' ? self : this);
/***/ },
/* 33 */,
/* 34 */,
/* 35 */,
/* 36 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(React) {/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var ReactDOM = __webpack_require__(37);
var react_redux_1 = __webpack_require__(38);
var pageLayout_1 = __webpack_require__(40);
function render(element, store) {
ReactDOM.render(React.createElement(react_redux_1.Provider, {store: store},
React.createElement(pageLayout_1.default, null)
), element);
}
exports.render = render;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(18)))
/***/ },
/* 37 */,
/* 38 */,
/* 39 */,
/* 40 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var React = __webpack_require__(18);
var react_1 = __webpack_require__(18);
var ReactDOM = __webpack_require__(37);
var react_redux_1 = __webpack_require__(38);
var Global = __webpack_require__(41);
var widgetGrid_ui_js_1 = __webpack_require__(43);
var layouts_ui_js_1 = __webpack_require__(86);
var widgetConfigDialog_ui_js_1 = __webpack_require__(89);
var dashboardMenuEntry_ui_js_1 = __webpack_require__(94);
var importExportDialog_ui_js_1 = __webpack_require__(95);
var datasourceConfigDialog_ui_js_1 = __webpack_require__(97);
var datasourceNavItem_ui_js_1 = __webpack_require__(98);
var widgetsNavItem_ui_js_1 = __webpack_require__(99);
var pluginNavItem_ui_1 = __webpack_require__(100);
var pluginsDialog_ui_1 = __webpack_require__(101);
var Persistence = __webpack_require__(104);
var datasourceFrames_ui_1 = __webpack_require__(105);
var Layout = (function (_super) {
__extends(Layout, _super);
function Layout(props) {
_super.call(this, props);
this.state = { hover: false };
}
Layout.prototype.onReadOnlyModeKeyPress = function (e) {
//console.log("key pressed", event.keyCode);
var intKey = (window.event) ? e.which : e.keyCode;
if (intKey === 27) {
this.props.setReadOnly(!this.props.isReadOnly);
}
};
Layout.prototype.componentDidMount = function () {
if (this.props.devMode) {
this.onReadOnlyModeKeyPress = this.onReadOnlyModeKeyPress.bind(this);
ReactDOM.findDOMNode(this)
.offsetParent
.addEventListener('keydown', this.onReadOnlyModeKeyPress);
}
};
Layout.prototype.render = function () {
var _this = this;
var props = this.props;
var devMode = props.devMode;
var showMenu = props.devMode && (!props.isReadOnly || this.state.hover);
return React.createElement("div", {className: "slds-grid slds-wrap", onKeyUp: function (event) { return _this.onReadOnlyModeKeyPress(event); }},
devMode ? React.createElement("div", null,
React.createElement(widgetConfigDialog_ui_js_1.default, null),
React.createElement(importExportDialog_ui_js_1.default, null),
React.createElement(datasourceConfigDialog_ui_js_1.default, null),
React.createElement(pluginsDialog_ui_1.default, null))
: null,
devMode ? React.createElement("div", {className: showMenu ? "menu-trigger" : "menu-trigger", onMouseOver: function () { _this.setState({ hover: true }); }, onMouseEnter: function () { _this.setState({ hover: true }); }})
: null,
devMode ?
React.createElement("div", {className: "slds-size--1-of-1 slds-context-bar" + (showMenu ? " topnav--visible" : " topnav--hidden"), onMouseOver: function () { _this.setState({ hover: true }); }, onMouseLeave: function () { _this.setState({ hover: false }); }},
React.createElement("div", {className: "slds-context-bar__primary slds-context-bar__item--divider-right"},
React.createElement("div", {className: "slds-context-bar__item slds-context-bar__dropdown-trigger slds-dropdown-trigger slds-dropdown-trigger--click slds-no-hover"},
React.createElement("span", {className: "slds-context-bar__label-action slds-context-bar__app-name"},
React.createElement("span", {className: "slds-truncate"},
React.createElement("a", {href: this.props.config.title.url}, this.props.config.title.text)
)
)
)
),
React.createElement("div", {className: "slds-context-bar__secondary", role: "navigation"},
React.createElement("ul", {className: "slds-grid"},
React.createElement(dashboardMenuEntry_ui_js_1.default, null),
React.createElement(pluginNavItem_ui_1.default, null),
React.createElement(widgetsNavItem_ui_js_1.default, null),
React.createElement(datasourceNavItem_ui_js_1.default, null),
React.createElement(layouts_ui_js_1.default, null),
React.createElement("div", {className: "slds-context-bar__vertical-divider"}),
React.createElement("li", {className: "slds-context-bar__item"},
React.createElement("a", {href: "javascript:void(0);", onClick: function () { return Persistence.clearData(); }, className: "slds-context-bar__label-action", title: "Reset Everything!"},
React.createElement("span", {className: "slds-truncate"}, "Reset Everything!")
)
),
React.createElement("li", {className: "slds-context-bar__item"},
React.createElement("div", {className: "slds-context-bar__icon-action", onClick: function () { return props.setReadOnly(!props.isReadOnly); }},
React.createElement("svg", {"aria-hidden": "true", className: "slds-icon slds-icon--small slds-icon-text-default"},
React.createElement("use", {xlinkHref: "assets/icons/utility-sprite/svg/symbols.svg#" + (props.isReadOnly ? "lock" : "unlock")})
),
React.createElement("span", {className: "slds-assistive-text"}, "Lock / Unlock"))
))
),
React.createElement("div", {className: "slds-context-bar__tertiary"},
React.createElement("ul", {className: "slds-grid slds-grid--vertical-align-center"},
props.config.auth && props.config.auth.username ?
React.createElement("div", {className: "slds-m-right--small"}, props.config.auth.username)
: null,
props.config.auth && props.config.auth.logoutUrl ?
React.createElement("a", {className: "slds-button slds-button--neutral", href: props.config.auth.logoutUrl},
React.createElement("svg", {"aria-hidden": "true", className: "slds-button__icon slds-button__icon--left"},
React.createElement("use", {xlinkHref: "assets/icons/utility-sprite/svg/symbols.svg#logout"})
),
"Logout")
: null,
React.createElement("div", {className: "slds-context-bar__vertical-divider"}),
React.createElement("span", {className: "slds-truncate slds-m-left--small"},
"v",
this.props.config.version))
))
: null,
React.createElement("div", {className: "slds-size--1-of-1"},
React.createElement(widgetGrid_ui_js_1.default, null)
),
React.createElement(datasourceFrames_ui_1.default, null));
};
return Layout;
}(react_1.Component));
exports.Layout = Layout;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = react_redux_1.connect(function (state) {
return {
isReadOnly: state.global.isReadOnly,
devMode: state.config.devMode,
config: state.config
};
}, function (dispatch) {
return {
setReadOnly: function (isReadOnly) { return dispatch(Global.setReadOnly(isReadOnly)); }
};
})(Layout);
/***/ },
/* 41 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var Action = __webpack_require__(42);
exports.initialState = {
isReadOnly: false
};
function setReadOnly(isReadOnly) {
return function (dispatch) {
dispatch(setReadOnlyAction(isReadOnly));
};
}
exports.setReadOnly = setReadOnly;
function setReadOnlyAction(isReadOnly) {
return {
type: Action.SET_READONLY,
isReadOnly: isReadOnly
};
}
function global(state, action) {
if (state === void 0) { state = exports.initialState; }
switch (action.type) {
case Action.SET_READONLY:
return Object.assign({}, state, {
isReadOnly: action.isReadOnly
});
default:
return state;
}
}
exports.global = global;
/***/ },
/* 42 */
/***/ function(module, exports) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* Rules for action names
* ------------------------
* (many of them are not applied but try to follow them in future)
*
* - Try to name Action after what happened not what should happen
* -- i.e. "STARTED_LOADING_PLUGIN" rather than "START_LOADING_PLUGIN"
*/
exports.CLEAR_STATE = "CLEAR_STATE";
// Config
exports.SET_CONFIG_VALUE = "SET_CONFIG_VALUE";
// Dashboard
exports.DASHBOARD_IMPORT = "DASHBOARD_IMPORT";
exports.SET_READONLY = "SET_READONLY";
// Layouts
exports.ADD_LAYOUT = "ADD_LAYOUT";
exports.UPDATE_LAYOUT = "UPDATE_LAYOUT";
exports.DELETE_LAYOUT = "DELETE_LAYOUT";
exports.LOAD_LAYOUT = "LOAD_LAYOUT";
exports.SET_CURRENT_LAYOUT = "SET_CURRENT_LAYOUT";
// Widgets
exports.ADD_WIDGET = "ADD_WIDGET";
exports.UPDATE_WIDGET_SETTINGS = "UPDATE_WIDGET_SETTINGS";
exports.UPDATED_SINGLE_WIDGET_SETTING = "UPDATED_SINGLE_WIDGET_SETTING";
exports.DELETE_WIDGET = "DELETE_WIDGET";
exports.UPDATE_WIDGET_LAYOUT = "UPDATE_WIDGET_LAYOUT";
exports.START_CREATE_WIDGET = "START_CREATE_WIDGET";
exports.START_CONFIGURE_WIDGET = "START_CONFIGURE_WIDGET";
// Datasources
exports.ADD_DATASOURCE = "ADD_DATASOURCE";
exports.UPDATE_DATASOURCE = "UPDATE_DATASOURCE";
exports.DELETE_DATASOURCE = "DELETE_DATASOURCE";
exports.DATASOURCE_FINISHED_LOADING = "DATASOURCE_FINISHED_LOADING";
// Datasource data
exports.FETCHED_DATASOURCE_DATA = "FETCHED_DATASOURCE_DATA";
exports.CLEAR_DATASOURCE_DATA = "CLEAR_DATASOURCE_DATA";
// Plugins
exports.WIDGET_PLUGIN_FINISHED_LOADING = "WIDGET_PLUGIN_FINISHED_LOADING";
exports.PLUGIN_FAILED_LOADING = "PLUGIN_FAILED_LOADING";
exports.DATASOURCE_PLUGIN_FINISHED_LOADING = "DATASOURCE_PLUGIN_FINISHED_LOADING";
exports.DELETE_WIDGET_PLUGIN = "DELETE_WIDGET_PLUGIN";
exports.DELETE_DATASOURCE_PLUGIN = "DELETE_DATASOURCE_PLUGIN";
exports.USE_PUBLISHED_DATASOURCE_PLUGIN = "USE_PUBLISHED_DATASOURCE_PLUGIN";
exports.USE_PUBLISHED_WIDGET_PLUGIN = "USE_PUBLISHED_WIDGET_PLUGIN";
exports.STARTED_LOADING_PLUGIN_FROM_URL = "STARTED_LOADING_PLUGIN_FROM_URL";
// Modal
exports.SHOW_MODAL = "SHOW_MODAL";
exports.HIDE_MODAL = "HIDE_MODAL";
exports.MODAL_ADD_USER_MESSAGE = "MODAL_ADD_USER_MESSAGE";
exports.MODAL_DELETED_USER_MESSAGE = "MODAL_DELETED_USER_MESSAGE";
/***/ },
/* 43 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var React = __webpack_require__(18);
var react_1 = __webpack_require__(18);
var react_redux_1 = __webpack_require__(38);
var _ = __webpack_require__(19);
var Widgets = __webpack_require__(44);
var widgetFrame_ui_1 = __webpack_require__(47);
var widthProvider_ui_1 = __webpack_require__(72);
var react_grid_layout_1 = __webpack_require__(73);
var ResponsiveGrid = widthProvider_ui_1.default(react_grid_layout_1.Responsive);
var breakpoints = { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 };
var cols = { lg: 12, md: 12, sm: 12, xs: 6, xxs: 3 };
var WidgetGrid = (function (_super) {
__extends(WidgetGrid, _super);
function WidgetGrid() {
_super.apply(this, arguments);
}
WidgetGrid.prototype.onLayoutChange = function (layout) {
if (this.props.onLayoutChange) {
this.props.onLayoutChange(layout);
}
};
WidgetGrid.prototype.render = function () {
var props = this.props;
var widgetStates = this.props.widgets;
// TODO: Remove unknown widget from state
var widgets = widgetStates.map(function (widgetState) {
var widgetPlugin = props.widgetPlugins[widgetState.type];
/*
if (!widgetPlugin) {
// TODO: Render widget with error message - currently a loading indicator is displayed and the setting button is hidden
console.warn("No WidgetPluginFactory for type '" + widgetState.type + "'! Skipping rendering.");
return null;
} */
// WidgetFrame must be loaded as function, else the grid is not working properly.
return widgetFrame_ui_1.default({ widget: widgetState, widgetPlugin: widgetPlugin, isReadOnly: props.isReadOnly });
}).filter(function (frame) { return frame !== null; });
/* //Does NOT work that way:
let widgets = widgetData.map((data) => <WidgetFrame {...data}
key={data.id}
_grid={{x: data.col, y: data.row, w: data.width, h: data.height}}
/>);*/
return (React.createElement(ResponsiveGrid, {className: "column", rowHeight: Widgets.ROW_HEIGHT, breakpoints: breakpoints, cols: cols, draggableCancel: ".no-drag", draggableHandle: ".drag", onLayoutChange: this.onLayoutChange.bind(this), isDraggable: !props.isReadOnly, isResizable: !props.isReadOnly}, widgets));
};
return WidgetGrid;
}(react_1.Component));
WidgetGrid.propTypes = {
widgets: react_1.PropTypes.array.isRequired,
datasources: react_1.PropTypes.object.isRequired,
widgetPlugins: react_1.PropTypes.object.isRequired,
onLayoutChange: react_1.PropTypes.func,
deleteWidget: react_1.PropTypes.func,
isReadOnly: react_1.PropTypes.bool.isRequired
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = react_redux_1.connect(function (state) {
return {
widgets: _.valuesIn(state.widgets) || [],
datasources: state.datasources || {},
widgetPlugins: state.widgetPlugins || {},
isReadOnly: state.global.isReadOnly
};
}, function (dispatch) {
return {
onLayoutChange: function (layout) {
dispatch(Widgets.updateLayout(layout));
},
deleteWidget: function (id) { return dispatch(Widgets.deleteWidget(id)); }
};
})(WidgetGrid);
/***/ },
/* 44 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var Uuid = __webpack_require__(45);
var _ = __webpack_require__(19);
var reducer_js_1 = __webpack_require__(46);
var Action = __webpack_require__(42);
exports.HEADER_HEIGHT = 35;
exports.ROW_HEIGHT = 100;
exports.initialWidgets = {
"initial_chart": {
"id": "initial_chart",
"type": "chart",
"settings": {
"name": "Random Values",
"datasource": "initial_random_source",
"chartType": "area-spline",
"dataKeys": "[\"value\"]",
"xKey": "x",
"names": "{\"value\": \"My Value\"}",
"gaugeData": "{\"min\":0,\"max\":100,\"units\":\" %\"}"
},
"row": 0,
"col": 0,
"width": 6,
"height": 2,
"availableHeightPx": 123
},
"initial_text": {
"id": "initial_text",
"type": "text",
"settings": {
"name": "Random data",
"datasource": "initial_random_source"
},
"row": 0,
"col": 6,
"width": 6,
"height": 3,
"availableHeightPx": 223
},
"106913f4-44fb-4f69-ab89-5d5ae857cf3c": {
"id": "106913f4-44fb-4f69-ab89-5d5ae857cf3c",
"type": "chart",
"settings": {
"name": "Random Values",
"datasource": "initial_random_source",
"chartType": "spline",
"dataKeys": "[\"value\", \"value2\"]",
"xKey": "x",
"names": "{\"value\": \"My Value\"}",
"gaugeData": "{\"min\":0,\"max\":100,\"units\":\" %\"}"
},
"row": 2,
"col": 0,
"width": 6,
"height": 2,
"availableHeightPx": 123
}
};
/* // TODO: better explicitly create initial state? But when? ...
export function createInitialWidgets() {
return function(dispatch: AppState.Dispatch) {
dispatch(addWidget('chart', {
"name": "Random Values",
"datasource": "initial_random_source",
"chartType": "area-spline",
"dataKeys": "[\"value\"]",
"xKey": "x",
"names": "{\"value\": \"My Value\"}",
"gaugeData": "{\"min\":0,\"max\":100,\"units\":\" %\"}"
}, 0, 0, 6, 2));
dispatch(addWidget('text', {
"name": "Random data",
"datasource": "initial_random_source"
}, 0, 6, 6, 3));
dispatch(addWidget('text', {
"name": "Bars",
"datasource": "initial_random_source",
"chartType": "spline",
"dataKeys": "[\"value\", \"value2\"]",
"xKey": "x",
"names": "{\"value\": \"My Value\"}",
"gaugeData": "{\"min\":0,\"max\":100,\"units\":\" %\"}"
}, 2, 0, 6, 2));
}
}
*/
function createWidget(widgetType, widgetSettings) {
return function (dispatch, getState) {
var widgets = getState().widgets;
var widgetPositions = calcNewWidgetPosition(widgets);
return dispatch(addWidget(widgetType, widgetSettings, widgetPositions.row, widgetPositions.col));
};
}
exports.createWidget = createWidget;
function addWidget(widgetType, widgetSettings, row, col, width, height, id) {
if (widgetSettings === void 0) { widgetSettings = {}; }
if (width === void 0) { width = 3; }
if (height === void 0) { height = 3; }
if (!id) {
id = Uuid.generate();
}
return {
type: Action.ADD_WIDGET,
id: id,
col: col,
row: row,
width: width,
height: height,
widgetType: widgetType,
widgetSettings: widgetSettings
};
}
exports.addWidget = addWidget;
function updateWidgetSettings(id, widgetSettings) {
return {
type: Action.UPDATE_WIDGET_SETTINGS,
id: id,
widgetSettings: widgetSettings
};
}
exports.updateWidgetSettings = updateWidgetSettings;
function updatedSingleSetting(id, settingId, settingValue) {
return {
type: Action.UPDATED_SINGLE_WIDGET_SETTING,
id: id,
settingId: settingId,
settingValue: settingValue
};
}
exports.updatedSingleSetting = updatedSingleSetting;
function deleteWidget(id) {
return {
type: Action.DELETE_WIDGET,
id: id
};
}
exports.deleteWidget = deleteWidget;
function updateLayout(layouts) {
return {
type: Action.UPDATE_WIDGET_LAYOUT,
layouts: layouts
};
}
exports.updateLayout = updateLayout;
var widgetsCrudReducer = reducer_js_1.genCrudReducer([Action.ADD_WIDGET, Action.DELETE_WIDGET], widget);
function widgets(state, action) {
if (state === void 0) { state = exports.initialWidgets; }
state = widgetsCrudReducer(state, action);
switch (action.type) {
case Action.UPDATE_WIDGET_LAYOUT:
return _.valuesIn(state)
.reduce(function (newState, _a) {
var id = _a.id;
newState[id] = widget(newState[id], action);
return newState;
}, _.assign({}, state));
case Action.LOAD_LAYOUT:
console.assert(action.layout.widgets, "Layout is missing Widgets, id: " + action.layout.id);
return action.layout.widgets || {};
case Action.DELETE_WIDGET_PLUGIN:
var toDelete = _.valuesIn(state).filter(function (widgetState) {
return widgetState.type === action.id;
});
var newState_1 = _.assign({}, state);
toDelete.forEach(function (widgetState) {
delete newState_1[widgetState.id];
});
return newState_1;
default:
return state;
}
}
exports.widgets = widgets;
function calcAvaliableHeight(heightUnits) {
// The 10 px extra seem to be based on a bug in the grid layout ...
return (heightUnits * (exports.ROW_HEIGHT + 10)) - exports.HEADER_HEIGHT - 10;
}
function widget(state, action) {
switch (action.type) {
case Action.ADD_WIDGET:
return {
id: action.id,
type: action.widgetType,
settings: action.widgetSettings,
row: action.row,
col: action.col,
width: action.width,
height: action.height,
availableHeightPx: calcAvaliableHeight(action.height)
};
case Action.UPDATE_WIDGET_SETTINGS:
return _.assign({}, state, { settings: action.widgetSettings });
case Action.UPDATED_SINGLE_WIDGET_SETTING: {
var newSettings = _.clone(state.settings);
newSettings[action.settingId] = action.settingValue;
return _.assign({}, state, { settings: newSettings });
}
case Action.UPDATE_WIDGET_LAYOUT:
var layout = layoutById(action.layouts, state.id);
if (layout == null) {
console.warn("No layout for widget. Skipping position update of widget with id: " + state.id);
return state;
}
var heightInPx = calcAvaliableHeight(layout.h);
// Only change state when something actually changed!
if (state.row !== layout.y ||
state.col !== layout.x ||
state.width !== layout.w ||
state.height !== layout.h ||
state.availableHeightPx !== heightInPx) {
return _.assign({}, state, {
row: layout.y,
col: layout.x,
width: layout.w,
height: layout.h,
availableHeightPx: heightInPx
});
}
else {
return state;
}
default:
return state;
}
}
// Local functions
function layoutById(layout, id) {
return _.find(layout, function (l) {
return l.i === id;
});
}
function calcNewWidgetPosition(widgets) {
var col