diff --git a/Birdmap.API/Birdmap.API.csproj b/Birdmap.API/Birdmap.API.csproj index 6999cfd..57b6c21 100644 --- a/Birdmap.API/Birdmap.API.csproj +++ b/Birdmap.API/Birdmap.API.csproj @@ -52,6 +52,7 @@ + @@ -61,7 +62,6 @@ - diff --git a/Birdmap.API/ClientApp/package-lock.json b/Birdmap.API/ClientApp/package-lock.json index 4721d28..eec6b97 100644 --- a/Birdmap.API/ClientApp/package-lock.json +++ b/Birdmap.API/ClientApp/package-lock.json @@ -1610,6 +1610,25 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, + "@rollup/plugin-babel": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz", + "integrity": "sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A==", + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, "@svgr/babel-plugin-add-jsx-attribute": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", @@ -1761,6 +1780,11 @@ "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==" }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -2356,6 +2380,20 @@ "normalize-path": "^2.1.1" } }, + "apexcharts": { + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.22.2.tgz", + "integrity": "sha512-pR+cmApk7dhfYILBpe8RVb+FdLfVCt/RDWvAJO1F5feeSQ8lKDgFkRuVu9KOeEarHVXjUpnhLqHNMx7YaprK8A==", + "requires": { + "@rollup/plugin-babel": "^5.2.1", + "svg.draggable.js": "^2.2.2", + "svg.easing.js": "^2.0.0", + "svg.filter.js": "^2.0.2", + "svg.pathmorphing.js": "^0.1.3", + "svg.resize.js": "^1.4.3", + "svg.select.js": "^3.0.1" + } + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -5566,6 +5604,11 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -10799,6 +10842,14 @@ "prop-types": "^15.6.2" } }, + "react-apexcharts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-1.3.7.tgz", + "integrity": "sha512-2OFhEHd70/WHN0kmrJtVx37UfaL71ZogVkwezmDqwQWgwhK6upuhlnEEX7tEq4xvjA+RFDn6hiUTNIuC/Q7Zqw==", + "requires": { + "prop-types": "^15.5.7" + } + }, "react-app-polyfill": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz", @@ -13066,6 +13117,70 @@ "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" }, + "svg.draggable.js": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", + "integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==", + "requires": { + "svg.js": "^2.0.1" + } + }, + "svg.easing.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz", + "integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=", + "requires": { + "svg.js": ">=2.3.x" + } + }, + "svg.filter.js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz", + "integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=", + "requires": { + "svg.js": "^2.2.5" + } + }, + "svg.js": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz", + "integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==" + }, + "svg.pathmorphing.js": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz", + "integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==", + "requires": { + "svg.js": "^2.4.0" + } + }, + "svg.resize.js": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz", + "integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==", + "requires": { + "svg.js": "^2.6.5", + "svg.select.js": "^2.1.2" + }, + "dependencies": { + "svg.select.js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz", + "integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==", + "requires": { + "svg.js": "^2.2.5" + } + } + } + }, + "svg.select.js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz", + "integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==", + "requires": { + "svg.js": "^2.6.5" + } + }, "svgo": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz", diff --git a/Birdmap.API/ClientApp/package.json b/Birdmap.API/ClientApp/package.json index 59d65f4..7546d46 100644 --- a/Birdmap.API/ClientApp/package.json +++ b/Birdmap.API/ClientApp/package.json @@ -7,6 +7,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.56", "@microsoft/signalr": "^5.0.0", + "apexcharts": "^3.22.2", "bootstrap": "^4.3.1", "connected-react-router": "6.5.2", "google-map-react": "^2.1.9", @@ -17,6 +18,7 @@ "merge": "1.2.1", "popper.js": "^1.16.0", "react": "^16.11.0", + "react-apexcharts": "^1.3.7", "react-dom": "16.11.0", "react-google-maps": "^9.4.5", "react-redux": "7.1.1", diff --git a/Birdmap.API/ClientApp/src/App.tsx b/Birdmap.API/ClientApp/src/App.tsx index bda936e..dabd34f 100644 --- a/Birdmap.API/ClientApp/src/App.tsx +++ b/Birdmap.API/ClientApp/src/App.tsx @@ -16,6 +16,7 @@ import MapContainer from './components/heatmap/Heatmap'; import Devices from './components/devices/Devices'; import { blueGrey, blue, orange, grey } from '@material-ui/core/colors'; import DevicesContextProvider from './contexts/DevicesContextProvider' +import Dashboard from './components/dashboard/Dashboard'; const theme = createMuiTheme({ @@ -48,7 +49,7 @@ function App() { } const DashboardComponent = () => { - return This is a link; + return ; }; const DevicesComponent = () => { diff --git a/Birdmap.API/ClientApp/src/components/dashboard/AddNewDialog.jsx b/Birdmap.API/ClientApp/src/components/dashboard/AddNewDialog.jsx new file mode 100644 index 0000000..2ac61d8 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/dashboard/AddNewDialog.jsx @@ -0,0 +1,61 @@ +import { TextField } from '@material-ui/core'; +import Button from '@material-ui/core/Button'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import React, { useState } from 'react'; + +export default function AddNewDialog(props) { + const [name, setName] = useState(""); + const [url, setUrl] = useState(""); + + const onNameChange = (event) => { + setName(event.target.value); + } + + const onUrlChange = (event) => { + setUrl(event.target.value); + } + + return ( +
+ + {"Add new service."} + + + + + + + + + +
+ ); +} diff --git a/Birdmap.API/ClientApp/src/components/dashboard/Dashboard.jsx b/Birdmap.API/ClientApp/src/components/dashboard/Dashboard.jsx new file mode 100644 index 0000000..7be8121 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/dashboard/Dashboard.jsx @@ -0,0 +1,161 @@ +import { Box, Grid, IconButton, Paper, Typography } from '@material-ui/core'; +import { blueGrey } from '@material-ui/core/colors'; +import { AddBox, Refresh } from '@material-ui/icons/'; +import { withStyles } from '@material-ui/styles'; +import { HubConnectionBuilder } from '@microsoft/signalr'; +import React, { Component } from 'react'; +import AddNewDialog from './AddNewDialog'; +import DashboardService, { ServiceRequest } from './DashboardService'; +import ServiceInfoComponent from './ServiceInfoComponent'; +import ServiceInfoSkeleton from './ServiceInfoSkeleton'; + +const styles = theme => ({ + root: { + flexGrow: 1, + padding: '64px', + backgroundColor: theme.palette.primary.dark, + }, + paper: { + backgroundColor: blueGrey[50], + height: '60px', + }, + typo: { + fontSize: theme.typography.pxToRem(20), + fontWeight: theme.typography.fontWeightRegular, + }, +}); + +const hub_url = "/hubs/services"; +const notify_method_name = "NotifyUpdatedAsync"; + +class Dashboard extends Component { + constructor(props) { + super(props); + + this.state = { + hubConnection: null, + isDialogOpen: false, + isLoading: false, + service: new DashboardService(), + services: [], + serviceCount: [1, 2, 3], + } + + this.handleDevicesUpdated = this.handleDevicesUpdated.bind(this); + this.addDevice = this.addDevice.bind(this); + } + + handleDevicesUpdated() { + this.setState({ isLoading: true }); + + this.state.service.getCount().then(result => { + const updatedCount = []; + for (var i = 0; i < result; i++) { + updatedCount.push(i); + } + this.setState({ serviceCount: updatedCount }); + }).catch(ex => { + console.log(ex); + }); + + this.state.service.get().then(result => { + const updatedServices = []; + for (var s of result) { + updatedServices.push(s); + } + this.setState({ services: updatedServices }); + }).catch(ex => { + console.log(ex); + }).finally(() => this.setState({ isLoading: false })); + } + + componentDidMount() { + this.handleDevicesUpdated(); + const newConnection = new HubConnectionBuilder() + .withUrl(hub_url) + .withAutomaticReconnect() + .build(); + + this.setState({ hubConnection: newConnection }); + + newConnection.start() + .then(_ => { + console.log('Services hub Connected!'); + newConnection.on(notify_method_name, () => this.handleDevicesUpdated()); + }).catch(e => console.log('Services hub Connection failed: ', e)); + } + + componentWillUnmount() { + if (this.state.hubConnection != null) { + this.state.hubConnection.off(notify_method_name); + console.log('Services hub Disconnected!'); + } + } + + addDevice(name, url) { + this.setState({ isDialogOpen: false }); + let request = new ServiceRequest(); + request.id = 0; + request.name = name; + request.uri = url; + + this.state.service.post(request).catch(ex => { + console.log(ex); + }); + } + + render() { + const { classes } = this.props; + + const Services = this.state.services.map((info, index) => ( + + )); + + const Skeletons = this.state.serviceCount.map((i, index) => ( + + )); + + return ( + + + + + + + Services + + + {this.props.isAdmin ? + this.setState({ isDialogOpen: true })}> + + + : null + } + + + + + + + this.setState({ isDialogOpen: false })} handleAdd={this.addDevice}/> + + + {this.state.isLoading ? Skeletons : Services} + + + + + + + + + + ); + } +} + +export default withStyles(styles)(Dashboard); \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.js b/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.js new file mode 100644 index 0000000..1a8bbee --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.js @@ -0,0 +1,386 @@ +"use strict"; +/* tslint:disable */ +/* eslint-disable */ +//---------------------- +// +// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org) +// +//---------------------- +// ReSharper disable InconsistentNaming +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ApiException = exports.HttpStatusCode = exports.ServiceRequest = exports.ServiceInfo = void 0; +var DashboardService = /** @class */ (function () { + function DashboardService(baseUrl, http) { + this.jsonParseReviver = undefined; + this.http = http ? http : window; + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : ""; + } + DashboardService.prototype.getCount = function () { + var _this = this; + var url_ = this.baseUrl + "/api/Services/count"; + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "GET", + headers: { + "Accept": "application/json", + 'Authorization': sessionStorage.getItem('user') + } + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processGetCount(_response); + }); + }; + DashboardService.prototype.processGetCount = function (response) { + var _this = this; + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + var result200 = null; + var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver); + result200 = resultData200 !== undefined ? resultData200 : null; + return result200; + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + DashboardService.prototype.get = function () { + var _this = this; + var url_ = this.baseUrl + "/api/Services"; + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "GET", + headers: { + "Accept": "application/json", + 'Authorization': sessionStorage.getItem('user') + } + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processGet(_response); + }); + }; + DashboardService.prototype.processGet = function (response) { + var _this = this; + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + var result200 = null; + var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver); + if (Array.isArray(resultData200)) { + result200 = []; + for (var _i = 0, resultData200_1 = resultData200; _i < resultData200_1.length; _i++) { + var item = resultData200_1[_i]; + result200.push(ServiceInfo.fromJS(item)); + } + } + return result200; + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + DashboardService.prototype.post = function (request) { + var _this = this; + var url_ = this.baseUrl + "/api/Services"; + url_ = url_.replace(/[?&]$/, ""); + var content_ = JSON.stringify(request); + var options_ = { + body: content_, + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + 'Authorization': sessionStorage.getItem('user') + } + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processPost(_response); + }); + }; + DashboardService.prototype.processPost = function (response) { + var _this = this; + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 201) { + return response.text().then(function (_responseText) { + var result201 = null; + var resultData201 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver); + result201 = ServiceRequest.fromJS(resultData201); + return result201; + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + DashboardService.prototype.put = function (request) { + var _this = this; + var url_ = this.baseUrl + "/api/Services"; + url_ = url_.replace(/[?&]$/, ""); + var content_ = JSON.stringify(request); + var options_ = { + body: content_, + method: "PUT", + headers: { + "Content-Type": "application/json", + 'Authorization': sessionStorage.getItem('user') + } + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processPut(_response); + }); + }; + DashboardService.prototype.processPut = function (response) { + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 204) { + return response.text().then(function (_responseText) { + return; + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + DashboardService.prototype.delete = function (id) { + var _this = this; + var url_ = this.baseUrl + "/api/Services/{id}"; + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "DELETE", + headers: { + 'Authorization': sessionStorage.getItem('user') + } + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processDelete(_response); + }); + }; + DashboardService.prototype.processDelete = function (response) { + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 204) { + return response.text().then(function (_responseText) { + return; + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + return DashboardService; +}()); +exports.default = DashboardService; +var ServiceInfo = /** @class */ (function () { + function ServiceInfo(data) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + this[property] = data[property]; + } + } + } + ServiceInfo.prototype.init = function (_data) { + if (_data) { + this.service = _data["service"] ? ServiceRequest.fromJS(_data["service"]) : undefined; + this.statusCode = _data["statusCode"]; + this.response = _data["response"]; + } + }; + ServiceInfo.fromJS = function (data) { + data = typeof data === 'object' ? data : {}; + var result = new ServiceInfo(); + result.init(data); + return result; + }; + ServiceInfo.prototype.toJSON = function (data) { + data = typeof data === 'object' ? data : {}; + data["service"] = this.service ? this.service.toJSON() : undefined; + data["statusCode"] = this.statusCode; + data["response"] = this.response; + return data; + }; + return ServiceInfo; +}()); +exports.ServiceInfo = ServiceInfo; +var ServiceRequest = /** @class */ (function () { + function ServiceRequest(data) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + this[property] = data[property]; + } + } + } + ServiceRequest.prototype.init = function (_data) { + if (_data) { + this.id = _data["id"]; + this.name = _data["name"]; + this.uri = _data["uri"]; + } + }; + ServiceRequest.fromJS = function (data) { + data = typeof data === 'object' ? data : {}; + var result = new ServiceRequest(); + result.init(data); + return result; + }; + ServiceRequest.prototype.toJSON = function (data) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["name"] = this.name; + data["uri"] = this.uri; + return data; + }; + return ServiceRequest; +}()); +exports.ServiceRequest = ServiceRequest; +var HttpStatusCode; +(function (HttpStatusCode) { + HttpStatusCode["Continue"] = "Continue"; + HttpStatusCode["SwitchingProtocols"] = "SwitchingProtocols"; + HttpStatusCode["Processing"] = "Processing"; + HttpStatusCode["EarlyHints"] = "EarlyHints"; + HttpStatusCode["OK"] = "OK"; + HttpStatusCode["Created"] = "Created"; + HttpStatusCode["Accepted"] = "Accepted"; + HttpStatusCode["NonAuthoritativeInformation"] = "NonAuthoritativeInformation"; + HttpStatusCode["NoContent"] = "NoContent"; + HttpStatusCode["ResetContent"] = "ResetContent"; + HttpStatusCode["PartialContent"] = "PartialContent"; + HttpStatusCode["MultiStatus"] = "MultiStatus"; + HttpStatusCode["AlreadyReported"] = "AlreadyReported"; + HttpStatusCode["IMUsed"] = "IMUsed"; + HttpStatusCode["MultipleChoices"] = "Ambiguous"; + HttpStatusCode["Ambiguous"] = "Ambiguous"; + HttpStatusCode["MovedPermanently"] = "Moved"; + HttpStatusCode["Moved"] = "Moved"; + HttpStatusCode["Found"] = "Redirect"; + HttpStatusCode["Redirect"] = "Redirect"; + HttpStatusCode["SeeOther"] = "RedirectMethod"; + HttpStatusCode["RedirectMethod"] = "RedirectMethod"; + HttpStatusCode["NotModified"] = "NotModified"; + HttpStatusCode["UseProxy"] = "UseProxy"; + HttpStatusCode["Unused"] = "Unused"; + HttpStatusCode["TemporaryRedirect"] = "TemporaryRedirect"; + HttpStatusCode["RedirectKeepVerb"] = "TemporaryRedirect"; + HttpStatusCode["PermanentRedirect"] = "PermanentRedirect"; + HttpStatusCode["BadRequest"] = "BadRequest"; + HttpStatusCode["Unauthorized"] = "Unauthorized"; + HttpStatusCode["PaymentRequired"] = "PaymentRequired"; + HttpStatusCode["Forbidden"] = "Forbidden"; + HttpStatusCode["NotFound"] = "NotFound"; + HttpStatusCode["MethodNotAllowed"] = "MethodNotAllowed"; + HttpStatusCode["NotAcceptable"] = "NotAcceptable"; + HttpStatusCode["ProxyAuthenticationRequired"] = "ProxyAuthenticationRequired"; + HttpStatusCode["RequestTimeout"] = "RequestTimeout"; + HttpStatusCode["Conflict"] = "Conflict"; + HttpStatusCode["Gone"] = "Gone"; + HttpStatusCode["LengthRequired"] = "LengthRequired"; + HttpStatusCode["PreconditionFailed"] = "PreconditionFailed"; + HttpStatusCode["RequestEntityTooLarge"] = "RequestEntityTooLarge"; + HttpStatusCode["RequestUriTooLong"] = "RequestUriTooLong"; + HttpStatusCode["UnsupportedMediaType"] = "UnsupportedMediaType"; + HttpStatusCode["RequestedRangeNotSatisfiable"] = "RequestedRangeNotSatisfiable"; + HttpStatusCode["ExpectationFailed"] = "ExpectationFailed"; + HttpStatusCode["MisdirectedRequest"] = "MisdirectedRequest"; + HttpStatusCode["UnprocessableEntity"] = "UnprocessableEntity"; + HttpStatusCode["Locked"] = "Locked"; + HttpStatusCode["FailedDependency"] = "FailedDependency"; + HttpStatusCode["UpgradeRequired"] = "UpgradeRequired"; + HttpStatusCode["PreconditionRequired"] = "PreconditionRequired"; + HttpStatusCode["TooManyRequests"] = "TooManyRequests"; + HttpStatusCode["RequestHeaderFieldsTooLarge"] = "RequestHeaderFieldsTooLarge"; + HttpStatusCode["UnavailableForLegalReasons"] = "UnavailableForLegalReasons"; + HttpStatusCode["InternalServerError"] = "InternalServerError"; + HttpStatusCode["NotImplemented"] = "NotImplemented"; + HttpStatusCode["BadGateway"] = "BadGateway"; + HttpStatusCode["ServiceUnavailable"] = "ServiceUnavailable"; + HttpStatusCode["GatewayTimeout"] = "GatewayTimeout"; + HttpStatusCode["HttpVersionNotSupported"] = "HttpVersionNotSupported"; + HttpStatusCode["VariantAlsoNegotiates"] = "VariantAlsoNegotiates"; + HttpStatusCode["InsufficientStorage"] = "InsufficientStorage"; + HttpStatusCode["LoopDetected"] = "LoopDetected"; + HttpStatusCode["NotExtended"] = "NotExtended"; + HttpStatusCode["NetworkAuthenticationRequired"] = "NetworkAuthenticationRequired"; +})(HttpStatusCode = exports.HttpStatusCode || (exports.HttpStatusCode = {})); +var ApiException = /** @class */ (function (_super) { + __extends(ApiException, _super); + function ApiException(message, status, response, headers, result) { + var _this = _super.call(this) || this; + _this.isApiException = true; + _this.message = message; + _this.status = status; + _this.response = response; + _this.headers = headers; + _this.result = result; + return _this; + } + ApiException.isApiException = function (obj) { + return obj.isApiException === true; + }; + return ApiException; +}(Error)); +exports.ApiException = ApiException; +function throwException(message, status, response, headers, result) { + if (result !== null && result !== undefined) + throw result; + else + throw new ApiException(message, status, response, headers, null); +} +//# sourceMappingURL=DashboardService.js.map \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.js.map b/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.js.map new file mode 100644 index 0000000..e7de3e0 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.js.map @@ -0,0 +1 @@ +{"version":3,"file":"DashboardService.js","sourceRoot":"","sources":["DashboardService.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.ts b/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.ts new file mode 100644 index 0000000..5a9dcdb --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/dashboard/DashboardService.ts @@ -0,0 +1,389 @@ +/* tslint:disable */ +/* eslint-disable */ +//---------------------- +// +// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org) +// +//---------------------- +// ReSharper disable InconsistentNaming + +export default class DashboardService { + private http: { fetch(url: RequestInfo, init?: RequestInit): Promise }; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise }) { + this.http = http ? http : window; + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : ""; + } + + getCount(): Promise { + let url_ = this.baseUrl + "/api/Services/count"; + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "GET", + headers: { + "Accept": "application/json", + 'Authorization': sessionStorage.getItem('user') + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processGetCount(_response); + }); + } + + protected processGetCount(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = resultData200 !== undefined ? resultData200 : null; + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + get(): Promise { + let url_ = this.baseUrl + "/api/Services"; + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "GET", + headers: { + "Accept": "application/json", + 'Authorization': sessionStorage.getItem('user') + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processGet(_response); + }); + } + + protected processGet(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + if (Array.isArray(resultData200)) { + result200 = [] as any; + for (let item of resultData200) + result200!.push(ServiceInfo.fromJS(item)); + } + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + post(request: ServiceRequest): Promise { + let url_ = this.baseUrl + "/api/Services"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(request); + + let options_ = { + body: content_, + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + 'Authorization': sessionStorage.getItem('user') + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processPost(_response); + }); + } + + protected processPost(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 201) { + return response.text().then((_responseText) => { + let result201: any = null; + let resultData201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result201 = ServiceRequest.fromJS(resultData201); + return result201; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + put(request: ServiceRequest): Promise { + let url_ = this.baseUrl + "/api/Services"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(request); + + let options_ = { + body: content_, + method: "PUT", + headers: { + "Content-Type": "application/json", + 'Authorization': sessionStorage.getItem('user') + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processPut(_response); + }); + } + + protected processPut(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 204) { + return response.text().then((_responseText) => { + return; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + delete(id: number): Promise { + let url_ = this.baseUrl + "/api/Services/{id}"; + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "DELETE", + headers: { + 'Authorization': sessionStorage.getItem('user') + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processDelete(_response); + }); + } + + protected processDelete(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 204) { + return response.text().then((_responseText) => { + return; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } +} + +export class ServiceInfo implements IServiceInfo { + service?: ServiceRequest | undefined; + statusCode!: HttpStatusCode; + response?: string | undefined; + + constructor(data?: IServiceInfo) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.service = _data["service"] ? ServiceRequest.fromJS(_data["service"]) : undefined; + this.statusCode = _data["statusCode"]; + this.response = _data["response"]; + } + } + + static fromJS(data: any): ServiceInfo { + data = typeof data === 'object' ? data : {}; + let result = new ServiceInfo(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["service"] = this.service ? this.service.toJSON() : undefined; + data["statusCode"] = this.statusCode; + data["response"] = this.response; + return data; + } +} + +export interface IServiceInfo { + service?: ServiceRequest | undefined; + statusCode: HttpStatusCode; + response?: string | undefined; +} + +export class ServiceRequest implements IServiceRequest { + id!: number; + name?: string | undefined; + uri?: string | undefined; + + constructor(data?: IServiceRequest) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.id = _data["id"]; + this.name = _data["name"]; + this.uri = _data["uri"]; + } + } + + static fromJS(data: any): ServiceRequest { + data = typeof data === 'object' ? data : {}; + let result = new ServiceRequest(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["name"] = this.name; + data["uri"] = this.uri; + return data; + } +} + +export interface IServiceRequest { + id: number; + name?: string | undefined; + uri?: string | undefined; +} + +export enum HttpStatusCode { + Continue = "Continue", + SwitchingProtocols = "SwitchingProtocols", + Processing = "Processing", + EarlyHints = "EarlyHints", + OK = "OK", + Created = "Created", + Accepted = "Accepted", + NonAuthoritativeInformation = "NonAuthoritativeInformation", + NoContent = "NoContent", + ResetContent = "ResetContent", + PartialContent = "PartialContent", + MultiStatus = "MultiStatus", + AlreadyReported = "AlreadyReported", + IMUsed = "IMUsed", + MultipleChoices = "Ambiguous", + Ambiguous = "Ambiguous", + MovedPermanently = "Moved", + Moved = "Moved", + Found = "Redirect", + Redirect = "Redirect", + SeeOther = "RedirectMethod", + RedirectMethod = "RedirectMethod", + NotModified = "NotModified", + UseProxy = "UseProxy", + Unused = "Unused", + TemporaryRedirect = "TemporaryRedirect", + RedirectKeepVerb = "TemporaryRedirect", + PermanentRedirect = "PermanentRedirect", + BadRequest = "BadRequest", + Unauthorized = "Unauthorized", + PaymentRequired = "PaymentRequired", + Forbidden = "Forbidden", + NotFound = "NotFound", + MethodNotAllowed = "MethodNotAllowed", + NotAcceptable = "NotAcceptable", + ProxyAuthenticationRequired = "ProxyAuthenticationRequired", + RequestTimeout = "RequestTimeout", + Conflict = "Conflict", + Gone = "Gone", + LengthRequired = "LengthRequired", + PreconditionFailed = "PreconditionFailed", + RequestEntityTooLarge = "RequestEntityTooLarge", + RequestUriTooLong = "RequestUriTooLong", + UnsupportedMediaType = "UnsupportedMediaType", + RequestedRangeNotSatisfiable = "RequestedRangeNotSatisfiable", + ExpectationFailed = "ExpectationFailed", + MisdirectedRequest = "MisdirectedRequest", + UnprocessableEntity = "UnprocessableEntity", + Locked = "Locked", + FailedDependency = "FailedDependency", + UpgradeRequired = "UpgradeRequired", + PreconditionRequired = "PreconditionRequired", + TooManyRequests = "TooManyRequests", + RequestHeaderFieldsTooLarge = "RequestHeaderFieldsTooLarge", + UnavailableForLegalReasons = "UnavailableForLegalReasons", + InternalServerError = "InternalServerError", + NotImplemented = "NotImplemented", + BadGateway = "BadGateway", + ServiceUnavailable = "ServiceUnavailable", + GatewayTimeout = "GatewayTimeout", + HttpVersionNotSupported = "HttpVersionNotSupported", + VariantAlsoNegotiates = "VariantAlsoNegotiates", + InsufficientStorage = "InsufficientStorage", + LoopDetected = "LoopDetected", + NotExtended = "NotExtended", + NetworkAuthenticationRequired = "NetworkAuthenticationRequired", +} + +export class ApiException extends Error { + message: string; + status: number; + response: string; + headers: { [key: string]: any; }; + result: any; + + constructor(message: string, status: number, response: string, headers: { [key: string]: any; }, result: any) { + super(); + + this.message = message; + this.status = status; + this.response = response; + this.headers = headers; + this.result = result; + } + + protected isApiException = true; + + static isApiException(obj: any): obj is ApiException { + return obj.isApiException === true; + } +} + +function throwException(message: string, status: number, response: string, headers: { [key: string]: any; }, result?: any): any { + if (result !== null && result !== undefined) + throw result; + else + throw new ApiException(message, status, response, headers, null); +} \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/dashboard/DeleteDialog.jsx b/Birdmap.API/ClientApp/src/components/dashboard/DeleteDialog.jsx new file mode 100644 index 0000000..bb523b7 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/dashboard/DeleteDialog.jsx @@ -0,0 +1,35 @@ +import Button from '@material-ui/core/Button'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import React from 'react'; + +export default function DeleteDialog(props) { + return ( +
+ props.handleClose(false)} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + {"Are you sure?"} + + + Deleting is permament. + + + + + + + +
+ ); +} diff --git a/Birdmap.API/ClientApp/src/components/dashboard/ServiceInfoComponent.jsx b/Birdmap.API/ClientApp/src/components/dashboard/ServiceInfoComponent.jsx new file mode 100644 index 0000000..0f68222 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/dashboard/ServiceInfoComponent.jsx @@ -0,0 +1,234 @@ +import { Box, FormControlLabel, Grid, IconButton, Paper, TextField, Typography } from '@material-ui/core'; +import Accordion from '@material-ui/core/Accordion'; +import AccordionDetails from '@material-ui/core/AccordionDetails'; +import AccordionSummary from '@material-ui/core/AccordionSummary'; +import { blueGrey, green, red } from '@material-ui/core/colors'; +import { CancelRounded, CheckCircleRounded, Delete, Edit } from '@material-ui/icons/'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import { withStyles } from '@material-ui/styles'; +import React, { Component } from 'react'; +import DeleteDialog from './DeleteDialog'; + +const styles = theme => ({ + root: { + flexGrow: 1, + padding: '64px', + backgroundColor: theme.palette.primary.dark, + }, + acc_summary: { + backgroundColor: blueGrey[50], + padding: theme.spacing(2), + textAlign: 'center', + height: '75px', + }, + acc_details: { + backgroundColor: blueGrey[100], + }, + grid_typo: { + fontSize: theme.typography.pxToRem(20), + fontWeight: theme.typography.fontWeightRegular, + }, + grid_typo_2: { + marginLeft: '5px', + fontSize: theme.typography.pxToRem(15), + fontWeight: theme.typography.fontWeightRegular, + color: theme.palette.text.secondary, + }, + typo: { + fontSize: theme.typography.pxToRem(20), + fontWeight: theme.typography.fontWeightRegular, + }, + icon_box: { + marginLeft: '30px', + }, + paper: { + backgroundColor: blueGrey[50], + padding: theme.spacing(2), + textAlign: 'center', + height: '75px', + } +}); + +class ServiceInfoComponent extends Component { + constructor(props) { + super(props); + + this.state = { + isDialogOpen: false, + isEditing: false, + name: "", + url: "", + } + + this.handleDialogClose = this.handleDialogClose.bind(this); + this.onNameChange = this.onNameChange.bind(this); + this.onUrlChange = this.onUrlChange.bind(this); + this.handleSaveCancel = this.handleSaveCancel.bind(this); + } + + componentDidMount() { + this.setState({ name: this.props.info.service.name, url: this.props.info.service.uri }); + + if (this.props.isEditing !== undefined) { + this.setState({ isEditing: this.props.isEditing }); + } + } + + onNameChange(event) { + this.setState({ name: event.target.value }); + } + + onUrlChange(event) { + this.setState({ url: event.target.value }); + } + + getColor(status) { + if (status === "OK") + return { color: green[600] }; + else + return { color: red[600] }; + } + + handleDialogClose(result) { + this.setState({ isDialogOpen: false }); + if (result === true) { + this.props.service.delete(this.props.info.service.id); + } + } + + handleEditCancel(value) { + this.setState({ isEditing: value }); + } + + handleSaveCancel() { + let request = { + ...this.props.info.service + }; + + request.name = this.state.name; + request.uri = this.state.url; + + if (request.id > 0) { + this.props.service.put(request).catch(ex => { + console.log(ex); + }); + } + else { + this.props.service.post(request).catch(ex => { + console.log(ex); + }); + } + + this.setState({ isEditing: false }); + } + + renderSaveCancel() { + return ( + + + + + this.setState({ isEditing: false })}> + + + + ); + } + + renderButtons() { + const renderEditDelete = () => { + return ( + + + this.handleEditCancel(true)}> + + + this.setState({ isDialogOpen: true })}> + + + + ); + } + + const { classes } = this.props; + return ( + + {this.props.isAdmin && this.props.info.service.name !== "Mqtt Client Service" ? renderEditDelete() : null} + + ); + } + + render() { + const { classes } = this.props; + + const renderAccordion = () => { + return ( + + } + aria-controls={"device-panel-/" + this.props.info.service.name} + id={"device-panel-/" + this.props.info.service.name}> + + + {this.props.info.service.name} + + + {this.props.info.service.uri} + + + + + event.stopPropagation()} + onFocus={(event) => event.stopPropagation()} + control={this.renderButtons()} /> + + + Status: {this.props.info.statusCode} + + + + + + + {this.props.info.response} + + + ); + }; + + const renderTextFields = () => { + return ( + + + + + + + + + + {this.renderSaveCancel()} + + + + ); + }; + + return this.state.isEditing ? renderTextFields() : renderAccordion(); + } +} + +export default withStyles(styles)(ServiceInfoComponent); \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/dashboard/ServiceInfoSkeleton.jsx b/Birdmap.API/ClientApp/src/components/dashboard/ServiceInfoSkeleton.jsx new file mode 100644 index 0000000..17d6a65 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/dashboard/ServiceInfoSkeleton.jsx @@ -0,0 +1,88 @@ +import { Grid, Typography } from '@material-ui/core'; +import Accordion from '@material-ui/core/Accordion'; +import AccordionDetails from '@material-ui/core/AccordionDetails'; +import AccordionSummary from '@material-ui/core/AccordionSummary'; +import { blueGrey } from '@material-ui/core/colors'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import { Skeleton } from '@material-ui/lab'; +import { withStyles } from '@material-ui/styles'; +import React, { Component } from 'react'; + +const styles = theme => ({ + acc_summary: { + backgroundColor: blueGrey[50], + padding: theme.spacing(2), + textAlign: 'center', + height: '75px', + }, + acc_details: { + backgroundColor: blueGrey[100], + }, + grid_typo: { + fontSize: theme.typography.pxToRem(20), + fontWeight: theme.typography.fontWeightRegular, + }, + grid_typo_2: { + marginLeft: '5px', + fontSize: theme.typography.pxToRem(15), + fontWeight: theme.typography.fontWeightRegular, + color: theme.palette.text.secondary, + }, +}); + +class ServiceInfoSkeleton extends Component { + + render() { + const { classes } = this.props; + + return ( + + }> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } +} + +export default withStyles(styles)(ServiceInfoSkeleton); \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/devices/DeviceComponent.jsx b/Birdmap.API/ClientApp/src/components/devices/DeviceComponent.jsx index 7415a93..6e73d8d 100644 --- a/Birdmap.API/ClientApp/src/components/devices/DeviceComponent.jsx +++ b/Birdmap.API/ClientApp/src/components/devices/DeviceComponent.jsx @@ -1,14 +1,14 @@ -import React, { Component } from 'react'; +import { Box, FormControlLabel, Grid, IconButton, Typography } from '@material-ui/core'; import Accordion from '@material-ui/core/Accordion'; -import { blue, blueGrey, green, orange, red, yellow } from '@material-ui/core/colors'; -import AccordionSummary from '@material-ui/core/AccordionSummary'; import AccordionDetails from '@material-ui/core/AccordionDetails'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import { Grid, Typography, Paper, IconButton, Box, FormControlLabel } from '@material-ui/core'; -import { withStyles } from '@material-ui/styles'; -import { withRouter } from "react-router"; +import AccordionSummary from '@material-ui/core/AccordionSummary'; +import { blueGrey, green, orange, red } from '@material-ui/core/colors'; import { Power, PowerOff, Refresh } from '@material-ui/icons/'; -import DeviceService from '../../common/DeviceService' +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import { withStyles } from '@material-ui/styles'; +import React, { Component } from 'react'; +import { withRouter } from "react-router"; +import DeviceService from '../../common/DeviceService'; import DevicesContext from '../../contexts/DevicesContext'; const styles = theme => ({ @@ -31,6 +31,7 @@ const styles = theme => ({ grid_item: { width: '100%', marginLeft: '5px', + marginRight: '30px', }, grid_item_typo: { fontSize: theme.typography.pxToRem(15), diff --git a/Birdmap.API/ClientApp/src/components/devices/Devices.jsx b/Birdmap.API/ClientApp/src/components/devices/Devices.jsx index 5e3d2d4..313295a 100644 --- a/Birdmap.API/ClientApp/src/components/devices/Devices.jsx +++ b/Birdmap.API/ClientApp/src/components/devices/Devices.jsx @@ -1,11 +1,11 @@ -import { Box, Paper, Typography, IconButton, Grid } from '@material-ui/core'; -import { blue, blueGrey, green, orange, red, yellow } from '@material-ui/core/colors'; +import { Box, Grid, IconButton, Paper, Typography } from '@material-ui/core'; +import { blueGrey } from '@material-ui/core/colors'; +import { Power, PowerOff, Refresh } from '@material-ui/icons/'; import { withStyles } from '@material-ui/styles'; import React from 'react'; import DeviceService from '../../common/DeviceService'; import DevicesContext from '../../contexts/DevicesContext'; import DeviceComponent from './DeviceComponent'; -import { Power, PowerOff, Refresh } from '@material-ui/icons/'; const styles = theme => ({ root: { @@ -15,7 +15,6 @@ const styles = theme => ({ paper: { backgroundColor: blueGrey[50], height: '60px', - margin: 'auto', }, typo: { fontSize: theme.typography.pxToRem(20), @@ -69,15 +68,15 @@ class Devices extends React.Component { All Devices - {this.renderButtons()} + {this.renderButtons()} diff --git a/Birdmap.API/ClientApp/src/components/heatmap/DeviceMarker.jsx b/Birdmap.API/ClientApp/src/components/heatmap/DeviceMarker.jsx index 80823c3..fc4f5b3 100644 --- a/Birdmap.API/ClientApp/src/components/heatmap/DeviceMarker.jsx +++ b/Birdmap.API/ClientApp/src/components/heatmap/DeviceMarker.jsx @@ -1,11 +1,9 @@ -import RadioButtonCheckedIcon from '@material-ui/icons/RadioButtonChecked'; -import PlayCircleFilledIcon from '@material-ui/icons/PlayCircleFilled'; -import { shadows } from '@material-ui/system'; -import { Box, Popover, Typography, Tooltip, Grid } from '@material-ui/core'; +import { Box, Tooltip } from '@material-ui/core'; import { blue, red, yellow } from '@material-ui/core/colors'; -import React, { Component } from 'react'; -import { useHistory, withRouter } from 'react-router-dom'; +import RadioButtonCheckedIcon from '@material-ui/icons/RadioButtonChecked'; import { makeStyles } from '@material-ui/styles'; +import React, { Component } from 'react'; +import { withRouter } from 'react-router-dom'; class DeviceMarker extends Component { constructor(props) { diff --git a/Birdmap.API/ClientApp/src/components/heatmap/Heatmap.jsx b/Birdmap.API/ClientApp/src/components/heatmap/Heatmap.jsx index a200483..11a6cca 100644 --- a/Birdmap.API/ClientApp/src/components/heatmap/Heatmap.jsx +++ b/Birdmap.API/ClientApp/src/components/heatmap/Heatmap.jsx @@ -1,9 +1,9 @@ /*global google*/ import GoogleMapReact from 'google-map-react'; import React, { Component } from 'react'; -import DeviceMarker from './DeviceMarker' -import C from '../../common/Constants' +import C from '../../common/Constants'; import DevicesContext from '../../contexts/DevicesContext'; +import DeviceMarker from './DeviceMarker'; const lat_offset = 0.000038; const lng_offset = -0.000058; diff --git a/Birdmap.API/ClientApp/src/contexts/DevicesContextProvider.js b/Birdmap.API/ClientApp/src/contexts/DevicesContextProvider.js index 21e1185..9680b77 100644 --- a/Birdmap.API/ClientApp/src/contexts/DevicesContextProvider.js +++ b/Birdmap.API/ClientApp/src/contexts/DevicesContextProvider.js @@ -96,7 +96,7 @@ export default class DevicesContextProvider extends Component { newConnection.start() .then(_ => { - console.log('Hub Connected!'); + console.log('Devices hub Connected!'); newConnection.on(C.probability_method_name, (id, date, prob) => { //console.log(method_name + " recieved: [id: " + id + ", date: " + date + ", prob: " + prob + "]"); @@ -115,7 +115,7 @@ export default class DevicesContextProvider extends Component { }); newConnection.on(C.update_method_name, (id) => this.updateDeviceInternal(id, service)); - }).catch(e => console.log('Hub Connection failed: ', e)); + }).catch(e => console.log('Devices hub Connection failed: ', e)); } componentWillUnmount() { @@ -123,7 +123,7 @@ export default class DevicesContextProvider extends Component { this.state.hubConnection.off(C.probability_method_name); this.state.hubConnection.off(C.update_all_method_name); this.state.hubConnection.off(C.update_method_name); - console.log('Hub Disconnected!'); + console.log('Devices hub Disconnected!'); } } diff --git a/Birdmap.API/Controllers/ServicesController.cs b/Birdmap.API/Controllers/ServicesController.cs index 869f84c..79aa554 100644 --- a/Birdmap.API/Controllers/ServicesController.cs +++ b/Birdmap.API/Controllers/ServicesController.cs @@ -1,14 +1,19 @@ using AutoMapper; using Birdmap.API.DTOs; +using Birdmap.API.Services; +using Birdmap.API.Services.Hubs; +using Birdmap.API.Services.Mqtt; using Birdmap.BLL.Interfaces; using Birdmap.DAL.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -21,21 +26,34 @@ namespace Birdmap.API.Controllers { private readonly IServiceService _service; private readonly IMapper _mapper; + private readonly IMqttClientService _mqttClientService; + private readonly IHubContext _hubContext; private readonly ILogger _logger; - public ServicesController(IServiceService service, IMapper mapper, ILogger logger) + public ServicesController(IServiceService service, IMapper mapper, MqttClientServiceProvider mqttClientProvider, + IHubContext hubContext, ILogger logger) { _service = service; _mapper = mapper; + _mqttClientService = mqttClientProvider.MqttClientService; + _hubContext = hubContext; _logger = logger; } + [HttpGet("count"), ProducesResponseType(StatusCodes.Status200OK)] + public async Task> GetCountAsync() + { + _logger.LogInformation($"Getting service count from db..."); + + return await _service.GetServiceCountAsync() + 1; + } + [HttpGet, ProducesResponseType(StatusCodes.Status200OK)] public async Task>> GetAsync() { _logger.LogInformation($"Getting all services from db..."); var serviceInfos = (await _service.GetAllServicesAsync()) - .Select(s => new ServiceInfo { Service = _mapper.Map(s) }); + .Select(s => new ServiceInfo { Service = _mapper.Map(s) }).ToList(); var client = new HttpClient(); foreach (var si in serviceInfos) @@ -50,11 +68,23 @@ namespace Birdmap.API.Controllers catch (Exception ex) { _logger.LogWarning($"Requesting service [{si.Service.Name}] faulted."); - si.StatusCode = System.Net.HttpStatusCode.ServiceUnavailable; + si.StatusCode = HttpStatusCode.ServiceUnavailable; si.Response = ex.ToString(); } } + serviceInfos.Add(new() + { + Service = new() + { + Id = 0, + Name = "Mqtt Client Service", + Uri = "localhost", + }, + Response = $"IsConnected: {_mqttClientService.IsConnected}", + StatusCode = _mqttClientService.IsConnected ? HttpStatusCode.OK : HttpStatusCode.ServiceUnavailable, + }); + return serviceInfos.ToList(); } @@ -67,6 +97,7 @@ namespace Birdmap.API.Controllers _mapper.Map(request)); _logger.LogInformation($"Created service [{created.Id}]."); + await _hubContext.Clients.All.NotifyUpdatedAsync(); return CreatedAtAction( nameof(GetAsync), @@ -82,6 +113,7 @@ namespace Birdmap.API.Controllers service.IsFromConfig = false; await _service.UpdateServiceAsync(service); + await _hubContext.Clients.All.NotifyUpdatedAsync(); return NoContent(); } @@ -93,6 +125,7 @@ namespace Birdmap.API.Controllers _logger.LogInformation($"Deleting service [{id}]..."); await _service.DeleteServiceAsync(id); + await _hubContext.Clients.All.NotifyUpdatedAsync(); return NoContent(); } diff --git a/Birdmap.API/Services/Hubs/DevicesHub.cs b/Birdmap.API/Services/Hubs/DevicesHub.cs index 887b548..9938b42 100644 --- a/Birdmap.API/Services/Hubs/DevicesHub.cs +++ b/Birdmap.API/Services/Hubs/DevicesHub.cs @@ -16,31 +16,16 @@ namespace Birdmap.API.Services.Hubs public override Task OnConnectedAsync() { - _logger.LogInformation("Hub Client connected."); + _logger.LogInformation("Devices Hub Client connected."); return base.OnConnectedAsync(); } public override Task OnDisconnectedAsync(Exception exception) { - _logger.LogInformation("Hub Client disconnected."); + _logger.LogInformation("Devices Hub Client disconnected."); return base.OnDisconnectedAsync(exception); } - - public Task SendProbabilityAsync(Guid deviceId, DateTime date, double probability) - { - return Clients.All.NotifyDeviceAsync(deviceId, date, probability); - } - - public Task SendDeviceUpdateAsync(Guid deviceId) - { - return Clients.All.NotifyDeviceUpdatedAsync(deviceId); - } - - public Task SendAllUpdatedAsync() - { - return Clients.All.NotifyAllUpdatedAsync(); - } } } diff --git a/Birdmap.API/Services/Hubs/IServicesHubClient.cs b/Birdmap.API/Services/Hubs/IServicesHubClient.cs new file mode 100644 index 0000000..6891865 --- /dev/null +++ b/Birdmap.API/Services/Hubs/IServicesHubClient.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Birdmap.API.Services.Hubs +{ + public interface IServicesHubClient + { + Task NotifyUpdatedAsync(); + } +} diff --git a/Birdmap.API/Services/Hubs/ServicesHub.cs b/Birdmap.API/Services/Hubs/ServicesHub.cs new file mode 100644 index 0000000..17f3ae2 --- /dev/null +++ b/Birdmap.API/Services/Hubs/ServicesHub.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; + +namespace Birdmap.API.Services.Hubs +{ + public class ServicesHub : Hub + { + private readonly ILogger _logger; + + public ServicesHub(ILogger logger) + { + _logger = logger; + } + + public override Task OnConnectedAsync() + { + _logger.LogInformation("Services Hub Client connected."); + + return base.OnConnectedAsync(); + } + + public override Task OnDisconnectedAsync(Exception exception) + { + _logger.LogInformation("Services Hub Client disconnected."); + + return base.OnDisconnectedAsync(exception); + } + } +} diff --git a/Birdmap.API/Services/IMqttClientService.cs b/Birdmap.API/Services/IMqttClientService.cs index a8e4676..8316d9a 100644 --- a/Birdmap.API/Services/IMqttClientService.cs +++ b/Birdmap.API/Services/IMqttClientService.cs @@ -10,6 +10,6 @@ namespace Birdmap.API.Services IMqttClientDisconnectedHandler, IMqttApplicationMessageReceivedHandler { - + public bool IsConnected { get; } } } diff --git a/Birdmap.API/Services/Mqtt/MqttClientService.cs b/Birdmap.API/Services/Mqtt/MqttClientService.cs index 6ca123e..2ed4abf 100644 --- a/Birdmap.API/Services/Mqtt/MqttClientService.cs +++ b/Birdmap.API/Services/Mqtt/MqttClientService.cs @@ -9,7 +9,6 @@ using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Options; using Newtonsoft.Json; using System; -using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -24,6 +23,8 @@ namespace Birdmap.API.Services.Mqtt private readonly IInputService _inputService; private readonly IHubContext _hubContext; + public bool IsConnected => _mqttClient.IsConnected; + public MqttClientService(IMqttClientOptions options, ILogger logger, IInputService inputService, IHubContext hubContext) { _options = options; diff --git a/Birdmap.API/Startup.cs b/Birdmap.API/Startup.cs index 16d53c9..fa906fd 100644 --- a/Birdmap.API/Startup.cs +++ b/Birdmap.API/Startup.cs @@ -139,6 +139,7 @@ namespace Birdmap.API endpoints.MapHealthChecks("/health"); endpoints.MapControllers(); endpoints.MapHub("/hubs/devices"); + endpoints.MapHub("/hubs/services"); }); app.UseSpa(spa => diff --git a/Birdmap.API/libman.json b/Birdmap.API/libman.json new file mode 100644 index 0000000..ceee271 --- /dev/null +++ b/Birdmap.API/libman.json @@ -0,0 +1,5 @@ +{ + "version": "1.0", + "defaultProvider": "cdnjs", + "libraries": [] +} \ No newline at end of file diff --git a/Birdmap.BLL/Interfaces/IServiceService.cs b/Birdmap.BLL/Interfaces/IServiceService.cs index 7db279b..f281040 100644 --- a/Birdmap.BLL/Interfaces/IServiceService.cs +++ b/Birdmap.BLL/Interfaces/IServiceService.cs @@ -6,6 +6,7 @@ namespace Birdmap.BLL.Interfaces { public interface IServiceService { + Task GetServiceCountAsync(); Task> GetAllServicesAsync(); Task GetServiceAsync(int id); Task CreateServiceAsync(Service service); diff --git a/Birdmap.BLL/Services/DummyDeviceAndInputService.cs b/Birdmap.BLL/Services/DummyDeviceAndInputService.cs index 00fc2c4..18a86bd 100644 --- a/Birdmap.BLL/Services/DummyDeviceAndInputService.cs +++ b/Birdmap.BLL/Services/DummyDeviceAndInputService.cs @@ -16,12 +16,12 @@ namespace Birdmap.BLL.Services private const double centerLat = 48.275939; private const double radius = 0.001; - private static readonly Random Rand = new Random(); + private static readonly Random Rand = new(); - private static readonly Lazy> Devices = new Lazy>(GenerateDevices); + private static readonly Lazy> Devices = new(GenerateDevices); - private static readonly Dictionary TagToInput = new Dictionary(); - private static readonly object InputLock = new object(); + private static readonly Dictionary TagToInput = new(); + private static readonly object InputLock = new(); private static ListOfDevices GenerateDevices() { @@ -43,20 +43,20 @@ namespace Birdmap.BLL.Services var sensors = new ArrayofSensors(); for (int s = 0; s < Rand.Next(1, 6); s++) { - sensors.Add(new Sensor + sensors.Add(new() { Id = Guid.NewGuid(), Status = GetRandomEnum(), }); } - devices.Add(new Device + devices.Add(new() { Id = Guid.NewGuid(), Sensors = sensors, Status = GetRandomEnum(), Url = "dummyservice.device.url", - Coordinates = new Coordinates + Coordinates = new() { Latitude = GetPlusMinus(centerLat, radius), Longitude = GetPlusMinus(centerLong, radius), @@ -150,10 +150,10 @@ namespace Birdmap.BLL.Services { if (!TagToInput.TryGetValue(tagID, out var value)) { - value = new InputSingeResponse + value = new() { Status = "Dummy_OK", - Message = new InputObject + Message = new() { Tag = tagID, Date = DateTime.Now, diff --git a/Birdmap.BLL/Services/ServiceService.cs b/Birdmap.BLL/Services/ServiceService.cs index 04c63ea..e2bf0a2 100644 --- a/Birdmap.BLL/Services/ServiceService.cs +++ b/Birdmap.BLL/Services/ServiceService.cs @@ -17,6 +17,11 @@ namespace Birdmap.BLL.Services _context = context; } + public Task GetServiceCountAsync() + { + return _context.Services.CountAsync(); + } + public async Task CreateServiceAsync(Service service) { _context.Services.Add(service);