diff --git a/package-lock.json b/package-lock.json index 1f7795b..01667d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3926,6 +3926,11 @@ "isarray": "^1.0.0" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -5775,6 +5780,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -7114,6 +7127,14 @@ "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" }, + "fibers": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.0.tgz", + "integrity": "sha512-UpGv/YAZp7mhKHxDvC1tColrroGRX90sSvh8RMZV9leo+e5+EkRVgCEZPlmXeo3BUNQTZxUaVdLskq1Q2FyCPg==", + "requires": { + "detect-libc": "^1.0.3" + } + }, "figgy-pudding": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", @@ -8209,11 +8230,6 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, - "immer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", - "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" - }, "immutable": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", @@ -10701,6 +10717,30 @@ "universalify": "^2.0.0" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -10732,6 +10772,33 @@ "set-immediate-shim": "~1.0.1" } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "requires": { + "tsscmp": "1.0.6" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -10884,11 +10951,46 @@ "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -13883,24 +13985,21 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" }, - "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } + "immer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", + "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, + "react-error-overlay": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", + "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -14000,11 +14099,6 @@ "prop-types": "^15.6.0" } }, - "react-error-overlay": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", - "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==" - }, "react-fullscreenable": { "version": "2.5.1-0", "resolved": "https://registry.npmjs.org/react-fullscreenable/-/react-fullscreenable-2.5.1-0.tgz", @@ -16710,6 +16804,18 @@ "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" }, + "ts-node": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, "ts-pnp": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", @@ -17092,6 +17198,14 @@ "use-isomorphic-layout-effect": "^1.0.0" } }, + "utf-8-validate": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.3.tgz", + "integrity": "sha512-jtJM6fpGv8C1SoH4PtG22pGto6x+Y8uPprW0tw3//gGFhDDTiuksgradgFN6yRayDP4SyZZa6ZMGHLIa17+M8A==", + "requires": { + "use-isomorphic-layout-effect": "^1.0.0" + } + }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", diff --git a/package.json b/package.json index 9488a59..22104f5 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,10 @@ "file-saver": "^2.0.5", "flux": "^3.1.3", "gaugeJS": "^1.3.7", - "handlebars": "^4.7.7", - "jquery": "^3.6.0", - "jszip": "^3.6.0", + "handlebars": "^4.7.6", + "jquery": "^3.5.1", + "jsonwebtoken": "^8.5.1", + "jszip": "^3.5.0", "libcimsvg": "git+https://git.rwth-aachen.de/acs/public/cim/pintura-npm-package.git", "lodash": "^4.17.21", "moment": "^2.29.1", @@ -41,6 +42,7 @@ "react-dnd-html5-backend": "^10.0.2", "react-dom": "^16.14.0", "react-fullscreenable": "^2.5.1-0", + "react-grid-system": "^7.1.1", "react-json-view": "^1.21.3", "react-notification-system": "^0.4.0", "react-rnd": "^10.2.4", diff --git a/src/app.js b/src/app.js index c71a367..df1d61e 100644 --- a/src/app.js +++ b/src/app.js @@ -20,6 +20,7 @@ import { DndProvider } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; import NotificationSystem from 'react-notification-system'; import { Redirect, Route } from 'react-router-dom'; +import jwt from 'jsonwebtoken' import AppDispatcher from './common/app-dispatcher'; import NotificationsDataManager from './common/data-managers/notifications-data-manager'; @@ -36,6 +37,7 @@ import Users from './user/users'; import User from './user/user'; import APIBrowser from './common/api-browser'; + import './styles/app.css'; import branding from './branding/branding'; @@ -59,22 +61,37 @@ class App extends React.Component { // if token stored locally, we are already logged-in let token = localStorage.getItem("token"); if (token != null && token !== '') { - let currentUser = JSON.parse(localStorage.getItem("currentUser")); - console.log("Already logged-in") - AppDispatcher.dispatch({ - type: 'users/logged-in', - token: token, - currentUser: currentUser - }); + + let isExpired = this.tokenIsExpired(token); + if (isExpired) { + console.log("Token expired") + AppDispatcher.dispatch({ + type: 'users/logout' + }); + } else { + let currentUser = JSON.parse(localStorage.getItem("currentUser")); + console.log("Already logged-in") + AppDispatcher.dispatch({ + type: 'users/logged-in', + token: token, + currentUser: currentUser + }); + } } } + tokenIsExpired(token){ + let decodedToken = jwt.decode(token); + let timeNow = (new Date().getTime() + 1) / 1000; + return decodedToken.exp < timeNow; + } + render() { let token = localStorage.getItem("token"); let currentUserRaw = localStorage.getItem("currentUser"); - if (token == null || token === "" || currentUserRaw == null || currentUserRaw === "") { + if ((token == null || token === "" || currentUserRaw == null || currentUserRaw === "") || this.tokenIsExpired(token)) { console.log("APP redirecting to logout/ login") return (); } diff --git a/src/dashboard/dashboard.js b/src/dashboard/dashboard.js index d627c77..fe3ca4f 100644 --- a/src/dashboard/dashboard.js +++ b/src/dashboard/dashboard.js @@ -21,7 +21,7 @@ import Fullscreenable from 'react-fullscreenable'; import classNames from 'classnames'; import EditWidget from '../widget/edit-widget/edit-widget'; -import EditFiles from '../file/edit-files'; +import EditFilesDialog from '../file/edit-files'; import EditSignalMappingDialog from "../signal/edit-signal-mapping"; import WidgetContextMenu from '../widget/widget-context-menu'; import WidgetToolbox from '../widget/widget-toolbox'; @@ -560,7 +560,7 @@ class Dashboard extends Component { ics={this.state.ics} /> - - - this.selectUploadFile(event)} - /> - - - +
+
Add file
+ + + this.selectUploadFile(event)} /> + + + - + + +
+ +
diff --git a/src/ic/ic-action.js b/src/ic/ic-action.js index df4c17f..a33f73f 100644 --- a/src/ic/ic-action.js +++ b/src/ic/ic-action.js @@ -74,14 +74,14 @@ class ICAction extends React.Component { * see: https://villas.fein-aachen.org/doc/controller-protocol.html */ - if (newAction.action == "create" || newAction.action === "delete") { + if (newAction.action === "create" || newAction.action === "delete") { // prepare parameters for delete incl. correct IC id newAction["parameters"] = {}; - if (newAction.action == "delete") { + if (newAction.action === "delete") { newAction.parameters["uuid"] = ic.uuid; } - else if (newAction.action == "create") { + else if (newAction.action === "create") { newAction.parameters = ic.statusupdateraw.properties; } diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index d892c7d..bc9aa18 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -88,14 +88,14 @@ class InfrastructureComponentStore extends ArrayStore { // adapt URL for newly created result ID a.results.url = a.results.url.replace("RESULTID", action.data.result.id); a.results.url = ICsDataManager.makeURL(a.results.url); - a.results.url = window.location.host + a.results.url; + a.results.url = 'https://' + window.location.host + a.results.url; } if (a.model !== undefined && a.model != null && JSON.stringify(a.model) !== JSON.stringify({})) { // adapt URL(s) for model file let modelURLs = [] for (let url of a.model.url){ let modifiedURL = ICsDataManager.makeURL(url); - modifiedURL = window.location.host + modifiedURL; + modifiedURL = 'https://' + window.location.host + modifiedURL; modelURLs.push(modifiedURL) } a.model.url = modelURLs diff --git a/src/result/edit-result.js b/src/result/edit-result.js index 2b8b13f..aba2117 100644 --- a/src/result/edit-result.js +++ b/src/result/edit-result.js @@ -154,11 +154,13 @@ class EditResultDialog extends React.Component { + +
@@ -194,11 +196,14 @@ class EditResultDialog extends React.Component { this.selectUploadFile(event)} /> + + diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index c6beadc..1a42b66 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -36,7 +36,7 @@ import ImportConfigDialog from '../componentconfig/import-config'; import ImportDashboardDialog from "../dashboard/import-dashboard"; import NewDashboardDialog from "../dashboard/new-dashboard"; import EditDashboardDialog from '../dashboard/edit-dashboard'; -import EditFiles from '../file/edit-files' +import EditFilesDialog from '../file/edit-files' import NewResultDialog from '../result/new-result'; import EditResultDialog from '../result/edit-result'; import ResultConfigDialog from '../result/result-configs-dialog'; @@ -168,7 +168,7 @@ class Scenario extends React.Component { componentDidUpdate(prevProps, prevState) { // check whether file data has been loaded if (this.state.filesToDownload && this.state.filesToDownload.length > 0) { - if (this.state.files != prevState.files) { + if (this.state.files !== prevState.files) { if (!this.state.zipfiles) { let fileToDownload = FileStore.getState().filter(file => file.id === this.state.filesToDownload[0]) if (fileToDownload.length === 1 && fileToDownload[0].data) { @@ -746,7 +746,7 @@ class Scenario extends React.Component {

{this.state.scenario.name}

- !this.usesExternalIC(index)} onChecked={(index, event) => this.onConfigChecked(index, event)} - width='30' + width={20} /> {this.state.currentUser.role === "Admin" ? : <> } this.setState({ editOutputSignalsModal: true, modalConfigData: this.state.configs[index], modalConfigIndex: index })} + width={150} /> this.setState({ editInputSignalsModal: true, modalConfigData: this.state.configs[index], modalConfigIndex: index })} + width={150} /> this.signalsAutoConf(index)} + width={150} /> this.getICName(icID)} + width={300} /> : <> } @@ -913,13 +920,17 @@ class Scenario extends React.Component { dataKey='name' link='/dashboards/' linkKey='id' + width={300} /> + dataKey='grid' + width={100} + /> + this.modifyResultNoColumn(id, result)} + width={70} /> this.downloadResultData(index)} + width={300} /> : <> } this.setState({ diff --git a/src/user/login-complete.js b/src/user/login-complete.js index 9ed2fc7..7df0d00 100644 --- a/src/user/login-complete.js +++ b/src/user/login-complete.js @@ -69,7 +69,7 @@ class LoginComplete extends React.Component { } startTimer() { - if (this.timer == 0 && this.state.secondsToWait > 0) { + if (this.timer === 0 && this.state.secondsToWait > 0) { // call function 'countDown' every 1000ms this.timer = setInterval(this.countDown, 1000); } @@ -80,7 +80,7 @@ class LoginComplete extends React.Component { this.setState({secondsToWait: seconds}); // waiting time over, stop counting down - if (seconds == 0) { + if (seconds === 0) { clearInterval(this.timer); } } @@ -90,11 +90,11 @@ class LoginComplete extends React.Component { this.stopTimer(); return (); } - else if (this.state.secondsToWait == 0) { + else if (this.state.secondsToWait === 0) { this.stopTimer(); return (); } else { - return
+ return