Merge branch 'dmgt-ra/feature/eslint' into 'master'

Add ESLint to devicemgt react app

Closes product-iots#291

See merge request entgra/carbon-device-mgt!419
This commit is contained in:
Dharmakeerthi Lasantha 2020-01-16 07:27:30 +00:00
commit c34811f0e7
59 changed files with 9836 additions and 9097 deletions

View File

@ -82,6 +82,16 @@
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>lint</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run-script lint</arguments>
</configuration>
<phase>generate-resources</phase>
</execution>
<execution>
<id>prod</id>
<goals>

View File

@ -0,0 +1,325 @@
{
"parser": "babel-eslint",
"plugins": [
"react",
"babel",
"jsx",
"prettier"
],
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaVersion": 2016,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"settings": {
"react": {
"createClass": "createReactClass",
"pragma": "React",
"version": "16.8.6"
}
},
"env": {
"node": true,
"commonjs": true,
"browser": true,
"jasmine": true,
"es6": true
},
"globals": {
"document": true,
"console": true,
// Only for development purposes
"setTimeout": true,
"window" : true
},
"rules": {
"prettier/prettier": "error",
// Enforce the spacing around the * in generator functions.
"generator-star-spacing": [2, "after"],
// Disallow using variables outside the blocks they are defined (especially
// since only let and const are used, see "no-var").
"block-scoped-var": 2,
// Require camel case names
"camelcase": 2,
// Allow trailing commas for easy list extension. Having them does not
// impair readability, but also not required either.
"comma-dangle": 0,
// Warn about cyclomatic complexity in functions.
"complexity": 1,
// Don't warn for inconsistent naming when capturing this (not so important
// with auto-binding fat arrow functions).
"consistent-this": 0,
// Enforce curly brace conventions for all control statements.
"curly": 2,
// Don't require a default case in switch statements. Avoid being forced to
// add a bogus default when you know all possible cases are handled.
"default-case": 0,
// Encourage the use of dot notation whenever possible.
"dot-notation": 2,
// Allow mixed 'LF' and 'CRLF' as linebreaks.
"linebreak-style": 0,
// Don't enforce the maximum depth that blocks can be nested.
"max-depth": 0,
// Maximum length of a line.
"max-len": [2, 120, 2, { "ignoreStrings": true, "ignoreUrls": true}],
// Maximum depth callbacks can be nested.
"max-nested-callbacks": [2, 3],
// Don't limit the number of parameters that can be used in a function.
"max-params": 0,
// Don't limit the maximum number of statement allowed in a function.
"max-statements": 0,
// Require a capital letter for constructors, only check if all new
// operators are followed by a capital letter. Don't warn when capitalized
// functions are used without the new operator.
"new-cap": [2, {"capIsNew": false}],
// Disallow use of the Array constructor.
"no-array-constructor": 2,
// Allow use of bitwise operators.
"no-bitwise": 0,
// Disallow use of arguments.caller or arguments.callee.
"no-caller": 2,
// Disallow the catch clause parameter name being the same as a variable in
// the outer scope, to avoid confusion.
"no-catch-shadow": 2,
// Disallow assignment in conditional expressions.
"no-cond-assign": 2,
// Allow using the console API.
"no-console": 0,
// Allow using constant expressions in conditions like while (true)
"no-constant-condition": 0,
// Allow use of the continue statement.
"no-continue": 0,
// Disallow control characters in regular expressions.
"no-control-regex": 2,
// Disallow deletion of variables (deleting properties is fine).
"no-delete-var": 2,
// Disallow duplicate arguments in functions.
"no-dupe-args": 2,
// Disallow duplicate keys when creating object literals.
"no-dupe-keys": 2,
// Disallow multiple empty lines
"no-multiple-empty-lines": "error",
// Disallow a duplicate case label.
"no-duplicate-case": 2,
// Disallow else after a return in an if. The else around the second return
// here is useless:
// if (something) { return false; } else { return true; }
"no-else-return": 2,
// Disallow empty statements. This will report an error for:
// try { something(); } catch (e) {}
// but will not report it for:
// try { something(); } catch (e) { /* Silencing the error because ...*/ }
// which is a valid use case.
"no-empty": 2,
// Disallow the use of empty character classes in regular expressions.
"no-empty-character-class": 2,
// Disallow use of labels for anything other then loops and switches.
"no-labels": 2,
// Disallow use of eval(). We have other APIs to evaluate code in content.
"no-eval": 2,
// Disallow assigning to the exception in a catch block.
"no-ex-assign": 2,
// Disallow adding to native types
"no-extend-native": 2,
// Disallow unnecessary function binding.
"no-extra-bind": 2,
// Disallow double-negation boolean casts in a boolean context.
"no-extra-boolean-cast": 2,
// Allow unnecessary parentheses, as they may make the code more readable.
"no-extra-parens": 0,
// Disallow fallthrough of case statements, except if there is a comment.
"no-fallthrough": 2,
// Allow the use of leading or trailing decimal points in numeric literals.
"no-floating-decimal": 0,
// Disallow if as the only statement in an else block.
"no-lonely-if": 2,
// Disallow use of multiline strings (use template strings instead).
"no-multi-str": 2,
// Disallow reassignments of native objects.
"no-native-reassign": 2,
// Disallow nested ternary expressions, they make the code hard to read.
"no-nested-ternary": 2,
// Allow use of new operator with the require function.
"no-new-require": 0,
// Disallow use of octal literals.
"no-octal": 2,
// Allow reassignment of function parameters.
"no-param-reassign": 0,
// Allow string concatenation with __dirname and __filename (not a node env).
"no-path-concat": 0,
// Allow use of unary operators, ++ and --.
"no-plusplus": 0,
// Allow using process.env (not a node environment).
"no-process-env": 0,
// Allow using process.exit (not a node environment).
"no-process-exit": 0,
// Disallow usage of __proto__ property.
"no-proto": 2,
// Disallow declaring the same variable more than once (we use let anyway).
"no-redeclare": 2,
// Disallow multiple spaces in a regular expression literal.
"no-regex-spaces": 2,
// Allow reserved words being used as object literal keys.
"no-reserved-keys": 0,
// Don't restrict usage of specified node modules (not a node environment).
"no-restricted-modules": 0,
// Disallow use of assignment in return statement. It is preferable for a
// single line of code to have only one easily predictable effect.
"no-return-assign": 2,
// Allow use of javascript: urls.
"no-script-url": 0,
// Disallow comparisons where both sides are exactly the same.
"no-self-compare": 2,
// Disallow use of comma operator.
"no-sequences": 2,
// Warn about declaration of variables already declared in the outer scope.
// This isn't an error because it sometimes is useful to use the same name
// in a small helper function rather than having to come up with another
// random name.
// Still, making this a warning can help people avoid being confused.
"no-shadow": 0,
// Require empty line at end of file
"eol-last": "error",
// Disallow shadowing of names such as arguments.
"no-shadow-restricted-names": 2,
"no-space-before-semi": 0,
// Disallow sparse arrays, eg. let arr = [,,2].
// Array destructuring is fine though:
// for (let [, breakpointPromise] of aPromises)
"no-sparse-arrays": 2,
// Allow use of synchronous methods (not a node environment).
"no-sync": 0,
// Allow the use of ternary operators.
"no-ternary": 0,
// Don't allow spaces after end of line
"no-trailing-spaces": "error",
// Disallow throwing literals (eg. throw "error" instead of
// throw new Error("error")).
"no-throw-literal": 2,
// Disallow use of undeclared variables unless mentioned in a /*global */
// block. Note that globals from head.js are automatically imported in tests
// by the import-headjs-globals rule form the mozilla eslint plugin.
"no-undef": 2,
// Allow use of undefined variable.
"no-undefined": 0,
// Disallow the use of Boolean literals in conditional expressions.
"no-unneeded-ternary": 2,
// Disallow unreachable statements after a return, throw, continue, or break
// statement.
"no-unreachable": 2,
// Allow using variables before they are defined.
"no-unused-vars": [2, {"vars": "all", "args": "none"}],
// Disallow global and local variables that arent used, but allow unused function arguments.
"no-use-before-define": 0,
// We use var-only-at-top-level instead of no-var as we allow top level
// vars.
"no-var": 0,
// Allow using TODO/FIXME comments.
"no-warning-comments": 0,
// Disallow use of the with statement.
"no-with": 2,
// Dont require method and property shorthand syntax for object literals.
// We use this in the code a lot, but not consistently, and this seems more
// like something to check at code review time.
"object-shorthand": 0,
// Allow more than one variable declaration per function.
"one-var": 0,
// Single quotes should be used.
"quotes": [2, "single", "avoid-escape"],
// Require use of the second argument for parseInt().
"radix": 2,
// Dont require to sort variables within the same declaration block.
// Anyway, one-var is disabled.
"sort-vars": 0,
"space-after-function-name": 0,
"space-before-function-parentheses": 0,
// Disallow space before function opening parenthesis.
//"space-before-function-paren": [2, "never"],
// Disable the rule that checks if spaces inside {} and [] are there or not.
// Our code is split on conventions, and itd be nice to have 2 rules
// instead, one for [] and one for {}. So, disabling until we write them.
"space-in-brackets": 0,
// Deprecated, will be removed in 1.0.
"space-unary-word-ops": 0,
// Require a space immediately following the // in a line comment.
"spaced-comment": [2, "always"],
// Require "use strict" to be defined globally in the script.
"strict": [2, "global"],
// Disallow comparisons with the value NaN.
"use-isnan": 2,
// Warn about invalid JSDoc comments.
// Disabled for now because of https://github.com/eslint/eslint/issues/2270
// The rule fails on some jsdoc comments like in:
// devtools/client/webconsole/console-output.js
"valid-jsdoc": 0,
// Ensure that the results of typeof are compared against a valid string.
"valid-typeof": 2,
// Allow vars to be declared anywhere in the scope.
"vars-on-top": 0,
// Dont require immediate function invocation to be wrapped in parentheses.
"wrap-iife": 0,
// Don't require regex literals to be wrapped in parentheses (which
// supposedly prevent them from being mistaken for division operators).
"wrap-regex": 0,
// Require for-in loops to have an if statement.
"guard-for-in": 0,
// allow/disallow an empty newline after var statement
"newline-after-var": 0,
// disallow the use of alert, confirm, and prompt
"no-alert": 0,
// disallow the use of deprecated react changes and lifecycle methods
"react/no-deprecated": 0,
// disallow comparisons to null without a type-checking operator
"no-eq-null": 0,
// disallow overwriting functions written as function declarations
"no-func-assign": 0,
// disallow use of eval()-like methods
"no-implied-eval": 0,
// disallow function or variable declarations in nested blocks
"no-inner-declarations": 0,
// disallow invalid regular expression strings in the RegExp constructor
"no-invalid-regexp": 0,
// disallow irregular whitespace outside of strings and comments
"no-irregular-whitespace": 0,
// disallow unnecessary nested blocks
"no-lone-blocks": 0,
// disallow creation of functions within loops
"no-loop-func": 0,
// disallow use of new operator when not part of the assignment or
// comparison
"no-new": 0,
// disallow use of new operator for Function object
"no-new-func": 0,
// disallow use of the Object constructor
"no-new-object": 0,
// disallows creating new instances of String,Number, and Boolean
"no-new-wrappers": 0,
// disallow the use of object properties of the global object (Math and
// JSON) as functions
"no-obj-calls": 0,
// disallow use of octal escape sequences in string literals, such as
// var foo = "Copyright \251";
"no-octal-escape": 0,
// disallow use of undefined when initializing variables
"no-undef-init": 0,
// disallow usage of expressions in statement position
"no-unused-expressions": 0,
// disallow use of void operator
"no-void": 0,
// disallow wrapping of non-IIFE statements in parens
"no-wrap-func": 0,
// require assignment operator shorthand where possible or prohibit it
// entirely
"operator-assignment": 0,
// enforce operators to be placed before or after line breaks
"operator-linebreak": 0,
// disable chacking prop types
"react/prop-types": 0
}
}

View File

@ -0,0 +1,5 @@
{
"singleQuote": true,
"trailingComma": "all",
"parser": "flow"
}

View File

@ -16,14 +16,13 @@
* under the License.
*/
module.exports = function (api) {
module.exports = function(api) {
api.cache(true);
const presets = [ "@babel/preset-env",
"@babel/preset-react" ];
const plugins = ["@babel/plugin-proposal-class-properties"];
const presets = ['@babel/preset-env', '@babel/preset-react'];
const plugins = ['@babel/plugin-proposal-class-properties'];
return {
presets,
plugins
plugins,
};
};
};

View File

@ -8,6 +8,7 @@
"acorn": "^6.2.0",
"antd": "^3.23.5",
"axios": "^0.18.1",
"babel-eslint": "^9.0.0",
"bizcharts": "^3.5.6",
"bootstrap": "^4.3.1",
"javascript-time-ago": "^2.0.1",
@ -46,6 +47,12 @@
"body-parser": "^1.19.0",
"chai": "^4.1.2",
"css-loader": "^0.28.11",
"eslint": "^5.16.0",
"eslint-config-prettier": "4.3.0",
"eslint-plugin-babel": "5.3.0",
"eslint-plugin-jsx": "0.0.2",
"eslint-plugin-prettier": "3.1.0",
"eslint-plugin-react": "7.14.2",
"express": "^4.17.1",
"express-pino-logger": "^4.0.0",
"file-loader": "^2.0.0",
@ -64,6 +71,7 @@
"npm-run-all": "^4.1.5",
"pino-colada": "^1.4.5",
"postcss-loader": "^3.0.0",
"prettier": "1.18.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-intl": "^2.9.0",
@ -84,6 +92,7 @@
"build_prod": "NODE_ENV=production NODE_OPTIONS=--max_old_space_size=4096 webpack -p --display errors-only --hide-modules",
"build_dev": "NODE_ENV=development webpack -d --watch ",
"server": "node-env-run server --exec nodemon | pino-colada",
"dev2": "run-p server start"
"dev2": "run-p server start",
"lint": "eslint \"src/**/*.js\""
}
}

View File

@ -16,153 +16,156 @@
* under the License.
*/
import React from "react";
import "antd/dist/antd.less";
import RouteWithSubRoutes from "./components/RouteWithSubRoutes";
import {
BrowserRouter as Router,
Redirect, Switch,
} from 'react-router-dom';
import axios from "axios";
import {Layout, Spin, Result, message, notification} from "antd";
import ConfigContext from "./context/ConfigContext";
import React from 'react';
import 'antd/dist/antd.less';
import RouteWithSubRoutes from './components/RouteWithSubRoutes';
import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
import axios from 'axios';
import { Layout, Spin, Result, notification } from 'antd';
import ConfigContext from './context/ConfigContext';
const {Content} = Layout;
const { Content } = Layout;
const loadingView = (
<Layout>
<Content style={{
padding: '0 0',
paddingTop: 300,
backgroundColor: '#fff',
textAlign: 'center'
}}>
<Spin tip="Loading..."/>
</Content>
</Layout>
<Layout>
<Content
style={{
padding: '0 0',
paddingTop: 300,
backgroundColor: '#fff',
textAlign: 'center',
}}
>
<Spin tip="Loading..." />
</Content>
</Layout>
);
const errorView = (
<Result
style={{
paddingTop: 200
}}
status="500"
title="Error occurred while loading the configuration"
subTitle="Please refresh your browser window"
/>
<Result
style={{
paddingTop: 200,
}}
status="500"
title="Error occurred while loading the configuration"
subTitle="Please refresh your browser window"
/>
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
error: false,
config: {},
};
}
constructor(props) {
super(props);
this.state = {
loading: true,
error: false,
config: {}
componentDidMount() {
axios
.get(window.location.origin + '/entgra/public/conf/config.json')
.then(res => {
const config = res.data;
this.checkUserLoggedIn(config);
})
.catch(error => {
this.setState({
loading: false,
error: true,
});
});
}
checkUserLoggedIn = config => {
axios
.post(
window.location.origin + '/entgra-ui-request-handler/user',
'platform=entgra',
)
.then(res => {
config.user = res.data.data;
const pageURL = window.location.pathname;
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
if (lastURLSegment === 'login') {
window.location.href = window.location.origin + '/entgra/';
} else {
this.setState({
loading: false,
config: config,
});
}
}
componentDidMount() {
axios.get(
window.location.origin + "/entgra/public/conf/config.json",
).then(res => {
const config = res.data;
this.checkUserLoggedIn(config);
}).catch((error) => {
this.getDeviceTypes(config);
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
const redirectUrl = encodeURI(window.location.href);
const pageURL = window.location.pathname;
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
if (lastURLSegment !== 'login') {
window.location.href =
window.location.origin + `/entgra/login?redirect=${redirectUrl}`;
} else {
this.setState({
loading: false,
error: true
})
});
}
checkUserLoggedIn = (config) => {
axios.post(
window.location.origin + "/entgra-ui-request-handler/user",
"platform=entgra"
).then(res => {
config.user = res.data.data;
const pageURL = window.location.pathname;
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
if (lastURLSegment === "login") {
window.location.href = window.location.origin + `/entgra/`;
} else {
this.setState({
loading: false,
config: config
});
}
this.getDeviceTypes(config);
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
const redirectUrl = encodeURI(window.location.href);
const pageURL = window.location.pathname;
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
if (lastURLSegment !== "login") {
window.location.href = window.location.origin + `/entgra/login?redirect=${redirectUrl}`;
} else {
this.setState({
loading: false,
config: config
})
}
} else {
this.setState({
loading: false,
error: true
})
}
});
};
getDeviceTypes = (config) => {
axios.get(
window.location.origin + "/entgra-ui-request-handler/invoke/device-mgt/v1.0/device-types",
).then(res => {
config.deviceTypes = JSON.parse(res.data.data);
this.setState({
config: config,
loading: false
loading: false,
config: config,
});
}).catch((error) => {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load device types.",
});
}
} else {
this.setState({
loading: false,
error: true,
});
}
});
};
getDeviceTypes = config => {
axios
.get(
window.location.origin +
'/entgra-ui-request-handler/invoke/device-mgt/v1.0/device-types',
)
.then(res => {
config.deviceTypes = JSON.parse(res.data.data);
this.setState({
config: config,
loading: false,
});
};
})
.catch(error => {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load device types.',
});
});
};
render() {
const {loading, error} = this.state;
render() {
const { loading, error } = this.state;
const applicationView = (
<Router>
<ConfigContext.Provider value={this.state.config}>
<div>
<Switch>
<Redirect exact from="/entgra" to="/entgra/devices" />
{this.props.routes.map(route => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>
</div>
</ConfigContext.Provider>
</Router>
);
const abc = this.state.deviceTypes;
const applicationView = (
<Router>
<ConfigContext.Provider value={this.state.config}>
<div>
<Switch>
<Redirect exact from="/entgra" to="/entgra/devices"/>
{this.props.routes.map((route) => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>
</div>
</ConfigContext.Provider>
</Router>
);
return (
<div>
{loading && loadingView}
{!loading && !error && applicationView}
{error && errorView}
</div>
);
}
return (
<div>
{loading && loadingView}
{!loading && !error && applicationView}
{error && errorView}
</div>
);
}
}
export default App;

View File

@ -16,217 +16,247 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {Icon, message, Modal, notification, Popconfirm, Select, Table, Tag, Tooltip, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import {
Icon,
message,
notification,
Popconfirm,
Table,
Tooltip,
Typography,
} from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../../context/ConfigContext";
import Moment from "react-moment";
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../../context/ConfigContext';
import Moment from 'react-moment';
const {Paragraph, Text} = Typography;
const { Paragraph, Text } = Typography;
let config = null;
class CertificateTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
};
}
componentDidMount() {
this.fetch();
}
// fetch data from api
fetch = (params = {}) => {
this.setState({ loading: true });
// get current page
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key])
.join('&');
// send request to the invoker
axios
.get(
window.location.origin +
config.serverConfig.invoker.uri +
'/certificate-mgt/v1.0/admin/certificates' +
encodedExtraParams,
)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
};
}
componentDidMount() {
this.fetch();
}
//fetch data from api
fetch = (params = {}) => {
this.setState({loading: true});
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
requireDeviceInfo: true,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
//send request to the invoker
axios.get(
window.location.origin + config.serverConfig.invoker.uri +
'/certificate-mgt/v1.0/admin/certificates',
).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data.certificates,
pagination
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to load devices.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
deleteCertificate = (serialNumber) =>{
axios.delete(
window.location.origin + config.serverConfig.invoker.uri +
'/certificate-mgt/v1.0/admin/certificates/'+ serialNumber,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 200) {
this.fetch();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully deleted the certificate.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to delete the certificate.",
});
}
});
};
columns = [
{
title: 'Serial Number',
dataIndex: 'serialNumber'
},
{
title: 'Username',
dataIndex: 'username'
},
{
title: 'Certificate Version',
dataIndex: 'certificateVersion'
},
{
title: 'Certificate Serial',
dataIndex: 'certificateserial'
},
{
title: 'Not Before',
dataIndex: 'notBefore',
render: notBefore => (
<Moment format="YYYY/MM/DD HH:mm" date={notBefore} />
)
},
{
title: 'Not After',
dataIndex: 'notAfter',
render: notAfter => (
<Moment format="YYYY/MM/DD HH:mm" date={notAfter} />
)
},
{
title: 'Subject',
dataIndex: 'subject',
render: subject => (
<Paragraph style={{marginBottom: 0}} ellipsis={{rows:1, expandable: true}}>{subject}</Paragraph>
)
},
{
title: 'Issuer',
dataIndex: 'issuer',
render: issuer => (
<Paragraph style={{marginBottom: 0}} ellipsis={{rows:1, expandable: true}}>{issuer}</Paragraph>
)
},
{
title: 'Actions',
key: 'actions',
dataIndex: 'serialNumber',
render: (serialNumber) => (
<Tooltip placement="bottom" title={"Remove User"}>
<Popconfirm
placement="top"
title={"Are you sure?"}
onConfirm={() => {this.deleteCertificate(serialNumber)}}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
</Popconfirm>
</Tooltip>
)
data: res.data.data.certificates,
pagination,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load devices.',
});
}
];
render() {
const {data, pagination, loading} = this.state;
this.setState({ loading: false });
});
};
return (
<div>
<div>
<Table
columns={this.columns}
rowKey={record => record.serialNumber}
dataSource={data}
pagination={{
...pagination,
size: "small",
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
/>
</div>
</div>
);
}
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
deleteCertificate = serialNumber => {
axios
.delete(
window.location.origin +
config.serverConfig.invoker.uri +
'/certificate-mgt/v1.0/admin/certificates/' +
serialNumber,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.fetch();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully deleted the certificate.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description:
'Error occurred while trying to delete the certificate.',
});
}
});
};
columns = [
{
title: 'Serial Number',
dataIndex: 'serialNumber',
},
{
title: 'Username',
dataIndex: 'username',
},
{
title: 'Certificate Version',
dataIndex: 'certificateVersion',
},
{
title: 'Certificate Serial',
dataIndex: 'certificateserial',
},
{
title: 'Not Before',
dataIndex: 'notBefore',
render: notBefore => (
<Moment format="YYYY/MM/DD HH:mm" date={notBefore} />
),
},
{
title: 'Not After',
dataIndex: 'notAfter',
render: notAfter => <Moment format="YYYY/MM/DD HH:mm" date={notAfter} />,
},
{
title: 'Subject',
dataIndex: 'subject',
render: subject => (
<Paragraph
style={{ marginBottom: 0 }}
ellipsis={{ rows: 1, expandable: true }}
>
{subject}
</Paragraph>
),
},
{
title: 'Issuer',
dataIndex: 'issuer',
render: issuer => (
<Paragraph
style={{ marginBottom: 0 }}
ellipsis={{ rows: 1, expandable: true }}
>
{issuer}
</Paragraph>
),
},
{
title: 'Actions',
key: 'actions',
dataIndex: 'serialNumber',
render: serialNumber => (
<Tooltip placement="bottom" title={'Remove User'}>
<Popconfirm
placement="top"
title={'Are you sure?'}
onConfirm={() => {
this.deleteCertificate(serialNumber);
}}
okText="Ok"
cancelText="Cancel"
>
<a>
<Text type="danger">
<Icon type="delete" />
</Text>
</a>
</Popconfirm>
</Tooltip>
),
},
];
render() {
const { data, pagination, loading } = this.state;
return (
<div>
<div>
<Table
columns={this.columns}
rowKey={record => record.serialNumber}
dataSource={data}
pagination={{
...pagination,
size: 'small',
// position: "top",
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} devices`,
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
/>
</div>
</div>
);
}
}
export default withConfigContext(CertificateTable);

View File

@ -16,129 +16,115 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {Card, Col, Icon, message, notification, Row, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { Card, Col, Icon, message, notification, Row } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
const {Text} = Typography;
let config = null;
let apiUrl;
class DeviceTypesTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
};
}
componentDidMount() {
this.fetchUsers();
}
// fetch data from api
fetchUsers = (params = {}) => {
const config = this.props.context;
this.setState({ loading: true });
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/device-types';
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: []
};
}
data: JSON.parse(res.data.data),
pagination,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load device types.',
});
}
componentDidMount() {
this.fetchUsers();
}
this.setState({ loading: false });
});
};
//fetch data from api
fetchUsers = (params = {}) => {
const config = this.props.context;
this.setState({loading: true});
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/device-types";
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: JSON.parse(res.data.data),
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load device types.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { Meta } = Card;
const itemCard = data.map((data) =>
<Col span={5} key={data.id}>
<Card
size="default"
style={{ width: 200 }}
bordered={true}
actions={[
<Icon type="setting" key="setting" />,
<Icon type="edit" key="edit" />,]}
>
<Meta
avatar={<Icon type="desktop" key="device-types"/>}
title={data.name}
/>
</Card>
</Col>
);
return (
<div style={{ background: '#ECECEC', padding: '20px' }}>
<Row gutter={16}>
{itemCard}
</Row>
</div>
);
}
render() {
const { data } = this.state;
const { Meta } = Card;
const itemCard = data.map(data => (
<Col span={5} key={data.id}>
<Card
size="default"
style={{ width: 200 }}
bordered={true}
actions={[
<Icon type="setting" key="setting" />,
<Icon type="edit" key="edit" />,
]}
>
<Meta
avatar={<Icon type="desktop" key="device-types" />}
title={data.name}
/>
</Card>
</Col>
));
return (
<div style={{ background: '#ECECEC', padding: '20px' }}>
<Row gutter={16}>{itemCard}</Row>
</div>
);
}
}
export default withConfigContext(DeviceTypesTable);
export default withConfigContext(DeviceTypesTable);

View File

@ -1,66 +1,56 @@
import React from 'react';
import {Button, Form, Row, Col, Card, Steps, Input, message, Modal, notification, Typography} from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
import DeviceType from "./DeviceType";
import EnrollAgent from "./EnrollAgent";
const {Step} = Steps;
import { Form, Row, Col, Card, Steps } from 'antd';
import { withConfigContext } from '../../context/ConfigContext';
import DeviceType from './DeviceType';
import EnrollAgent from './EnrollAgent';
const { Step } = Steps;
class AddDevice extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
this.state = {
isAddDeviceModalVisible: false,
current : 0,
}
constructor(props) {
super(props);
this.config = this.props.context;
this.state = {
isAddDeviceModalVisible: false,
current: 0,
};
}
onClickType = () =>{
this.setState({
current: 1,
})
};
onClickType = () => {
this.setState({
current: 1,
});
};
openAddDeviceModal = () =>{
this.setState({
isAddDeviceModalVisible : true,
})
};
render() {
const { current } = this.state;
return (
<div>
<Row>
<Col span={16} offset={4}>
<Steps style={{ minHeight: 32 }} current={current}>
<Step key="DeviceType" title="Device Type" />
<Step key="EnrollAgent" title="Enroll Agent" />
<Step key="Result" title="Result" />
</Steps>
</Col>
<Col span={16} offset={4}>
<Card style={{ marginTop: 24 }}>
<div style={{ display: current === 0 ? 'unset' : 'none' }}>
<DeviceType onClickType={this.onClickType} />
</div>
<div style={{ display: current === 1 ? 'unset' : 'none' }}>
<EnrollAgent />
</div>
render() {
const {loading, current, isError, supportedOsVersions, errorText, forbiddenErrors} = this.state;
const { getFieldDecorator } = this.props.form;
return (
<div>
<Row>
<Col span={16} offset={4}>
<Steps style={{minHeight: 32}} current={current}>
<Step key="DeviceType" title="Device Type"/>
<Step key="EnrollAgent" title="Enroll Agent"/>
<Step key="Result" title="Result"/>
</Steps>
</Col>
<Col span={16} offset={4}>
<Card style={{marginTop: 24}}>
<div style={{display: (current === 0 ? 'unset' : 'none')}}>
<DeviceType onClickType={this.onClickType}/>
</div>
<div style={{display: (current === 1 ? 'unset' : 'none')}}>
<EnrollAgent />
</div>
<div style={{display: (current === 2 ? 'unset' : 'none')}}>
</div>
</Card>
</Col>
</Row>
</div>
);
}
<div style={{ display: current === 2 ? 'unset' : 'none' }}></div>
</Card>
</Col>
</Row>
</div>
);
}
}
export default withConfigContext(Form.create({name: 'add-device'})(AddDevice));
export default withConfigContext(
Form.create({ name: 'add-device' })(AddDevice),
);

View File

@ -16,109 +16,118 @@
* under the License.
*/
import React from "react";
import {Button, Tooltip, Popconfirm, Divider} from "antd";
import React from 'react';
import { Button, Tooltip, Popconfirm, Divider } from 'antd';
class BulkActionBar extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedMultiple: false,
selectedSingle: false,
canDelete: true,
};
}
constructor(props) {
super(props);
this.state = {
selectedMultiple: false,
selectedSingle: false,
canDelete: true,
}
// This method checks whether NON-REMOVED devices are selected
onDeleteDeviceCall = () => {
let tempDeleteState;
for (let i = 0; i < this.props.selectedRows.length; i++) {
if (this.props.selectedRows[i].enrolmentInfo.status != 'REMOVED') {
tempDeleteState = false;
break;
}
tempDeleteState = true;
}
this.setState({ canDelete: tempDeleteState });
};
//This method checks whether NON-REMOVED devices are selected
onDeleteDeviceCall = () => {
let tempDeleteState;
for(let i=0; i < this.props.selectedRows.length; i++){
if(this.props.selectedRows[i].enrolmentInfo.status != "REMOVED"){
tempDeleteState = false;
break;
onConfirmDelete = () => {
if (this.state.canDelete) {
this.props.deleteDevice();
}
};
onConfirmDisenroll = () => {
this.props.disenrollDevice();
};
onDeviceGroupCall = () => {
this.props.getGroups();
};
render() {
const isSelected = this.props.selectedRows.length > 0;
const isSelectedSingle = this.props.selectedRows.length == 1;
return (
<div style={{ display: isSelected ? 'inline' : 'none', padding: '11px' }}>
<Tooltip
placement="bottom"
title={'Delete Device'}
autoAdjustOverflow={true}
>
<Popconfirm
placement="topLeft"
title={
this.state.canDelete
? 'Are you sure you want to delete?'
: 'You can only delete disenrolled devices'
}
tempDeleteState = true;
}
this.setState({canDelete:tempDeleteState})
};
onConfirmDelete = () => {
if (this.state.canDelete) {
this.props.deleteDevice();
}
};
onConfirmDisenroll = () => {
this.props.disenrollDevice();
};
onDeviceGroupCall = () => {
this.props.getGroups();
}
render() {
const isSelected = this.props.selectedRows.length > 0;
const isSelectedSingle = this.props.selectedRows.length == 1;
return (
<div style={{display: isSelected ? "inline" : "none", padding: '11px'}}>
<Tooltip
placement="bottom"
title={"Delete Device"}
autoAdjustOverflow={true}>
<Popconfirm
placement="topLeft"
title={
this.state.canDelete ?
"Are you sure you want to delete?" : "You can only delete disenrolled devices"}
onConfirm={this.onConfirmDelete}
okText="Ok"
cancelText="Cancel">
<Button
type="link"
shape="circle"
icon="delete"
size={'default'}
onClick={this.onDeleteDeviceCall}
disabled={isSelected ? false : true}
style={{margin: "2px"}}/>
</Popconfirm>
</Tooltip>
<Divider type="vertical"/>
<Tooltip placement="bottom" title={"Disenroll Device"}>
<Popconfirm
placement="topLeft"
title={"Are you sure?"}
onConfirm={this.onConfirmDisenroll}
okText="Ok"
disabled={isSelectedSingle ? false : true}
cancelText="Cancel">
<Button
type="link"
shape="circle"
icon="close"
size={'default'}
style={{display:isSelectedSingle ? "inline" : "none", margin: "2px"}}/>
</Popconfirm>
</Tooltip>
<Divider type="vertical" style={{display:isSelectedSingle ? "inline-block" : "none"}}/>
<Tooltip placement="bottom" title={"Add to group"}>
<Button
type="link"
shape="circle"
icon="deployment-unit"
size={'default'}
onClick={this.onDeviceGroupCall}
style={{margin: "2px"}}/>
</Tooltip>
</div>
)
}
onConfirm={this.onConfirmDelete}
okText="Ok"
cancelText="Cancel"
>
<Button
type="link"
shape="circle"
icon="delete"
size={'default'}
onClick={this.onDeleteDeviceCall}
disabled={!isSelected}
style={{ margin: '2px' }}
/>
</Popconfirm>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={'Disenroll Device'}>
<Popconfirm
placement="topLeft"
title={'Are you sure?'}
onConfirm={this.onConfirmDisenroll}
okText="Ok"
disabled={!isSelectedSingle}
cancelText="Cancel"
>
<Button
type="link"
shape="circle"
icon="close"
size={'default'}
style={{
display: isSelectedSingle ? 'inline' : 'none',
margin: '2px',
}}
/>
</Popconfirm>
</Tooltip>
<Divider
type="vertical"
style={{ display: isSelectedSingle ? 'inline-block' : 'none' }}
/>
<Tooltip placement="bottom" title={'Add to group'}>
<Button
type="link"
shape="circle"
icon="deployment-unit"
size={'default'}
onClick={this.onDeviceGroupCall}
style={{ margin: '2px' }}
/>
</Tooltip>
</div>
);
}
}
export default BulkActionBar;
export default BulkActionBar;

View File

@ -16,133 +16,126 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {Card, Col, Icon, message, notification, Row, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { Card, Col, Icon, message, notification, Row } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
const {Text} = Typography;
let config = null;
let apiUrl;
class DeviceType extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
};
}
componentDidMount() {
this.fetchUsers();
}
onClickCard = data => {
console.log(data);
this.props.onClickType();
};
// fetch data from api
fetchUsers = (params = {}) => {
const config = this.props.context;
this.setState({ loading: true });
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/device-types';
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: []
};
}
data: JSON.parse(res.data.data),
pagination,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load device types.',
});
}
componentDidMount() {
this.fetchUsers();
}
this.setState({ loading: false });
});
};
onClickCard = (data) =>{
console.log(data);
this.props.onClickType();
};
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
//fetch data from api
fetchUsers = (params = {}) => {
const config = this.props.context;
this.setState({loading: true});
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/device-types";
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: JSON.parse(res.data.data),
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load device types.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { Meta } = Card;
const itemCard = data.map((data) =>
<Col span={5} key={data.id}>
<Card
size="default"
style={{ width: 150 }}
bordered={true}
onClick={this.onClickCard}
cover={<Icon type="android" key="device-types" style={{color:'#ffffff',
backgroundColor:'#4b92db', fontSize: '100px', padding:'20px'}}/>}
>
<Meta
title={data.name}
/>
</Card>
</Col>
);
return (
<div>
<Row gutter={16}>
{itemCard}
</Row>
</div>
);
}
render() {
const { data } = this.state;
const { Meta } = Card;
const itemCard = data.map(data => (
<Col span={5} key={data.id}>
<Card
size="default"
style={{ width: 150 }}
bordered={true}
onClick={this.onClickCard}
cover={
<Icon
type="android"
key="device-types"
style={{
color: '#ffffff',
backgroundColor: '#4b92db',
fontSize: '100px',
padding: '20px',
}}
/>
}
>
<Meta title={data.name} />
</Card>
</Col>
));
return (
<div>
<Row gutter={16}>{itemCard}</Row>
</div>
);
}
}
export default withConfigContext(DeviceType);
export default withConfigContext(DeviceType);

View File

@ -16,471 +16,523 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {Icon, message, Modal, notification, Select, Table, Tag, Tooltip, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import {
Icon,
message,
Modal,
notification,
Select,
Table,
Tag,
Tooltip,
} from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
import BulkActionBar from "./BulkActionBar";
const {Text} = Typography;
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
import BulkActionBar from './BulkActionBar';
let config = null;
const columns = [
{
title: 'Device',
dataIndex: 'name',
width: 100,
},
{
title: 'Type',
dataIndex: 'type',
key: 'type',
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
let color = defaultPlatformIcons.default.color;
let theme = defaultPlatformIcons.default.theme;
{
title: 'Device',
dataIndex: 'name',
width: 100,
},
{
title: 'Type',
dataIndex: 'type',
key: 'type',
// eslint-disable-next-line react/display-name
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
let color = defaultPlatformIcons.default.color;
let theme = defaultPlatformIcons.default.theme;
if (defaultPlatformIcons.hasOwnProperty(type)) {
icon = defaultPlatformIcons[type].icon;
color = defaultPlatformIcons[type].color;
theme = defaultPlatformIcons[type].theme;
}
if (defaultPlatformIcons.hasOwnProperty(type)) {
icon = defaultPlatformIcons[type].icon;
color = defaultPlatformIcons[type].color;
theme = defaultPlatformIcons[type].theme;
}
return (
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
<Icon type={icon} theme={theme}/>
</span>
);
}
// todo add filtering options
return (
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
<Icon type={icon} theme={theme} />
</span>
);
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner
// todo add filtering options
// todo add filtering options
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner,
// todo add filtering options
},
{
title: 'Ownership',
dataIndex: 'enrolmentInfo',
key: 'ownership',
render: enrolmentInfo => enrolmentInfo.ownership,
// todo add filtering options
},
{
title: 'Status',
dataIndex: 'enrolmentInfo',
key: 'status',
// eslint-disable-next-line react/display-name
render: enrolmentInfo => {
const status = enrolmentInfo.status.toLowerCase();
let color = '#f9ca24';
switch (status) {
case 'active':
color = '#badc58';
break;
case 'created':
color = '#6ab04c';
break;
case 'removed':
color = '#ff7979';
break;
case 'inactive':
color = '#f9ca24';
break;
case 'blocked':
color = '#636e72';
break;
}
return <Tag color={color}>{status}</Tag>;
},
{
title: 'Ownership',
dataIndex: 'enrolmentInfo',
key: 'ownership',
render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
// eslint-disable-next-line react/display-name
render: data => {
const { dateOfLastUpdate } = data;
const timeAgoString = getTimeAgo(dateOfLastUpdate);
return (
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
{timeAgoString}
</Tooltip>
);
},
{
title: 'Status',
dataIndex: 'enrolmentInfo',
key: 'status',
render: (enrolmentInfo) => {
const status = enrolmentInfo.status.toLowerCase();
let color = "#f9ca24";
switch (status) {
case "active":
color = "#badc58";
break;
case "created":
color = "#6ab04c";
break;
case "removed":
color = "#ff7979";
break;
case "inactive":
color = "#f9ca24";
break;
case "blocked":
color = "#636e72";
break;
}
return <Tag color={color}>{status}</Tag>;
}
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
render: (data) => {
const {dateOfLastUpdate} = data;
const timeAgoString = getTimeAgo(dateOfLastUpdate);
return <Tooltip title={new Date(dateOfLastUpdate).toString()}>{timeAgoString}</Tooltip>;
}
// todo add filtering options
}
// todo add filtering options
},
];
const getTimeAgo = (time) => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
const getTimeAgo = time => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
};
class DeviceTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
deviceGroups: [],
groupModalVisible: false,
selectedGroupId: [],
selectedRowKeys: [],
};
}
componentDidMount() {
this.fetch();
}
// fetch data from api
fetch = (params = {}) => {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
requireDeviceInfo: true,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key])
.join('&');
// send request to the invoker
axios
.get(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/devices?' +
encodedExtraParams,
)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: [],
deviceGroups: [],
groupModalVisible: false,
selectedGroupId: [],
selectedRowKeys:[]
};
}
componentDidMount() {
this.fetch();
}
//fetch data from api
fetch = (params = {}) => {
const config = this.props.context;
this.setState({loading: true});
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
requireDeviceInfo: true,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
//send request to the invoker
axios.get(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/devices?" + encodedExtraParams,
).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data.devices,
pagination
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to load devices.",
});
}
this.setState({loading: false});
});
};
deleteDevice = () => {
const config = this.props.context;
this.setState({loading: true});
const deviceData = this.state.selectedRows.map(obj => obj.deviceIdentifier);
//send request to the invoker
axios.put(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/admin/devices/permanent-delete",
deviceData,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 200) {
this.fetch();
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to delete devices.",
});
}
this.setState({loading: false});
});
};
disenrollDevice = () => {
const config = this.props.context;
this.setState({loading: true});
const deviceData = this.state.selectedRows[0];
//send request to the invoker
axios.delete(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/devices/type/" + deviceData.type + "/id/" + deviceData.deviceIdentifier,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 200) {
this.fetch();
this.setState({
selectedRowKeys:[]
})
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully dis-enrolled the device.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to dis-enroll devices.",
});
}
this.setState({loading: false});
});
};
addDevicesToGroup = (groupId) => {
const config = this.props.context;
this.setState({loading: true});
let apiUrl;
let deviceData;
if (this.state.selectedRows.length === 1) {
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/device/assign";
deviceData = {
deviceIdentifier: {
id: this.state.selectedRows[0].deviceIdentifier,
type: this.state.selectedRows[0].type
},
deviceGroupIds: groupId
}
} else if (!groupId[0]){
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/id/" + groupId + "/devices/add";
deviceData = this.state.selectedRows.map(obj => ({id: obj.deviceIdentifier, type: obj.type}));
} else{
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/id/" + groupId[0] + "/devices/add";
deviceData = this.state.selectedRows.map(obj => ({id: obj.deviceIdentifier, type: obj.type}));
data: res.data.data.devices,
pagination,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load devices.',
});
}
//send request to the invoker
axios.post(
apiUrl,
deviceData,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 200) {
this.setState({
loading: false
});
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully added to the device group.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while adding to the device group.",
});
}
this.setState({ loading: false });
});
};
this.setState({loading: false});
});
};
deleteDevice = () => {
const config = this.props.context;
this.setState({ loading: true });
getGroups = () => {
this.setState({
groupModalVisible: true
});
//send request to the invoker
axios.get(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups"
).then(res => {
this.setState({deviceGroups: res.data.data.deviceGroups})
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while retrieving device groups.",
});
}
const deviceData = this.state.selectedRows.map(obj => obj.deviceIdentifier);
this.setState({loading: false});
});
};
handleOk = e => {
if(this.state.selectedGroupId){
this.addDevicesToGroup(this.state.selectedGroupId);
this.setState({
groupModalVisible: false
});
}else{
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Please select a group.",
});
// send request to the invoker
axios
.put(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/admin/devices/permanent-delete',
deviceData,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.fetch();
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to delete devices.',
});
}
};
this.setState({ loading: false });
});
};
handleCancel = e => {
this.setState({
groupModalVisible: false,
});
};
disenrollDevice = () => {
const config = this.props.context;
this.setState({ loading: true });
onGroupSelectChange = (value) => {
this.setState({selectedGroupId: value});
};
const deviceData = this.state.selectedRows[0];
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
onSelectChange = (selectedRowKeys, selectedRows) => {
this.setState({
selectedRowKeys,
selectedRows: selectedRows
});
};
render() {
const {data, pagination, loading, selectedRows, selectedRowKeys} = this.state;
const isSelectedSingle = this.state.selectedRows.length == 1;
let selectedText;
if(isSelectedSingle){
selectedText = "You have selected 1 device"
}else{
selectedText = "You have selected " + this.state.selectedRows.length + " devices"
// send request to the invoker
axios
.delete(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/devices/type/' +
deviceData.type +
'/id/' +
deviceData.deviceIdentifier,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.fetch();
this.setState({
selectedRowKeys: [],
});
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully dis-enrolled the device.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to dis-enroll devices.',
});
}
const rowSelection = {
selectedRowKeys,
selectedRows,
onChange: this.onSelectChange,
};
this.setState({ loading: false });
});
};
let item = this.state.deviceGroups.map((data) =>
<Select.Option
value={data.id}
key={data.id}>
{data.name}
</Select.Option>);
return (
<div>
<BulkActionBar
deleteDevice={this.deleteDevice}
getGroups={this.getGroups}
disenrollDevice={this.disenrollDevice}
selectedRows={this.state.selectedRows}/>
<div>
<Table
columns={columns}
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
dataSource={data}
pagination={{
...pagination,
size: "small",
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={rowSelection}
/>
</div>
addDevicesToGroup = groupId => {
const config = this.props.context;
this.setState({ loading: true });
<Modal
title="Grouping Devices"
width="350px"
visible={this.state.groupModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<p>{selectedText}</p>
<Select
mode={isSelectedSingle ? "multiple" : "default"}
showSearch
style={{display:"block"}}
placeholder="Select Group"
optionFilterProp="children"
onChange={this.onGroupSelectChange}
>
{item}
</Select>
</Modal>
</div>
);
let apiUrl;
let deviceData;
if (this.state.selectedRows.length === 1) {
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/groups/device/assign';
deviceData = {
deviceIdentifier: {
id: this.state.selectedRows[0].deviceIdentifier,
type: this.state.selectedRows[0].type,
},
deviceGroupIds: groupId,
};
} else if (!groupId[0]) {
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/groups/id/' +
groupId +
'/devices/add';
deviceData = this.state.selectedRows.map(obj => ({
id: obj.deviceIdentifier,
type: obj.type,
}));
} else {
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/groups/id/' +
groupId[0] +
'/devices/add';
deviceData = this.state.selectedRows.map(obj => ({
id: obj.deviceIdentifier,
type: obj.type,
}));
}
// send request to the invoker
axios
.post(apiUrl, deviceData, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => {
if (res.status === 200) {
this.setState({
loading: false,
});
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully added to the device group.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while adding to the device group.',
});
}
this.setState({ loading: false });
});
};
getGroups = () => {
this.setState({
groupModalVisible: true,
});
// send request to the invoker
axios
.get(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/groups',
)
.then(res => {
this.setState({ deviceGroups: res.data.data.deviceGroups });
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while retrieving device groups.',
});
}
this.setState({ loading: false });
});
};
handleOk = e => {
if (this.state.selectedGroupId) {
this.addDevicesToGroup(this.state.selectedGroupId);
this.setState({
groupModalVisible: false,
});
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Please select a group.',
});
}
};
handleCancel = e => {
this.setState({
groupModalVisible: false,
});
};
onGroupSelectChange = value => {
this.setState({ selectedGroupId: value });
};
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
onSelectChange = (selectedRowKeys, selectedRows) => {
this.setState({
selectedRowKeys,
selectedRows: selectedRows,
});
};
render() {
const {
data,
pagination,
loading,
selectedRows,
selectedRowKeys,
} = this.state;
const isSelectedSingle = this.state.selectedRows.length == 1;
let selectedText;
if (isSelectedSingle) {
selectedText = 'You have selected 1 device';
} else {
selectedText =
'You have selected ' + this.state.selectedRows.length + ' devices';
}
const rowSelection = {
selectedRowKeys,
selectedRows,
onChange: this.onSelectChange,
};
let item = this.state.deviceGroups.map(data => (
<Select.Option value={data.id} key={data.id}>
{data.name}
</Select.Option>
));
return (
<div>
<BulkActionBar
deleteDevice={this.deleteDevice}
getGroups={this.getGroups}
disenrollDevice={this.disenrollDevice}
selectedRows={this.state.selectedRows}
/>
<div>
<Table
columns={columns}
rowKey={record =>
record.deviceIdentifier +
record.enrolmentInfo.owner +
record.enrolmentInfo.ownership
}
dataSource={data}
pagination={{
...pagination,
size: 'small',
// position: "top",
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} devices`,
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={rowSelection}
/>
</div>
<Modal
title="Grouping Devices"
width="350px"
visible={this.state.groupModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<p>{selectedText}</p>
<Select
mode={isSelectedSingle ? 'multiple' : 'default'}
showSearch
style={{ display: 'block' }}
placeholder="Select Group"
optionFilterProp="children"
onChange={this.onGroupSelectChange}
>
{item}
</Select>
</Modal>
</div>
);
}
}
export default withConfigContext(DeviceTable);
export default withConfigContext(DeviceTable);

View File

@ -1,87 +1,97 @@
import React from 'react';
import {Collapse, Button, Divider, message, notification , Select} from 'antd';
import TimeAgo from "javascript-time-ago/modules/JavascriptTimeAgo";
import en from "javascript-time-ago/locale/en";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
const { Option } = Select;
import { Button, Divider, message, notification } from 'antd';
import TimeAgo from 'javascript-time-ago/modules/JavascriptTimeAgo';
import en from 'javascript-time-ago/locale/en';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
class EnrollAgent extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
visibleSelector: {display : 'none'}
};
}
componentDidMount() {
this.getConfigData();
constructor(props) {
super(props);
this.config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
visibleSelector: { display: 'none' },
};
}
componentDidMount() {
this.getConfigData();
}
onGetEnrollmentQR = () =>{
this.setState({
visibleSelector: {display : 'block'}
})
};
onGetEnrollmentQR = () => {
this.setState({
visibleSelector: { display: 'block' },
});
};
getConfigData = () =>{
axios.get(
window.location.origin + this.config.serverConfig.invoker.uri +
"/device-mgt/android/v1.0/configuration"
).then(res => {
let data = res.data.data;
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while retrieving device groups.",
});
}
getConfigData = () => {
axios
.get(
window.location.origin +
this.config.serverConfig.invoker.uri +
'/device-mgt/android/v1.0/configuration',
)
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while retrieving device groups.',
});
}
});
};
});
};
render() {
return (
<div>
<Divider orientation="left">Step 01 - Get your Android Agent.</Divider>
<div>
<p>
The Android agent can be downloaded by using following QR. The
generated QR code can be scanned, and the agent APK downloaded from
the link, and transferred to the device and then installed.
</p>
</div>
<div style={{ margin: '30px' }}>
<Button type="primary" size={'default'}>
Get Android Agent
</Button>
</div>
<Divider orientation="left">
Step 02 - Enroll the Android Agent.
</Divider>
render() {
return (
<div>
<Divider orientation="left">Step 01 - Get your Android Agent.</Divider>
<div>
<p>The Android agent can be downloaded by using following QR.
The generated QR code can be scanned, and the agent APK downloaded from the link,
and transferred to the device and then installed.</p>
</div>
<div style={{ margin:'30px'}}>
<Button type="primary" size={"default"}>
Get Android Agent
</Button>
</div>
<Divider orientation="left">Step 02 - Enroll the Android Agent.</Divider>
<div>
<p> Your device can be enrolled with Entgra IoTS automatically via QR code.
To enroll first download agent as mentioned in Step 1 then proceed with the ENROLL WITH
QR option from the device setup activity. Thereafter select the ownership configuration
and scan the generated QR to complete the process.</p>
</div>
<div style={{ margin:'30px'}}>
<Button type="primary" size={"default"} onClick={this.onGetEnrollmentQR}>
Enroll Using QR
</Button>
</div>
</div>
);
}
<div>
<p>
{' '}
Your device can be enrolled with Entgra IoTS automatically via QR
code. To enroll first download agent as mentioned in Step 1 then
proceed with the ENROLL WITH QR option from the device setup
activity. Thereafter select the ownership configuration and scan the
generated QR to complete the process.
</p>
</div>
<div style={{ margin: '30px' }}>
<Button
type="primary"
size={'default'}
onClick={this.onGetEnrollmentQR}
>
Enroll Using QR
</Button>
</div>
</div>
);
}
}
export default withConfigContext(EnrollAgent);
export default withConfigContext(EnrollAgent);

View File

@ -16,232 +16,252 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {Icon, message, notification, Table, Tag, Tooltip, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { Icon, message, notification, Table, Tag, Tooltip } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
const {Text} = Typography;
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
let config = null;
let apiUrl;
const columns = [
{
title: 'Device',
dataIndex: 'name',
width: 100,
},
{
title: 'Type',
dataIndex: 'type',
key: 'type',
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
let color = defaultPlatformIcons.default.color;
let theme = defaultPlatformIcons.default.theme;
{
title: 'Device',
dataIndex: 'name',
width: 100,
},
{
title: 'Type',
dataIndex: 'type',
key: 'type',
// eslint-disable-next-line react/display-name
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
let color = defaultPlatformIcons.default.color;
let theme = defaultPlatformIcons.default.theme;
if (defaultPlatformIcons.hasOwnProperty(type)) {
icon = defaultPlatformIcons[type].icon;
color = defaultPlatformIcons[type].color;
theme = defaultPlatformIcons[type].theme;
}
if (defaultPlatformIcons.hasOwnProperty(type)) {
icon = defaultPlatformIcons[type].icon;
color = defaultPlatformIcons[type].color;
theme = defaultPlatformIcons[type].theme;
}
return (
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
<Icon type={icon} theme={theme}/>
</span>
);
}
// todo add filtering options
return (
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
<Icon type={icon} theme={theme} />
</span>
);
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner
// todo add filtering options
// todo add filtering options
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner,
// todo add filtering options
},
{
title: 'Ownership',
dataIndex: 'enrolmentInfo',
key: 'ownership',
render: enrolmentInfo => enrolmentInfo.ownership,
// todo add filtering options
},
{
title: 'Status',
dataIndex: 'enrolmentInfo',
key: 'status',
// eslint-disable-next-line react/display-name
render: enrolmentInfo => {
const status = enrolmentInfo.status.toLowerCase();
let color = '#f9ca24';
switch (status) {
case 'active':
color = '#badc58';
break;
case 'created':
color = '#6ab04c';
break;
case 'removed':
color = '#ff7979';
break;
case 'inactive':
color = '#f9ca24';
break;
case 'blocked':
color = '#636e72';
break;
}
return <Tag color={color}>{status}</Tag>;
},
{
title: 'Ownership',
dataIndex: 'enrolmentInfo',
key: 'ownership',
render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
// eslint-disable-next-line react/display-name
render: data => {
const { dateOfLastUpdate } = data;
const timeAgoString = getTimeAgo(dateOfLastUpdate);
return (
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
{timeAgoString}
</Tooltip>
);
},
{
title: 'Status',
dataIndex: 'enrolmentInfo',
key: 'status',
render: (enrolmentInfo) => {
const status = enrolmentInfo.status.toLowerCase();
let color = "#f9ca24";
switch (status) {
case "active":
color = "#badc58";
break;
case "created":
color = "#6ab04c";
break;
case "removed":
color = "#ff7979";
break;
case "inactive":
color = "#f9ca24";
break;
case "blocked":
color = "#636e72";
break;
}
return <Tag color={color}>{status}</Tag>;
}
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
render: (data) => {
const {dateOfLastUpdate} = data;
const timeAgoString = getTimeAgo(dateOfLastUpdate);
return <Tooltip title={new Date(dateOfLastUpdate).toString()}>{timeAgoString}</Tooltip>;
}
// todo add filtering options
}
// todo add filtering options
},
];
const getTimeAgo = (time) => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
const getTimeAgo = time => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
};
class ReportDeviceTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
paramsObj: {},
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows,
});
},
};
componentDidMount() {
this.fetch();
}
// Rerender component when parameters change
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevProps.paramsObject !== this.props.paramsObject) {
this.fetch();
}
}
// fetch data from api
fetch = (params = {}) => {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
this.props.paramsObject.offset = 10 * (currentPage - 1); // calculate the offset
this.props.paramsObject.limit = 10;
const encodedExtraParams = Object.keys(this.props.paramsObject)
.map(key => key + '=' + this.props.paramsObject[key])
.join('&');
if (
this.props.paramsObject.from == null &&
this.props.paramsObject.to == null
) {
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/devices?' +
encodedExtraParams;
} else {
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/reports/devices?' +
encodedExtraParams;
}
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: [],
paramsObj:{}
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
data: res.data.data.devices,
pagination,
});
}
};
componentDidMount() {
this.fetch();
}
//Rerender component when parameters change
componentDidUpdate(prevProps, prevState, snapshot) {
if(prevProps.paramsObject !== this.props.paramsObject){
this.fetch();
}
}
//fetch data from api
fetch = (params = {}) => {
const config = this.props.context;
this.setState({loading: true});
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
this.props.paramsObject.offset = 10 * (currentPage -1); //calculate the offset
this.props.paramsObject.limit = 10;
const encodedExtraParams = Object.keys(this.props.paramsObject)
.map(key => key + '=' + this.props.paramsObject[key]).join('&');
if(this.props.paramsObject.from==null && this.props.paramsObject.to==null){
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/devices?" + encodedExtraParams;
}else{
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices?" + encodedExtraParams;
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load devices.',
});
}
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data.devices,
pagination,
});
}
this.setState({ loading: false });
});
};
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load devices.",
});
}
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
dataSource={data}
pagination={{
...pagination,
size: "small",
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
);
}
render() {
const { data, pagination, loading } = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record =>
record.deviceIdentifier +
record.enrolmentInfo.owner +
record.enrolmentInfo.ownership
}
dataSource={data}
pagination={{
...pagination,
size: 'small',
// position: "top",
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} devices`,
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
);
}
}
export default withConfigContext(ReportDeviceTable);
export default withConfigContext(ReportDeviceTable);

View File

@ -16,66 +16,64 @@
* under the License.
*/
import React, {Component, Fragment} from "react";
import React, { Component, Fragment } from 'react';
import {
Map,
TileLayer,
Marker,
Polyline, Popup, Tooltip
} from "react-leaflet";
import {withConfigContext} from "../../../context/ConfigContext";
Map,
TileLayer,
Marker,
Polyline,
Popup,
Tooltip,
} from 'react-leaflet';
import { withConfigContext } from '../../../context/ConfigContext';
class GeoCustomMap extends Component {
constructor(props) {
super(props);
}
constructor(props) {
super(props);
}
/**
* Polyline draw for historical locations
* @param locationData - location data object
* @returns content
*/
polylineMarker = locationData => {
const polyMarkers = locationData.map(locationPoint => {
return [locationPoint.latitude, locationPoint.longitude];
});
/**
* Polyline draw for historical locations
* @param locationData - location data object
* @returns content
*/
polylineMarker = (locationData) => {
return (
<div style={{ display: 'none' }}>
{
<Polyline color="green" positions={polyMarkers}>
<Popup>on the way</Popup>
</Polyline>
}
</div>
);
};
const polyMarkers = locationData
.map(locationPoint => {
return [locationPoint.latitude, locationPoint.longitude]
});
return (
<div style={{display: "none"}}>{
<Polyline color="green" positions={polyMarkers}>
<Popup>on the way</Popup>
</Polyline>
}</div>
);
};
render() {
const locationData = this.props.locationData;
const config = this.props.context;
const attribution = config.geoMap.attribution;
const url = config.geoMap.url;
const startingPoint = [locationData[0].latitude, locationData[0].longitude];
const zoom = config.geoMap.defaultZoomLevel;
return (
<div style={{backgroundColor: "#ffffff", borderRadius: 5, padding: 5}}>
<Map center={startingPoint} zoom={zoom}>
<TileLayer
url={url}
attribution={attribution}
/>
<Fragment>
{this.polylineMarker(locationData)}
<Marker position={startingPoint}>
<Tooltip>Starting Location</Tooltip>
</Marker>
</Fragment>
</Map>
</div>
);
}
render() {
const locationData = this.props.locationData;
const config = this.props.context;
const attribution = config.geoMap.attribution;
const url = config.geoMap.url;
const startingPoint = [locationData[0].latitude, locationData[0].longitude];
const zoom = config.geoMap.defaultZoomLevel;
return (
<div style={{ backgroundColor: '#ffffff', borderRadius: 5, padding: 5 }}>
<Map center={startingPoint} zoom={zoom}>
<TileLayer url={url} attribution={attribution} />
<Fragment>
{this.polylineMarker(locationData)}
<Marker position={startingPoint}>
<Tooltip>Starting Location</Tooltip>
</Marker>
</Fragment>
</Map>
</div>
);
}
}
export default withConfigContext(GeoCustomMap);

View File

@ -16,266 +16,300 @@
* under the License.
*/
import React from "react";
import moment from "moment";
import {Button, Select, message, notification, Tag, Tooltip, Empty, DatePicker} from "antd";
import axios from "axios";
import {withConfigContext} from "../../../context/ConfigContext";
import GeoCustomMap from "../geo-custom-map/GeoCustomMap";
import "./GeoDashboard.css";
import React from 'react';
import moment from 'moment';
import {
Button,
Select,
message,
notification,
Tag,
Tooltip,
Empty,
DatePicker,
} from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../../context/ConfigContext';
import GeoCustomMap from '../geo-custom-map/GeoCustomMap';
import './GeoDashboard.css';
class GeoDashboard extends React.Component {
constructor(props) {
super(props);
let start = moment(
new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), 0, 0, 0, 0)
);
let end = moment(start)
.add(1, "days")
.subtract(1, "seconds");
this.state = {
deviceData: [],
selectedDevice: '',
locationData: [],
loading: false,
start: start,
end: end,
buttonTooltip: "Fetch Locations",
};
}
componentDidMount() {
this.fetchDevices();
// this.fetchCurrentLocation();
}
/**
* Call back on apply button in the date time picker
* @param startDate - start date
* @param endDate - end date
*/
applyCallback = (dates, dateStrings) => {
console.log("Apply Callback");
this.setState({
start: dateStrings[0],
end: dateStrings[1]
});
constructor(props) {
super(props);
let start = moment(
new Date(
new Date().getFullYear(),
new Date().getMonth(),
new Date().getDate(),
0,
0,
0,
0,
),
);
let end = moment(start)
.add(1, 'days')
.subtract(1, 'seconds');
this.state = {
deviceData: [],
selectedDevice: '',
locationData: [],
loading: false,
start: start,
end: end,
buttonTooltip: 'Fetch Locations',
};
}
/**
* Api call handle on fetch location date button
*/
handleApiCall = () => {
componentDidMount() {
this.fetchDevices();
// this.fetchCurrentLocation();
}
if (this.state.selectedDevice && this.state.start && this.state.end) {
const toInMills = moment(this.state.end);
const fromInMills = moment(this.state.start);
const deviceType = this.state.selectedDevice.type;
const deviceId = this.state.selectedDevice.deviceIdentifier;
const config = this.props.context;
this.setState({loading: true});
/**
* Call back on apply button in the date time picker
* @param startDate - start date
* @param endDate - end date
*/
applyCallback = (dates, dateStrings) => {
console.log('Apply Callback');
this.setState({
start: dateStrings[0],
end: dateStrings[1],
});
};
axios.get(window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt
+ "/devices/" + deviceType + "/" + deviceId + "/location-history?" + "from=" + fromInMills + "&to=" +
toInMills,).then(res => {
if (res.status === 200) {
const locationData = JSON.parse(res.data.data);
this.setState({
loading: false,
locationData,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to fetch locations......",
});
}
/**
* Api call handle on fetch location date button
*/
handleApiCall = () => {
if (this.state.selectedDevice && this.state.start && this.state.end) {
const toInMills = moment(this.state.end);
const fromInMills = moment(this.state.start);
const deviceType = this.state.selectedDevice.type;
const deviceId = this.state.selectedDevice.deviceIdentifier;
const config = this.props.context;
this.setState({ loading: true });
this.setState({loading: false});
console.log(error);
axios
.get(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/devices/' +
deviceType +
'/' +
deviceId +
'/location-history?' +
'from=' +
fromInMills +
'&to=' +
toInMills,
)
.then(res => {
if (res.status === 200) {
const locationData = JSON.parse(res.data.data);
this.setState({
loading: false,
locationData,
});
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Please provide a date range and a device.",
});
}
};
}
})
.catch(error => {
if (
error.hasOwnProperty('response') &&
error.response.status === 401
) {
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description:
'Error occurred while trying to fetch locations......',
});
}
/**
* Device dropdown list handler
* @param e - selected device data
*/
handleDeviceList = (e) => {
let selectedDevice = this.state.deviceData[e];
this.setState({selectedDevice})
};
/**
* render fetch location button
*/
fetchLocationButton = () => {
let flag;
let toolTip = "";
if (this.state.selectedDevice === "") {
flag = true;
toolTip = "Please select a Device";
}
return (
<Tooltip placement="rightBottom" title={toolTip}>
<Button disabled={flag}
onClick={this.handleApiCall}>
Fetch Locations
</Button>
</Tooltip>);
};
/**
* fetches device data to populate the dropdown list
*/
fetchDevices = () => {
const config = this.props.context;
this.setState({loading: true});
axios.get(
window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt +
"/devices?excludeStatus=REMOVED",).then(res => {
if (res.status === 200) {
this.setState({
loading: false,
deviceData: res.data.data.devices,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to load devices.",
});
}
this.setState({loading: false});
this.setState({ loading: false });
console.log(error);
});
};
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Please provide a date range and a device.',
});
}
};
/**
* Geo Dashboard controller
*/
controllerBar = () => {
/**
* Device dropdown list handler
* @param e - selected device data
*/
handleDeviceList = e => {
let selectedDevice = this.state.deviceData[e];
this.setState({ selectedDevice });
};
const {RangePicker} = DatePicker;
let now = new Date();
let start = moment(
new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0)
);
let end = moment(start)
.add(1, "days")
.subtract(1, "seconds");
let ranges = {
"Today Only": [moment(start), moment(end)],
"Yesterday Only": [
moment(start).subtract(1, "days"),
moment(end).subtract(1, "days")
],
"3 Days": [moment(start).subtract(3, "days"), moment(end)],
"5 Days": [moment(start).subtract(5, "days"), moment(end)],
"1 Week": [moment(start).subtract(7, "days"), moment(end)],
"2 Weeks": [moment(start).subtract(14, "days"), moment(end)],
"1 Month": [moment(start).subtract(1, "months"), moment(end)],
};
/**
* render fetch location button
*/
fetchLocationButton = () => {
let flag;
let toolTip = '';
if (this.state.selectedDevice === '') {
flag = true;
toolTip = 'Please select a Device';
}
return (
<Tooltip placement="rightBottom" title={toolTip}>
<Button disabled={flag} onClick={this.handleApiCall}>
Fetch Locations
</Button>
</Tooltip>
);
};
let {deviceData} = this.state;
/**
* fetches device data to populate the dropdown list
*/
fetchDevices = () => {
const config = this.props.context;
this.setState({ loading: true });
return (
<div className="controllerDiv">
<RangePicker
ranges={ranges}
style={{marginRight: 20}}
showTime
format="YYYY-MM-DD HH:mm:ss"
defaultValue={[this.state.start, this.state.end]}
onChange={this.applyCallback}
/>
<Select
showSearch
style={{width: 220, marginRight: 20}}
placeholder="Select a Device"
optionFilterProp="children"
onChange={this.handleDeviceList}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{deviceData.map((device, index) =>
<Select.Option key={index} value={index}>
{device.name + " "}{this.statusTag(device)}
</Select.Option>)}
</Select>
{this.fetchLocationButton()}
</div>
);
};
/**
* Creates color based tags on device status
* @param device - device object
*/
statusTag = (device) => {
const status = device.enrolmentInfo.status.toLowerCase();
let color = "#f9ca24";
switch (status) {
case "active":
color = "#badc58";
break;
case "created":
color = "#6ab04c";
break;
case "inactive":
color = "#f9ca24";
break;
case "blocked":
color = "#636e72";
break;
axios
.get(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/devices?excludeStatus=REMOVED',
)
.then(res => {
if (res.status === 200) {
this.setState({
loading: false,
deviceData: res.data.data.devices,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load devices.',
});
}
return <Tag color={color}>{status}</Tag>
this.setState({ loading: false });
});
};
/**
* Geo Dashboard controller
*/
controllerBar = () => {
const { RangePicker } = DatePicker;
let now = new Date();
let start = moment(
new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0),
);
let end = moment(start)
.add(1, 'days')
.subtract(1, 'seconds');
let ranges = {
'Today Only': [moment(start), moment(end)],
'Yesterday Only': [
moment(start).subtract(1, 'days'),
moment(end).subtract(1, 'days'),
],
'3 Days': [moment(start).subtract(3, 'days'), moment(end)],
'5 Days': [moment(start).subtract(5, 'days'), moment(end)],
'1 Week': [moment(start).subtract(7, 'days'), moment(end)],
'2 Weeks': [moment(start).subtract(14, 'days'), moment(end)],
'1 Month': [moment(start).subtract(1, 'months'), moment(end)],
};
render() {
const locationData = [...this.state.locationData];
let { deviceData } = this.state;
return (
<div className="container">
{this.controllerBar()}
{(locationData.length > 0) ?
<GeoCustomMap locationData={locationData}/>
:
<Empty/>
}
</div>
);
return (
<div className="controllerDiv">
<RangePicker
ranges={ranges}
style={{ marginRight: 20 }}
showTime
format="YYYY-MM-DD HH:mm:ss"
defaultValue={[this.state.start, this.state.end]}
onChange={this.applyCallback}
/>
<Select
showSearch
style={{ width: 220, marginRight: 20 }}
placeholder="Select a Device"
optionFilterProp="children"
onChange={this.handleDeviceList}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >=
0
}
>
{deviceData.map((device, index) => (
<Select.Option key={index} value={index}>
{device.name + ' '}
{this.statusTag(device)}
</Select.Option>
))}
</Select>
{this.fetchLocationButton()}
</div>
);
};
/**
* Creates color based tags on device status
* @param device - device object
*/
statusTag = device => {
const status = device.enrolmentInfo.status.toLowerCase();
let color = '#f9ca24';
switch (status) {
case 'active':
color = '#badc58';
break;
case 'created':
color = '#6ab04c';
break;
case 'inactive':
color = '#f9ca24';
break;
case 'blocked':
color = '#636e72';
break;
}
return <Tag color={color}>{status}</Tag>;
};
render() {
const locationData = [...this.state.locationData];
return (
<div className="container">
{this.controllerBar()}
{locationData.length > 0 ? (
<GeoCustomMap locationData={locationData} />
) : (
<Empty />
)}
</div>
);
}
}
export default withConfigContext(GeoDashboard);

View File

@ -16,160 +16,159 @@
* under the License.
*/
import React from "react";
import {Button, Form, Input, message, Modal, notification, Typography} from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
const {Text} = Typography;
let config = null;
import React from 'react';
import { Button, Form, Input, message, Modal, notification } from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
class AddGroup extends React.Component {
constructor(props) {
super(props);
this.state = {
addModalVisible: false,
name: '',
description: '',
};
}
constructor(props) {
super(props);
config = this.props.context;
this.state = {
addModalVisible: false,
name:'',
description:'',
onConfirmAdGroup = () => {
const config = this.props.context;
const groupData = {
name: this.state.name,
description: this.state.description,
};
// send request to the invoker
axios
.post(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/groups',
groupData,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 201) {
this.props.fetchGroups();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully added the group.',
});
}
}
onConfirmAdGroup = () => {
const config = this.props.context;
const groupData = {
name: this.state.name,
description: this.state.description
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to add group.',
});
}
});
};
//send request to the invoker
axios.post(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups",
groupData,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 201) {
this.props.fetchGroups();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully added the group.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to add group.",
});
}
openAddModal = () => {
this.setState({
addModalVisible: true,
});
};
handleAddOk = e => {
this.props.form.validateFields(err => {
if (!err) {
this.onConfirmAdGroup();
this.setState({
addModalVisible: false,
});
};
}
});
};
openAddModal = () => {
this.setState({
addModalVisible:true
})
};
handleAddCancel = e => {
this.setState({
addModalVisible: false,
});
};
handleAddOk = e => {
this.props.form.validateFields(err => {
if (!err) {
this.onConfirmAdGroup();
this.setState({
addModalVisible: false,
});
}
});
};
onChangeName = e => {
this.setState({
name: e.currentTarget.value,
});
};
handleAddCancel = e => {
this.setState({
addModalVisible: false,
});
};
onChangeDescription = e => {
this.setState({
description: e.currentTarget.value,
});
};
onChangeName = (e) => {
this.setState({
name:e.currentTarget.value
})
};
onChangeDescription = (e) => {
this.setState({
description:e.currentTarget.value
})
};
render() {
const { getFieldDecorator } = this.props.form;
return(
<div>
<div>
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal}>
Add Group
</Button>
</div>
<div>
<Modal
title="ADD NEW GROUP"
width="40%"
visible={this.state.addModalVisible}
onOk={this.handleAddOk}
onCancel={this.handleAddCancel}
footer={[
<Button key="cancel" onClick={this.handleAddCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.handleAddOk}>
Submit
</Button>,
]}
>
<div style={{alignItems:"center"}}>
<p>Create new device group on IoT Server.</p>
<Form
labelCol={{ span: 5 }}
wrapperCol={{ span: 18 }}
>
<Form.Item label="Name" style={{display:"block"}}>
{getFieldDecorator('name', {
rules: [
{
required: true,
message: 'Please input group name',
},
],
})(<Input onChange={this.onChangeName}/>)}
</Form.Item>
<Form.Item label="Description" style={{display:"block"}}>
{getFieldDecorator('description', {
rules: [
{
required: true,
message: 'Please input group description',
},
],
})(<Input onChange={this.onChangeDescription}/>)}
</Form.Item>
</Form>
</div>
</Modal>
</div>
render() {
const { getFieldDecorator } = this.props.form;
return (
<div>
<div>
<Button
type="primary"
icon="plus"
size={'default'}
onClick={this.openAddModal}
>
Add Group
</Button>
</div>
<div>
<Modal
title="ADD NEW GROUP"
width="40%"
visible={this.state.addModalVisible}
onOk={this.handleAddOk}
onCancel={this.handleAddCancel}
footer={[
<Button key="cancel" onClick={this.handleAddCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.handleAddOk}>
Submit
</Button>,
]}
>
<div style={{ alignItems: 'center' }}>
<p>Create new device group on IoT Server.</p>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item label="Name" style={{ display: 'block' }}>
{getFieldDecorator('name', {
rules: [
{
required: true,
message: 'Please input group name',
},
],
})(<Input onChange={this.onChangeName} />)}
</Form.Item>
<Form.Item label="Description" style={{ display: 'block' }}>
{getFieldDecorator('description', {
rules: [
{
required: true,
message: 'Please input group description',
},
],
})(<Input onChange={this.onChangeDescription} />)}
</Form.Item>
</Form>
</div>
)
}
</Modal>
</div>
</div>
);
}
}
export default withConfigContext(Form.create({name: 'add-group'})(AddGroup));
export default withConfigContext(Form.create({ name: 'add-group' })(AddGroup));

View File

@ -16,364 +16,380 @@
* under the License.
*/
import React from "react";
import React from 'react';
import {
Button,
Divider,
Form,
Icon,
Input,
message,
Modal,
notification,
Popconfirm,
Select,
Tooltip,
Typography
} from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
Button,
Divider,
Form,
Icon,
Input,
message,
Modal,
notification,
Popconfirm,
Select,
Tooltip,
Typography,
} from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
const {Text} = Typography;
let config = null;
const { Text } = Typography;
class GroupActions extends React.Component {
constructor(props) {
super(props);
this.state = {
editModalVisible: false,
shareModalVisible: false,
name: this.props.data.name,
description: this.props.data.description,
groupDataObject: {},
rolesData: [],
shareRolesData: [],
};
}
constructor(props) {
super(props);
config = this.props.context;
this.state = {
editModalVisible: false,
shareModalVisible: false,
name:this.props.data.name,
description:this.props.data.description,
groupDataObject:{},
rolesData:[],
shareRolesData:[]
onConfirmDeleteGroup = () => {
const config = this.props.context;
// send request to the invoker
axios
.delete(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/groups/id/' +
this.props.data.id,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully deleted the group.',
});
}
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to delete group.',
});
}
});
};
onConfirmDeleteGroup = () => {
const config = this.props.context;
onConfirmUpdateGroup = data => {
const config = this.props.context;
//send request to the invoker
axios.delete(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/id/" + this.props.data.id,
{headers: {'Content-Type': 'application/json'}}
// send request to the invoker
axios
.put(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/groups/id/' +
this.props.data.id,
data,
)
.then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully updated the group.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to update group.',
});
}
});
};
).then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully deleted the group.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to delete group.",
});
}
});
fetchUserRoles = (params = {}) => {
const config = this.props.context;
const apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/roles';
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
this.setState({
rolesData: res.data.data.roles,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load roles.',
});
}
});
};
onConfirmShareGroup = data => {
const config = this.props.context;
// send request to the invoker
axios
.post(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/groups/id/' +
this.props.data.id +
'/share',
data,
)
.then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully shared the group.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to share group.',
});
}
});
};
openEditModal = () => {
this.setState({
editModalVisible: true,
});
};
openShareModal = () => {
this.fetchUserRoles();
this.setState({
shareModalVisible: true,
});
};
handleEditOk = e => {
const groupDataObject = {
name: this.state.name,
description: this.state.description,
id: this.props.data.id,
owner: this.props.data.owner,
groupProperties: this.props.data.groupProperties,
};
onConfirmUpdateGroup = (data) => {
const config = this.props.context;
this.setState({ groupDataObject });
//send request to the invoker
axios.put(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/id/" + this.props.data.id,
data
).then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully updated the group.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to update group.",
});
}
});
};
fetchUserRoles = (params = {}) => {
const config = this.props.context;
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/roles";
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
this.setState({
rolesData: res.data.data.roles,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load roles.",
});
}
});
};
onConfirmShareGroup = (data) => {
const config = this.props.context;
//send request to the invoker
axios.post(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/id/" + this.props.data.id + "/share",
data
).then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully shared the group.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to share group.",
});
}
});
}
openEditModal = () => {
this.props.form.validateFields(err => {
if (!err) {
this.onConfirmUpdateGroup(this.state.groupDataObject);
this.setState({
editModalVisible:true
})
};
openShareModal = () => {
this.fetchUserRoles();
this.setState({
shareModalVisible:true
})
}
handleEditOk = e => {
this.state.groupDataObject = {
name:this.state.name,
description:this.state.description,
id:this.props.data.id,
owner:this.props.data.owner,
groupProperties:this.props.data.groupProperties
};
this.props.form.validateFields(err => {
if (!err) {
this.onConfirmUpdateGroup(this.state.groupDataObject);
this.setState({
editModalVisible: false,
});
}
editModalVisible: false,
});
};
}
});
};
handleEditCancel = e => {
this.setState({
editModalVisible: false,
});
};
handleEditCancel = e => {
this.setState({
editModalVisible: false,
});
};
handleShareOk = e => {
this.setState({
shareModalVisible: false,
});
this.onConfirmShareGroup(this.state.shareRolesData);
};
handleShareOk = e => {
this.setState({
shareModalVisible: false,
});
this.onConfirmShareGroup(this.state.shareRolesData);
};
handleShareCancel = e => {
this.setState({
shareModalVisible: false,
});
};
handleShareCancel = e => {
this.setState({
shareModalVisible: false,
});
};
onChangeName = (e) => {
this.setState({
name:e.currentTarget.value
})
};
onChangeName = e => {
this.setState({
name: e.currentTarget.value,
});
};
onChangeDescription = (e) => {
this.setState({
description:e.currentTarget.value
})
};
onChangeDescription = e => {
this.setState({
description: e.currentTarget.value,
});
};
handleRolesDropdownChange = (value) => {
this.setState({
shareRolesData:value
})
};
handleRolesDropdownChange = value => {
this.setState({
shareRolesData: value,
});
};
render() {
const isAdminGroups = this.props.data.id==1 || this.props.data.id==2;
const { Option } = Select;
const { getFieldDecorator } = this.props.form;
let item = this.state.rolesData.map((data) =>
<Select.Option
value={data}
key={data}>
{data}
</Select.Option>);
return(
<div>
<div style={{display:isAdminGroups ? "none" : "inline"}}>
<Tooltip placement="top" title={"Share Group"}>
<a><Icon type="share-alt" onClick={this.openShareModal}/></a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="top" title={"Edit Group"}>
<a><Icon type="edit" onClick={this.openEditModal}/></a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={"Delete Group"}>
<Popconfirm
placement="top"
title={"Are you sure?"}
onConfirm={this.onConfirmDeleteGroup}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
</Popconfirm>
</Tooltip>
</div>
<div>
<Modal
title="Update Group"
width="40%"
visible={this.state.editModalVisible}
onOk={this.handleEditOk}
onCancel={this.handleEditCancel}
footer={[
<Button key="cancel" onClick={this.handleEditCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.handleEditOk}>
Submit
</Button>,
]}
>
<div style={{alignItems:"center"}}>
<p>Enter new name and description for the group</p>
<Form
labelCol={{ span: 5 }}
wrapperCol={{ span: 18 }}
>
<Form.Item label="Name" style={{display:"block"}}>
{getFieldDecorator(
'name',
{
initialValue: this.props.data.name,
rules: [
{
required: true,
message: 'Please input group name',
},
],
})(<Input
onChange={this.onChangeName}/>)}
</Form.Item>
<Form.Item label="Description" style={{display:"block"}}>
{getFieldDecorator(
'description',
{
initialValue: this.props.data.description,
rules: [
{
required: true,
message: 'Please input group description',
},
],
})(<Input
onChange={this.onChangeDescription}/>)}
</Form.Item>
</Form>
</div>
</Modal>
</div>
<div>
<Modal
title="Share Group"
width="500px"
visible={this.state.shareModalVisible}
onOk={this.handleShareOk}
onCancel={this.handleShareCancel}
footer={[
<Button key="new-role" onClick={this.handleShareCancel}>
New Role
</Button>,
<Button key="new-role-selection" onClick={this.handleShareCancel}>
New Role from Selection
</Button>,
<Button key="submit" type="primary" onClick={this.handleShareOk}>
Share
</Button>,
]}
>
<p>Select user role(s)</p>
<Select
mode="multiple"
defaultValue={"admin"}
style={{ width: '100%' }}
onChange={this.handleRolesDropdownChange}>
{item}
</Select>,
</Modal>
</div>
render() {
const isAdminGroups = this.props.data.id == 1 || this.props.data.id == 2;
const { getFieldDecorator } = this.props.form;
let item = this.state.rolesData.map(data => (
<Select.Option value={data} key={data}>
{data}
</Select.Option>
));
return (
<div>
<div style={{ display: isAdminGroups ? 'none' : 'inline' }}>
<Tooltip placement="top" title={'Share Group'}>
<a>
<Icon type="share-alt" onClick={this.openShareModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="top" title={'Edit Group'}>
<a>
<Icon type="edit" onClick={this.openEditModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={'Delete Group'}>
<Popconfirm
placement="top"
title={'Are you sure?'}
onConfirm={this.onConfirmDeleteGroup}
okText="Ok"
cancelText="Cancel"
>
<a>
<Text type="danger">
<Icon type="delete" />
</Text>
</a>
</Popconfirm>
</Tooltip>
</div>
<div>
<Modal
title="Update Group"
width="40%"
visible={this.state.editModalVisible}
onOk={this.handleEditOk}
onCancel={this.handleEditCancel}
footer={[
<Button key="cancel" onClick={this.handleEditCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.handleEditOk}>
Submit
</Button>,
]}
>
<div style={{ alignItems: 'center' }}>
<p>Enter new name and description for the group</p>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item label="Name" style={{ display: 'block' }}>
{getFieldDecorator('name', {
initialValue: this.props.data.name,
rules: [
{
required: true,
message: 'Please input group name',
},
],
})(<Input onChange={this.onChangeName} />)}
</Form.Item>
<Form.Item label="Description" style={{ display: 'block' }}>
{getFieldDecorator('description', {
initialValue: this.props.data.description,
rules: [
{
required: true,
message: 'Please input group description',
},
],
})(<Input onChange={this.onChangeDescription} />)}
</Form.Item>
</Form>
</div>
)
}
</Modal>
</div>
<div>
<Modal
title="Share Group"
width="500px"
visible={this.state.shareModalVisible}
onOk={this.handleShareOk}
onCancel={this.handleShareCancel}
footer={[
<Button key="new-role" onClick={this.handleShareCancel}>
New Role
</Button>,
<Button key="new-role-selection" onClick={this.handleShareCancel}>
New Role from Selection
</Button>,
<Button key="submit" type="primary" onClick={this.handleShareOk}>
Share
</Button>,
]}
>
<p>Select user role(s)</p>
<Select
mode="multiple"
defaultValue={'admin'}
style={{ width: '100%' }}
onChange={this.handleRolesDropdownChange}
>
{item}
</Select>
,
</Modal>
</div>
</div>
);
}
}
export default withConfigContext(Form.create({name: 'group-actions'})(GroupActions));
export default withConfigContext(
Form.create({ name: 'group-actions' })(GroupActions),
);

View File

@ -16,193 +16,191 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {message, notification, Table, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { message, notification, Table } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
import GroupActions from "./GroupActions";
import AddGroup from "./AddGroup";
import Filter from "../Utils/Filter/Filter";
const {Text} = Typography;
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
import GroupActions from './GroupActions';
import AddGroup from './AddGroup';
import Filter from '../Utils/Filter/Filter';
const searchFields = [
{
name: 'name',
placeholder: 'Name'
},
{
name: 'owner',
placeholder: 'Owner'
}
{
name: 'name',
placeholder: 'Name',
},
{
name: 'owner',
placeholder: 'Owner',
},
];
let config = null;
let apiUrl;
const getTimeAgo = (time) => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
};
class GroupsTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
};
}
columns = [
{
title: 'Group Name',
dataIndex: 'name',
width: 100,
},
{
title: 'Owner',
dataIndex: 'owner',
key: 'owner',
// render: enrolmentInfo => enrolmentInfo.owner
// todo add filtering options
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
// render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
},
{
title: 'Action',
dataIndex: 'id',
key: 'action',
render: (id, row) => (
<span>
<GroupActions data={row} fetchGroups={this.fetchGroups} />
</span>
),
},
];
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows,
});
},
};
componentDidMount() {
this.fetchGroups();
}
// fetch data from api
fetchGroups = (params = {}, filters = {}) => {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
...filters,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key])
.join('&');
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/admin/groups?' +
encodedExtraParams;
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: []
};
}
columns = [
{
title: 'Group Name',
dataIndex: 'name',
width: 100,
},
{
title: 'Owner',
dataIndex: 'owner',
key: 'owner',
// render: enrolmentInfo => enrolmentInfo.owner
// todo add filtering options
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
// render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
},
{
title: 'Action',
dataIndex: 'id',
key: 'action',
render: (id, row) => (
<span>
<GroupActions data={row} fetchGroups={this.fetchGroups}/>
</span>
),
},
];
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
data: res.data.data,
pagination,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load device groups.',
});
}
};
componentDidMount() {
this.fetchGroups();
}
this.setState({ loading: false });
});
};
//fetch data from api
fetchGroups = (params = {}, filters = {}) => {
const config = this.props.context;
this.setState({loading: true});
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetchGroups({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
render() {
const { data, pagination, loading } = this.state;
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
...filters
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/admin/groups?" + encodedExtraParams;
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data,
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load device groups.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetchGroups({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
return (
<div>
<div style={{background: '#f0f2f5'}}>
<AddGroup fetchGroups={this.fetchGroups} style={{marginBottom:"10px"}}/>
</div>
<div style={{textAlign: 'right'}}>
<Filter fields={searchFields} callback={this.fetchGroups}/>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<Table
columns={this.columns}
rowKey={record => (record.id)}
dataSource={data.deviceGroups}
pagination={{
...pagination,
size: "small",
total: data.count,
pageSize: 10,
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
</div>
);
}
return (
<div>
<div style={{ background: '#f0f2f5' }}>
<AddGroup
fetchGroups={this.fetchGroups}
style={{ marginBottom: '10px' }}
/>
</div>
<div style={{ textAlign: 'right' }}>
<Filter fields={searchFields} callback={this.fetchGroups} />
</div>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<Table
columns={this.columns}
rowKey={record => record.id}
dataSource={data.deviceGroups}
pagination={{
...pagination,
size: 'small',
total: data.count,
pageSize: 10,
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} groups`,
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
</div>
);
}
}
export default withConfigContext(GroupsTable);

View File

@ -1,104 +1,86 @@
import React from 'react';
import {Button, Form, Row, Col, Card, Steps, Input, message, Modal, notification, Typography} from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
import DeviceType from "../Devices/DeviceType";
import SelectPlatform from "./SelectPlatform";
import ConfigureProfile from "./ConfigureProfile";
const {Step} = Steps;
import { Button, Form, Row, Col, Card, Steps } from 'antd';
import { withConfigContext } from '../../context/ConfigContext';
import SelectPlatform from './SelectPlatform';
import ConfigureProfile from './ConfigureProfile';
const { Step } = Steps;
class AddPolicy extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
this.state = {
isAddDeviceModalVisible: false,
current : 0,
}
constructor(props) {
super(props);
this.config = this.props.context;
this.state = {
isAddDeviceModalVisible: false,
current: 0,
};
}
onClickType = () =>{
this.setState({
current: 1,
})
};
onClickType = () => {
this.setState({
current: 1,
});
};
next() {
const current = this.state.current + 1;
this.setState({ current });
}
prev() {
const current = this.state.current - 1;
this.setState({ current });
}
openAddDeviceModal = () =>{
this.setState({
isAddDeviceModalVisible : true,
})
};
render() {
const {loading, current, isError, supportedOsVersions, errorText, forbiddenErrors} = this.state;
const { getFieldDecorator } = this.props.form;
return (
<div>
<Row>
<Col span={20} offset={2}>
<Steps style={{minHeight: 32}} current={current}>
<Step key="Platform" title="Select a Platform"/>
<Step key="ProfileConfigure" title="Configure profile"/>
<Step key="PolicyType" title="Select policy type"/>
<Step key="AssignGroups" title="Assign to groups"/>
<Step key="Publish" title="Publish to devices"/>
<Step key="Result" title="Result"/>
</Steps>
</Col>
<Col span={16} offset={4}>
<Card style={{marginTop: 24}}>
<div style={{display: (current === 0 ? 'unset' : 'none')}}>
<SelectPlatform onClickType={this.onClickType}/>
</div>
<div style={{display: (current === 1 ? 'unset' : 'none')}}>
<ConfigureProfile/>
</div>
<div style={{display: (current === 2 ? 'unset' : 'none')}}>
</div>
<div style={{display: (current === 3 ? 'unset' : 'none')}}>
</div>
<div style={{display: (current === 4 ? 'unset' : 'none')}}>
</div>
<div style={{display: (current === 5 ? 'unset' : 'none')}}>
</div>
</Card>
</Col>
<Col span={16} offset={4}>
<div style={{marginTop: 24}}>
{current > 0 && (
<Button style={{ marginRight: 8 }} onClick={() => this.prev()}>
Previous
</Button>
)}
{current < 5 && current > 0 && (
<Button type="primary" onClick={() => this.next()}>
Next
</Button>
)}
{current === 5 && (
<Button type="primary">
Done
</Button>
)}
</div>
</Col>
</Row>
next() {
const current = this.state.current + 1;
this.setState({ current });
}
prev() {
const current = this.state.current - 1;
this.setState({ current });
}
render() {
const { current } = this.state;
return (
<div>
<Row>
<Col span={20} offset={2}>
<Steps style={{ minHeight: 32 }} current={current}>
<Step key="Platform" title="Select a Platform" />
<Step key="ProfileConfigure" title="Configure profile" />
<Step key="PolicyType" title="Select policy type" />
<Step key="AssignGroups" title="Assign to groups" />
<Step key="Publish" title="Publish to devices" />
<Step key="Result" title="Result" />
</Steps>
</Col>
<Col span={16} offset={4}>
<Card style={{ marginTop: 24 }}>
<div style={{ display: current === 0 ? 'unset' : 'none' }}>
<SelectPlatform onClickType={this.onClickType} />
</div>
<div style={{ display: current === 1 ? 'unset' : 'none' }}>
<ConfigureProfile />
</div>
<div style={{ display: current === 2 ? 'unset' : 'none' }}></div>
<div style={{ display: current === 3 ? 'unset' : 'none' }}></div>
<div style={{ display: current === 4 ? 'unset' : 'none' }}></div>
<div style={{ display: current === 5 ? 'unset' : 'none' }}></div>
</Card>
</Col>
<Col span={16} offset={4}>
<div style={{ marginTop: 24 }}>
{current > 0 && (
<Button style={{ marginRight: 8 }} onClick={() => this.prev()}>
Previous
</Button>
)}
{current < 5 && current > 0 && (
<Button type="primary" onClick={() => this.next()}>
Next
</Button>
)}
{current === 5 && <Button type="primary">Done</Button>}
</div>
);
}
</Col>
</Row>
</div>
);
}
}
export default withConfigContext(Form.create({name: 'add-policy'})(AddPolicy));
export default withConfigContext(
Form.create({ name: 'add-policy' })(AddPolicy),
);

View File

@ -1,268 +1,270 @@
import React from 'react';
import {Tabs, Row, Col, Switch, Menu,Input, Typography, Form, Checkbox, Select,
Tooltip, Icon, Collapse, Alert, Upload, Button,Radio} from "antd";
import {withConfigContext} from "../../context/ConfigContext";
import "../../pages/Dashboard/Policies/policies.css";
import jsonResponse from "./configuration";
const { Title, Text, Paragraph } = Typography;
import {
Tabs,
Row,
Col,
Switch,
Input,
Typography,
Form,
Checkbox,
Select,
Tooltip,
Icon,
Alert,
Upload,
Button,
Radio,
} from 'antd';
import { withConfigContext } from '../../context/ConfigContext';
import '../../pages/Dashboard/Policies/policies.css';
import jsonResponse from './configuration';
const { Title, Paragraph } = Typography;
const { TabPane } = Tabs;
const {Option} = Select;
const {Panel} = Collapse;
const { Option } = Select;
const { TextArea } = Input;
const policyConfigurationsList = jsonResponse.PolicyConfigurations;
class ConfigureProfile extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
this.policies = policyConfigurationsList.androidPolicy.Policy;
this.state = {
isDisplayMain: "none",
activeKeys: []
}
constructor(props) {
super(props);
this.config = this.props.context;
this.policies = policyConfigurationsList.androidPolicy.Policy;
this.state = {
isDisplayMain: 'none',
activeKeys: [],
};
}
componentDidMount() {
componentDidMount() {}
onChange = e => {
console.log(`checked = ${e.target.id}`);
};
onChecked = (e, i) => {
if (e) {
this.setState({
isDisplayMain: 'block',
});
} else {
this.setState({
isDisplayMain: 'none',
});
}
};
onChange = (e) =>{
console.log(`checked = ${e.target.id}`);
};
onClickSwitch = e => {};
onChecked = (e,i) =>{
if(e){
this.setState({
isDisplayMain: "block",
});
}else{
this.setState({
isDisplayMain: "none",
});
getPanelItems = panel => {
const { getFieldDecorator } = this.props.form;
return panel.map((item, k) => {
switch (item._type) {
case 'select':
return (
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
style={{ display: 'block' }}
>
{getFieldDecorator(`${item._id}`, {
initialValue: `${item.Optional.Option[0]}`,
})(
<Select>
{item.Optional.Option.map(option => {
return <Option key={option}>{option}</Option>;
})}
</Select>,
)}
</Form.Item>
);
case 'input':
return (
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
style={{ display: 'block' }}
>
{getFieldDecorator(`${item._id}`, {
rules: [
{
pattern: new RegExp(`${item.Optional.rules.regex}`),
message: `${item.Optional.rules.validationMsg}`,
},
],
})(<Input placeholder={item.Optional.Placeholder} />)}
</Form.Item>
);
case 'checkbox':
return (
<Form.Item key={k}>
{getFieldDecorator(`${item._id}`, {
valuePropName: 'checked',
initialValue: `${item.Optional.checked}`,
})(
<Checkbox
// checked={item.Optional.checked}
onChange={this.onChange}
>
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
</Checkbox>,
)}
</Form.Item>
);
case 'textArea':
return (
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
style={{ display: 'block' }}
>
{getFieldDecorator(`${item._id}`, {})(
<TextArea
placeholder={item.Optional.Placeholder}
rows={item.Optional.Row}
/>,
)}
</Form.Item>
);
case 'radioGroup':
return (
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
style={{ display: 'block' }}
>
{getFieldDecorator(`${item._id}`, {})(
<Radio.Group>
{item.Optional.Radio.map(option => {
return (
<Radio key={option} value={option}>
{option}
</Radio>
);
})}
</Radio.Group>,
)}
</Form.Item>
);
case 'title':
return (
<Title key={k} level={4}>
{item.Label}{' '}
</Title>
);
case 'paragraph':
return (
<Paragraph key={k} style={{ marginTop: 20 }}>
{item.Label}{' '}
</Paragraph>
);
case 'alert':
return (
<Alert key={k} description={item.Label} type="warning" showIcon />
);
case 'upload':
return (
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
>
{getFieldDecorator('upload', {})(
<Upload>
<Button>
<Icon type="upload" /> Click to upload
</Button>
</Upload>,
)}
</Form.Item>
);
default:
return null;
}
});
};
}
};
onClickSwitch = (e) =>{
};
getPanelItems = (panel)=>{
const { getFieldDecorator } = this.props.form;
return (
panel.map((item,k)=>{
switch(item._type){
case "select":
return(
<Form.Item key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
style={{display: "block"}}>
{getFieldDecorator(`${item._id}`, {
initialValue: `${item.Optional.Option[0]}`
})(
<Select>
{item.Optional.Option.map((option)=>{
return(
<Option key={option}>{option}</Option>
);
})}
</Select>
)}
</Form.Item>
);
case "input":
return(
<Form.Item key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
style={{display: "block"}}>
{getFieldDecorator(`${item._id}`, {
rules: [
{
pattern: new RegExp(`${item.Optional.rules.regex}`),
message: `${item.Optional.rules.validationMsg}`,
},
],
})(
<Input placeholder={item.Optional.Placeholder}/>
)}
</Form.Item>
);
case "checkbox":
return(
<Form.Item key={k}>
{getFieldDecorator(`${item._id}`, {
valuePropName: 'checked',
initialValue: `${item.Optional.checked}`,
})(
<Checkbox
// checked={item.Optional.checked}
onChange={this.onChange}
>
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
</Checkbox>
)}
</Form.Item>
);
case "textArea":
return(
<Form.Item key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
style={{display: "block"}}>
{getFieldDecorator(`${item._id}`, {
})(
<TextArea placeholder={item.Optional.Placeholder}
rows={item.Optional.Row} />
)}
</Form.Item>
);
case "radioGroup":
return(
<Form.Item key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
style={{display: "block"}}>
{getFieldDecorator(`${item._id}`, {
})(
<Radio.Group>
{item.Optional.Radio.map((option)=>{
return(
<Radio value={option}>{option}</Radio>
);
})}
</Radio.Group>
)}
</Form.Item>
);
case "title":
return(
<Title key={k} level={4}>{item.Label} </Title>
);
case "paragraph":
return(
<Paragraph key={k} style={{marginTop:20}}>{item.Label} </Paragraph>
);
case "alert":
return(
<Alert
key={k}
description={item.Label}
type="warning"
showIcon
render() {
return (
<div>
<Tabs tabPosition={'left'} size={'large'}>
{this.policies.map((element, i) => {
return (
<TabPane tab={element.Name} key={i}>
{/* <div style={{ height: 800, overflowY: "scroll"}}>*/}
{Object.values(element.Panel).map((panel, j) => {
return (
<div key={j}>
<div>
<Row>
<Col offset={0} span={14}>
<Title level={4}>{panel.title} </Title>
</Col>
<Col offset={8} span={1}>
<Switch
checkedChildren="ON"
unCheckedChildren="OFF"
id={i}
onClick={this.onClickSwitch}
onChange={this.onChecked}
/>
);
case "upload":
return(
<Form.Item key={k}
label={
<span>
{item.Label}&nbsp;
<Tooltip title={item.tooltip} placement="right">
<Icon type="question-circle-o" />
</Tooltip>
</span>
}
>
{getFieldDecorator('upload', {
})(
<Upload>
<Button>
<Icon type="upload" /> Click to upload
</Button>
</Upload>,
)}
</Form.Item>
);
default:
return null;
}
})
)
};
render() {
return (
<div>
<Tabs tabPosition={"left"} size={"large"}>
{ this.policies.map((element, i) =>{
return(
<TabPane tab={element.Name} key={i} >
{/*<div style={{ height: 800, overflowY: "scroll"}}>*/}
{ Object.values(element.Panel).map((panel, j)=>{
return(
<div key={j} >
<div>
<Row>
<Col offset={0} span={14}>
<Title level={4}>{panel.title} </Title>
</Col>
<Col offset={8} span={1}>
<Switch
checkedChildren="ON"
unCheckedChildren="OFF"
id={i}
onClick={this.onClickSwitch}
onChange={this.onChecked}
/>
</Col>
</Row>
<Row>{panel.description}</Row>
</div>
<div style={{display: `${this.state.isDisplayMain}`}}>
<Form >
{this.getPanelItems(panel.PanelItem)}
</Form>
</div>
</div>
);
})
}
</TabPane>
)
})
}
</Tabs>
</div>
);
}
</Col>
</Row>
<Row>{panel.description}</Row>
</div>
<div style={{ display: `${this.state.isDisplayMain}` }}>
<Form>{this.getPanelItems(panel.PanelItem)}</Form>
</div>
</div>
);
})}
</TabPane>
);
})}
</Tabs>
</div>
);
}
}
export default withConfigContext(Form.create()(ConfigureProfile));
export default withConfigContext(Form.create()(ConfigureProfile));

View File

@ -16,165 +16,162 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {message, notification, Table, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { message, notification, Table } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
const {Text} = Typography;
let config = null;
let apiUrl;
const columns = [
{
title: 'Policy Name',
dataIndex: 'policyName',
width: 100,
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
// render: enrolmentInfo => enrolmentInfo.owner
// todo add filtering options
},
{
title: 'Compilance',
dataIndex: 'compliance',
key: 'compliance',
// render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
},
{
title: 'Policy Type',
dataIndex: 'policyType',
key: 'policyType',
// render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
}
{
title: 'Policy Name',
dataIndex: 'policyName',
width: 100,
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
// render: enrolmentInfo => enrolmentInfo.owner
// todo add filtering options
},
{
title: 'Compilance',
dataIndex: 'compliance',
key: 'compliance',
// render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
},
{
title: 'Policy Type',
dataIndex: 'policyType',
key: 'policyType',
// render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
},
];
const getTimeAgo = (time) => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
};
class PoliciesTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows,
});
},
};
componentDidMount() {
this.fetchGroups();
}
// fetch data from api
fetchGroups = (params = {}) => {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key])
.join('&');
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/policies?' +
encodedExtraParams;
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: []
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
data: res.data.data.policies,
pagination,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load policies.',
});
}
};
componentDidMount() {
this.fetchGroups();
}
this.setState({ loading: false });
});
};
//fetch data from api
fetchGroups = (params = {}) => {
const config = this.props.context;
this.setState({loading: true});
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/policies?" + encodedExtraParams;
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data.policies,
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load policies.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record => (record.id)}
dataSource={data}
pagination={{
...pagination,
size: "small",
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
);
}
render() {
const { data, pagination, loading } = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record => record.id}
dataSource={data}
pagination={{
...pagination,
size: 'small',
// position: "top",
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} groups`,
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
);
}
}
export default withConfigContext(PoliciesTable);
export default withConfigContext(PoliciesTable);

View File

@ -16,133 +16,126 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {Card, Col, Icon, message, notification, Row, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { Card, Col, Icon, message, notification, Row } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
const {Text} = Typography;
let config = null;
let apiUrl;
class SelectPlatform extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
};
}
componentDidMount() {
this.fetchUsers();
}
onClickCard = data => {
console.log(data);
this.props.onClickType();
};
// fetch data from api
fetchUsers = (params = {}) => {
const config = this.props.context;
this.setState({ loading: true });
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/device-types';
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: []
};
}
data: JSON.parse(res.data.data),
pagination,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load device types.',
});
}
componentDidMount() {
this.fetchUsers();
}
this.setState({ loading: false });
});
};
onClickCard = (data) =>{
console.log(data);
this.props.onClickType();
};
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
//fetch data from api
fetchUsers = (params = {}) => {
const config = this.props.context;
this.setState({loading: true});
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/device-types";
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: JSON.parse(res.data.data),
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load device types.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { Meta } = Card;
const itemCard = data.map((data) =>
<Col span={5} key={data.id}>
<Card
size="default"
style={{ width: 150 }}
bordered={true}
onClick={this.onClickCard}
cover={<Icon type="android" key="device-types" style={{color:'#ffffff',
backgroundColor:'#4b92db', fontSize: '100px', padding:'20px'}}/>}
>
<Meta
title={data.name}
/>
</Card>
</Col>
);
return (
<div>
<Row gutter={16}>
{itemCard}
</Row>
</div>
);
}
render() {
const { data } = this.state;
const { Meta } = Card;
const itemCard = data.map(data => (
<Col span={5} key={data.id}>
<Card
size="default"
style={{ width: 150 }}
bordered={true}
onClick={this.onClickCard}
cover={
<Icon
type="android"
key="device-types"
style={{
color: '#ffffff',
backgroundColor: '#4b92db',
fontSize: '100px',
padding: '20px',
}}
/>
}
>
<Meta title={data.name} />
</Card>
</Col>
));
return (
<div>
<Row gutter={16}>{itemCard}</Row>
</div>
);
}
}
export default withConfigContext(SelectPlatform);
export default withConfigContext(SelectPlatform);

View File

@ -16,50 +16,47 @@
* under the License.
*/
import React from "react";
import React from 'react';
import { DatePicker } from 'antd';
import moment from 'moment';
class DateRangePicker extends React.Component {
constructor(props) {
super(props);
}
constructor(props){
super(props);
}
// Send updated date range to Reports.js when duration change
onChange = (dates, dateStrings) => {
this.props.updateDurationValue(dateStrings[0], dateStrings[1]);
};
//Send updated date range to Reports.js when duration change
onChange = (dates, dateStrings) => {
this.props.updateDurationValue(dateStrings[0],dateStrings[1]);
}
render(){
const { RangePicker } = DatePicker;
return(
<RangePicker
ranges={{
'Today': [
moment(),
moment()],
'Yesterday': [
moment().subtract(1, 'days'),
moment().subtract(1, 'days')],
'Last 7 Days': [
moment().subtract(6, 'days'),
moment()],
'Last 30 Days': [
moment().subtract(29, 'days'),
moment()],
'This Month': [
moment().startOf('month'),
moment().endOf('month')],
'Last Month': [
moment().subtract(1, 'month').startOf('month'),
moment().subtract(1, 'month').endOf('month')]
}}
format="YYYY-MM-DD"
onChange={this.onChange}
/>
)
}
render() {
const { RangePicker } = DatePicker;
return (
<RangePicker
ranges={{
Today: [moment(), moment()],
Yesterday: [
moment().subtract(1, 'days'),
moment().subtract(1, 'days'),
],
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
'This Month': [moment().startOf('month'), moment().endOf('month')],
'Last Month': [
moment()
.subtract(1, 'month')
.startOf('month'),
moment()
.subtract(1, 'month')
.endOf('month'),
],
}}
format="YYYY-MM-DD"
onChange={this.onChange}
/>
);
}
}
export default DateRangePicker;
export default DateRangePicker;

View File

@ -16,52 +16,53 @@
* under the License.
*/
import React from "react";
import React from 'react';
import { Select } from 'antd';
class Filter extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedItem: null,
};
}
constructor(props){
super(props);
const { Option } = Select;
this.state = {
selectedItem:null
// Send updated filter value to Reports.js
onChange = value => {
this.setState({ selectedItem: value }, () => {
if (this.props.dropDownName == 'Device Status') {
this.props.updateFiltersValue(this.state.selectedItem, 'Device Status');
} else {
this.props.updateFiltersValue(
this.state.selectedItem,
'Device Ownership',
);
}
});
};
render() {
// Dynamically generate dropdown items from dropDownItems array
let item = this.props.dropDownItems.map(data => (
<Select.Option value={data} key={data}>
{data}
</Select.Option>
));
return (
<Select
showSearch
style={{ width: 200 }}
placeholder={this.props.dropDownName}
optionFilterProp="children"
onChange={this.onChange}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
}
//Send updated filter value to Reports.js
onChange = value => {
this.setState({selectedItem:value},() => {
if(this.props.dropDownName=="Device Status"){
this.props.updateFiltersValue(this.state.selectedItem,"Device Status");
}else{
this.props.updateFiltersValue(this.state.selectedItem, "Device Ownership");
}
});
}
render(){
//Dynamically generate dropdown items from dropDownItems array
let item = this.props.dropDownItems.map((data) =>
<Select.Option
value={data}
key={data}>
{data}
</Select.Option>);
return(
<Select
showSearch
style={{ width: 200 }}
placeholder={this.props.dropDownName}
optionFilterProp="children"
onChange={this.onChange}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}>
{item}
</Select>
)
}
>
{item}
</Select>
);
}
}
export default Filter;
export default Filter;

View File

@ -16,110 +16,112 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon,
Tag,
Radio, Select, Button, Card,
Row, Col, message, notification
} from "antd";
import React from 'react';
import { PageHeader, Breadcrumb, Icon, Select, Button, Card } from 'antd';
import {Link} from "react-router-dom";
import PoliciesTable from "../../../components/Policies/PoliciesTable";
import DevicesTable from "../../../components/Devices/DevicesTable";
import DateRangePicker from "../../../components/Reports/DateRangePicker";
import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable";
import PieChart from "../../../components/Reports/Widgets/PieChart";
import axios from "axios";
import CountWidget from "../../../components/Reports/Widgets/CountWidget";
import {withConfigContext} from "../../../context/ConfigContext";
const {Paragraph} = Typography;
const { CheckableTag } = Tag;
import { Link } from 'react-router-dom';
import ReportDeviceTable from '../../../components/Devices/ReportDevicesTable';
import PieChart from '../../../components/Reports/Widgets/PieChart';
import { withConfigContext } from '../../../context/ConfigContext';
const { Option } = Select;
let config = null;
class DeviceStatusReport extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
config = this.props.context;
const { reportData } = this.props.location;
this.state = {
selectedTags: ['Enrolled'],
paramsObject:{
from:reportData.duration[0],
to:reportData.duration[1]
},
statsObject:{},
statArray:[{item:"ACTIVE",count:0},{item:"INACTIVE",count:0},{item:"REMOVED",count:0}]
};
}
onClickPieChart = (value) => {
console.log(value.data.point.item);
const chartValue = value.data.point.item;
let tempParamObj = this.state.paramsObject;
tempParamObj.status = chartValue;
this.setState({paramsObject:tempParamObj});
console.log(this.state.paramsObject)
constructor(props) {
super(props);
this.routes = props.routes;
const { reportData } = this.props.location;
this.state = {
selectedTags: ['Enrolled'],
paramsObject: {
from: reportData.duration[0],
to: reportData.duration[1],
},
statsObject: {},
statArray: [
{ item: 'ACTIVE', count: 0 },
{ item: 'INACTIVE', count: 0 },
{ item: 'REMOVED', count: 0 },
],
};
}
render() {
const { statArray } = this.state;
const { reportData } = this.props.location;
onClickPieChart = value => {
console.log(value.data.point.item);
const chartValue = value.data.point.item;
let tempParamObj = this.state.paramsObject;
const params = {...this.state.paramsObject};
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Report</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap" style={{marginBottom: '10px'}}>
<h3>Summary of enrollments</h3>
<div style={{marginBottom: '10px'}}>
<Select defaultValue="android" style={{ width: 120 , marginRight:10}}>
<Option value="android">Android</Option>
<Option value="ios">IOS</Option>
<Option value="windows">Windows</Option>
</Select>
<Button onClick={this.onSubmitReport} style={{marginLeft:10}} type="primary">Generate Report</Button>
</div>
</div>
tempParamObj.status = chartValue;
<div>
<Card
bordered={true}
hoverable={true}
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
this.setState({ paramsObject: tempParamObj });
console.log(this.state.paramsObject);
};
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData}/>
</Card>
</div>
render() {
const { reportData } = this.props.location;
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<ReportDeviceTable paramsObject={params}/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
const params = { ...this.state.paramsObject };
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Report</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap" style={{ marginBottom: '10px' }}>
<h3>Summary of enrollments</h3>
<div style={{ marginBottom: '10px' }}>
<Select
defaultValue="android"
style={{ width: 120, marginRight: 10 }}
>
<Option value="android">Android</Option>
<Option value="ios">IOS</Option>
<Option value="windows">Windows</Option>
</Select>
<Button
onClick={this.onSubmitReport}
style={{ marginLeft: 10 }}
type="primary"
>
Generate Report
</Button>
</div>
);
}
</div>
<div>
<Card
bordered={true}
hoverable={true}
style={{
borderRadius: 5,
marginBottom: 10,
height: window.innerHeight * 0.5,
}}
>
<PieChart
onClickPieChart={this.onClickPieChart}
reportData={reportData}
/>
</Card>
</div>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<ReportDeviceTable paramsObject={params} />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default withConfigContext(DeviceStatusReport);

View File

@ -16,118 +16,88 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon,
Tag,
Radio, Select, Button, Card,
Row, Col, message, notification
} from "antd";
import {Link} from "react-router-dom";
import PoliciesTable from "../../../components/Policies/PoliciesTable";
import DevicesTable from "../../../components/Devices/DevicesTable";
import DateRangePicker from "../../../components/Reports/DateRangePicker";
import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable";
import PieChart from "../../../components/Reports/Widgets/PieChart";
import axios from "axios";
import CountWidget from "../../../components/Reports/Widgets/CountWidget";
import {withConfigContext} from "../../../context/ConfigContext";
const {Paragraph} = Typography;
const { CheckableTag } = Tag;
const { Option } = Select;
let config = null;
import React from 'react';
import { PageHeader, Breadcrumb, Icon, Card } from 'antd';
import { Link } from 'react-router-dom';
import ReportDeviceTable from '../../../components/Devices/ReportDevicesTable';
import PieChart from '../../../components/Reports/Widgets/PieChart';
import { withConfigContext } from '../../../context/ConfigContext';
class EnrollmentTypeReport extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
config = this.props.context;
const { reportData } = this.props.location;
this.state = {
paramsObject:{
from:reportData.duration[0],
to:reportData.duration[1]
}
};
console.log(reportData.duration);
}
setParam = (tempParamObj, type, value) => {
if(type==="status"){
tempParamObj.status = value;
if(tempParamObj.status) {
delete tempParamObj.status;
}
} else if(type=="ownership"){
tempParamObj.ownership = value;
if(value=="ALL" && tempParamObj.ownership) {
delete tempParamObj.ownership;
}
}
constructor(props) {
super(props);
this.routes = props.routes;
const { reportData } = this.props.location;
this.state = {
paramsObject: {
from: reportData.duration[0],
to: reportData.duration[1],
},
};
onClickPieChart = (value) => {
const chartValue = value.data.point.item;
let tempParamObj = this.state.paramsObject;
console.log(reportData.duration);
}
console.log(chartValue)
onClickPieChart = value => {
const chartValue = value.data.point.item;
let tempParamObj = this.state.paramsObject;
tempParamObj.ownership = chartValue;
this.setState({paramsObject:tempParamObj});
};
console.log(chartValue);
render() {
const { reportData } = this.props.location;
tempParamObj.ownership = chartValue;
const params = {...this.state.paramsObject};
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Report</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap" style={{marginBottom: '10px'}}>
<h3>Summary of enrollments</h3>
this.setState({ paramsObject: tempParamObj });
};
</div>
render() {
const { reportData } = this.props.location;
<div>
<Card
bordered={true}
hoverable={true}
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
const params = { ...this.state.paramsObject };
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Report</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap" style={{ marginBottom: '10px' }}>
<h3>Summary of enrollments</h3>
</div>
<div>
<Card
bordered={true}
hoverable={true}
style={{
borderRadius: 5,
marginBottom: 10,
height: window.innerHeight * 0.5,
}}
>
<PieChart
onClickPieChart={this.onClickPieChart}
reportData={reportData}
/>
</Card>
</div>
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData}/>
</Card>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<ReportDeviceTable paramsObject={params}/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<ReportDeviceTable paramsObject={params} />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default withConfigContext(EnrollmentTypeReport);

View File

@ -16,157 +16,111 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon,
Tag,
Radio, Select, Button, Card,
Row, Col, message, notification
} from "antd";
import {Link, Redirect} from "react-router-dom";
import PoliciesTable from "../../../components/Policies/PoliciesTable";
import DevicesTable from "../../../components/Devices/DevicesTable";
import DateRangePicker from "../../../components/Reports/DateRangePicker";
import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable";
import PieChart from "../../../components/Reports/Widgets/PieChart";
import axios from "axios";
import CountWidget from "../../../components/Reports/Widgets/CountWidget";
import {withConfigContext} from "../../../context/ConfigContext";
const {Paragraph} = Typography;
const { CheckableTag } = Tag;
const { Option } = Select;
let config = null;
import React from 'react';
import { PageHeader, Breadcrumb, Icon, Card } from 'antd';
import { Link, Redirect } from 'react-router-dom';
import ReportDeviceTable from '../../../components/Devices/ReportDevicesTable';
import PieChart from '../../../components/Reports/Widgets/PieChart';
import { withConfigContext } from '../../../context/ConfigContext';
class EnrollmentsVsUnenrollmentsReport extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
config = this.props.context;
const { reportData } = this.props.location;
constructor(props) {
super(props);
this.routes = props.routes;
const { reportData } = this.props.location;
this.state = {
paramsObject:{
from:reportData? reportData.duration[0]: "2019-01-01",
to:reportData? reportData.duration[1]: "2019-01-01"
},
redirect: false
};
this.state = {
paramsObject: {
from: reportData ? reportData.duration[0] : '2019-01-01',
to: reportData ? reportData.duration[1] : '2019-01-01',
},
redirect: false,
};
this.redirectToHome();
console.log(this.state.paramsObject);
this.redirectToHome();
console.log(this.state.paramsObject);
}
redirectToHome = () => {
return <Redirect to="/entgra" />;
};
onClickPieChart = value => {
const chartValue = value.data.point.item;
let tempParamObj = this.state.paramsObject;
console.log(chartValue);
if (chartValue === 'Enrollments') {
tempParamObj.status = 'ACTIVE&status=INACTIVE';
} else {
tempParamObj.status = 'REMOVED';
}
setParam = (tempParamObj, type, value) => {
if(type==="status"){
tempParamObj.status = value;
if(tempParamObj.status) {
delete tempParamObj.status;
}
} else if(type=="ownership"){
tempParamObj.ownership = value;
if(value=="ALL" && tempParamObj.ownership) {
delete tempParamObj.ownership;
}
}
this.setState({ paramsObject: tempParamObj });
};
render() {
const { reportData } = this.props.location;
console.log('======');
console.log(reportData);
console.log('======');
let reportDataClone = {
params: ['ACTIVE'],
duration: ['2020-01-01', '2020-01-01'],
};
redirectToHome = () => {
return <Redirect to="/entgra" />
};
const params = { ...this.state.paramsObject };
return (
<div>
<div>
{!reportData ? (
<Redirect to="/entgra/reports" />
) : (
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Report</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap" style={{ marginBottom: '10px' }}>
<h3>Summary of enrollments</h3>
</div>
setRedirect = (reportData) => {
if(!reportData){
this.setState({
redirect: true
})
}
};
<div>
<Card
bordered={true}
hoverable={true}
style={{
borderRadius: 5,
marginBottom: 10,
height: window.innerHeight * 0.5,
}}
>
<PieChart
onClickPieChart={this.onClickPieChart}
reportData={reportData ? reportData : reportDataClone}
/>
</Card>
</div>
renderRedirect = () => {
if (this.state.redirect) {
return <Redirect to='/entgra' />
}
}
onClickPieChart = (value) => {
const chartValue = value.data.point.item;
let tempParamObj = this.state.paramsObject;
console.log(chartValue)
// tempParamObj.status = chartValue;
if(chartValue==="Enrollments"){
tempParamObj.status = "ACTIVE&status=INACTIVE"
}else{
tempParamObj.status = "REMOVED"
}
this.setState({paramsObject:tempParamObj});
};
render() {
const { reportData } = this.props.location;
console.log("======")
console.log(reportData)
console.log("======")
let reportDataClone = {
params: ["ACTIVE"],
duration: ["2020-01-01","2020-01-01"]
};
const params = {...this.state.paramsObject};
return (
<div>
<div>{!reportData ? (
<Redirect to='/entgra/reports' />
) : (
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Report</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap" style={{marginBottom: '10px'}}>
<h3>Summary of enrollments</h3>
</div>
<div>
<Card
bordered={true}
hoverable={true}
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData? reportData : reportDataClone}/>
</Card>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<ReportDeviceTable paramsObject={params}/>
</div>
</PageHeader>
)}</div>
</div>
);
}
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<ReportDeviceTable paramsObject={params} />
</div>
</PageHeader>
)}
</div>
</div>
);
}
}
export default withConfigContext(EnrollmentsVsUnenrollmentsReport);

View File

@ -1,63 +1,47 @@
import React from "react";
import React from 'react';
import {Card, Col, Icon} from "antd";
import {Link} from "react-router-dom";
import { Card, Col } from 'antd';
class CountWidget extends React.Component {
constructor(props) {
super(props);
this.routes = props.routes;
this.state = {
statArray: [],
};
}
constructor(props) {
super(props);
this.routes = props.routes;
this.state = {
statArray:[]
}
}
componentDidMount() {
this.setState({ statArray: this.props.statArray });
console.log('$$$$');
console.log(this.props.statArray);
}
componentDidMount() {
this.setState({statArray:this.props.statArray})
console.log("$$$$")
console.log(this.props.statArray)
}
render() {
const { statArray } = this.state;
let card = statArray.map(data => (
<Col key={data.item} span={6}>
<Card
key={data.item}
bordered={true}
hoverable={true}
style={{ borderRadius: 10, marginBottom: 16 }}
>
<div align="center">
<h2>
<b>{data.item}</b>
</h2>
<h1>{data.count}</h1>
{/* <p>{data.duration}</p>*/}
{/* <ReportFilterModal/>*/}
</div>
</Card>
</Col>
));
render() {
const countObj = [
{item:"All",count:100},
{item:"Enrolled",count:80},
{item:"Unenrolled",count:20}];
const { statArray } = this.state;
let card = statArray.map((data) =>
// <Card
// bordered={true}
// hoverable={true}
// key={data.item}
// style={{borderRadius: 5, marginBottom: 5, width:"100%"}}>
//
// <h3>{data.item} Devices: {data.count}</h3>
//
// </Card>
<Col key={data.item} span={6}>
<Card key={data.item} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
<div align='center'>
<h2><b>{data.item}</b></h2>
<h1>{data.count}</h1>
{/*<p>{data.duration}</p>*/}
{/*<ReportFilterModal/>*/}
</div>
</Card>
</Col>
)
return(
<div>
{card}
</div>
)
}
return <div>{card}</div>;
}
}
export default CountWidget;
export default CountWidget;

View File

@ -1,322 +1,342 @@
import React from "react";
import React from 'react';
import {
G2,
Chart,
Geom,
Axis,
Tooltip,
Coord,
Label,
Legend,
View,
Guide,
Shape,
Facet,
Util
} from "bizcharts";
import DataSet from "@antv/data-set";
import axios from "axios";
import {message, notification} from "antd";
import {withConfigContext} from "../../../context/ConfigContext";
Chart,
Geom,
Axis,
Tooltip,
Coord,
Label,
Legend,
Guide,
} from 'bizcharts';
import DataSet from '@antv/data-set';
import axios from 'axios';
import { message, notification } from 'antd';
import { withConfigContext } from '../../../context/ConfigContext';
let config = null;
class PieChart extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
this.state = {
loading: true,
statArray: [],
};
}
constructor(props) {
super(props);
config = this.props.context;
this.state = {
loading:true,
statArray:[]
};
componentDidMount() {
const { reportData } = this.props;
let params = {
status: reportData.params[0],
from: reportData.duration[0],
to: reportData.duration[1],
};
const urlSet = {
paramsList: reportData.params,
duration: reportData.duration,
};
console.log(urlSet);
if (reportData.params[0] === 'Enrollments') {
this.getEnrollmentsVsUnenrollmentsCount(params, urlSet);
} else if (reportData.params[0] === 'BYOD') {
this.getEnrollmentTypeCount(params, urlSet);
} else {
this.getCount(params, urlSet);
}
}
componentDidMount() {
let { statArray } = this.state;
const { reportData } = this.props;
let params = {
status: reportData.params[0],
from: reportData.duration[0],
to: reportData.duration[1]
};
clicked = () => {
console.log('Clicked...!!');
};
const urlSet = {
paramsList:reportData.params,
duration:reportData.duration
};
onChartChange = data => {
this.props.onClickPieChart(data);
};
console.log(urlSet)
statArray = [];
if(reportData.params[0]==="Enrollments"){
this.getEnrollmentsVsUnenrollmentsCount(params, urlSet)
}else if(reportData.params[0]==="BYOD"){
this.getEnrollmentTypeCount(params, urlSet);
}else{
this.getCount(params, urlSet);
// Call count APIs and get count for given parameters, then create data object to build pie chart
getCount = (params, urlSet) => {
this.setState({ loading: true });
let { statArray } = this.state;
console.log(urlSet);
const urlArray = [];
urlSet.paramsList.map(data => {
const paramsObj = {
status: data,
from: urlSet.duration[0],
to: urlSet.duration[1],
};
// console.log(paramsObj)
const encodedExtraParams = Object.keys(paramsObj)
.map(key => key + '=' + paramsObj[key])
.join('&');
const apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/reports/devices/count?' +
encodedExtraParams;
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray);
axios
.all(urlArray)
.then(res => {
res.map(response => {
if (response.status === 200) {
let countData = {
item: response.config[0],
// eslint-disable-next-line radix
count: parseInt(response.data.data),
};
statArray.push(countData);
}
});
this.setState({ statArray });
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popup with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to get device count.',
});
}
}
});
};
clicked = () => {
console.log("Clicked...!!")
// Call count APIs and get count for given parameters, then create data object to build pie chart
getEnrollmentsVsUnenrollmentsCount = (params, urlSet) => {
this.setState({ loading: true });
let { statArray } = this.state;
console.log(urlSet);
const urlArray = [];
urlSet.paramsList.map(data => {
const paramsObj = {
from: urlSet.duration[0],
to: urlSet.duration[1],
};
const encodedExtraParams = Object.keys(paramsObj)
.map(key => key + '=' + paramsObj[key])
.join('&');
let apiUrl;
if (data === 'Enrollments') {
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/reports/devices/count?status=ACTIVE&status=INACTIVE&' +
encodedExtraParams;
} else {
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/reports/devices/count?status=REMOVED&' +
encodedExtraParams;
}
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray);
axios
.all(urlArray)
.then(res => {
res.map(response => {
if (response.status === 200) {
let countData = {
item: response.config[0],
// eslint-disable-next-line radix
count: parseInt(response.data.data),
};
statArray.push(countData);
}
});
this.setState({ statArray });
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popup with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to get device count.',
});
}
});
};
// Call count APIs and get count for given parameters, then create data object to build pie chart
getEnrollmentTypeCount = (params, urlSet) => {
this.setState({ loading: true });
let { statArray } = this.state;
console.log(urlSet);
const urlArray = [];
urlSet.paramsList.map(data => {
const paramsObj = {
ownership: data,
from: urlSet.duration[0],
to: urlSet.duration[1],
};
const encodedExtraParams = Object.keys(paramsObj)
.map(key => key + '=' + paramsObj[key])
.join('&');
const apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/reports/devices/count?' +
encodedExtraParams;
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray);
axios
.all(urlArray)
.then(res => {
res.map(response => {
if (response.status === 200) {
let countData = {
item: response.config[0],
// eslint-disable-next-line radix
count: parseInt(response.data.data),
};
statArray.push(countData);
}
});
this.setState({ statArray });
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popup with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to get device count.',
});
}
});
};
render() {
const { DataView } = DataSet;
const { Html } = Guide;
const { statArray } = this.state;
const dv = new DataView();
dv.source(statArray).transform({
type: 'percent',
field: 'count',
dimension: 'item',
as: 'percent',
});
const cols = {
percent: {
formatter: val => {
val = val * 100 + '%';
return val;
},
},
};
onChartChange = (data) => {
this.props.onClickPieChart(data);
};
statArray = [];
//Call count APIs and get count for given parameters, then create data object to build pie chart
getCount = (params, urlSet) => {
this.setState({loading: true});
let { statArray } = this.state;
console.log(urlSet);
const urlArray = [];
urlSet.paramsList.map((data) => {
const paramsObj = {
status:data,
from:urlSet.duration[0],
to:urlSet.duration[1]
}
// console.log(paramsObj)
const encodedExtraParams = Object.keys(paramsObj)
.map(key => key + '=' + paramsObj[key]).join('&');
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices/count?" + encodedExtraParams;
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray)
axios.all(urlArray).then(res => {
res.map((response) => {
if(response.status === 200){
let countData = {item:response.config[0], count:parseInt(response.data.data)}
statArray.push(countData);
}
})
this.setState({statArray})
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popup with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to get device count.",
});
}
});
};
//Call count APIs and get count for given parameters, then create data object to build pie chart
getEnrollmentsVsUnenrollmentsCount = (params, urlSet) => {
this.setState({loading: true});
let { statArray } = this.state;
console.log(urlSet);
const urlArray = [];
urlSet.paramsList.map((data) => {
const paramsObj = {
from:urlSet.duration[0],
to:urlSet.duration[1]
}
const encodedExtraParams = Object.keys(paramsObj)
.map(key => key + '=' + paramsObj[key]).join('&');
let apiUrl;
if(data==="Enrollments"){
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices/count?status=ACTIVE&status=INACTIVE&" + encodedExtraParams;
}else{
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices/count?status=REMOVED&" + encodedExtraParams;
}
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray)
axios.all(urlArray).then(res => {
res.map((response) => {
if(response.status === 200){
let countData = {item:response.config[0], count:parseInt(response.data.data)}
statArray.push(countData);
}
})
this.setState({statArray})
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popup with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to get device count.",
});
}
});
};
//Call count APIs and get count for given parameters, then create data object to build pie chart
getEnrollmentTypeCount = (params, urlSet) => {
this.setState({loading: true});
let { statArray } = this.state;
console.log(urlSet);
const urlArray = [];
urlSet.paramsList.map((data) => {
const paramsObj = {
ownership:data,
from:urlSet.duration[0],
to:urlSet.duration[1]
}
const encodedExtraParams = Object.keys(paramsObj)
.map(key => key + '=' + paramsObj[key]).join('&');
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices/count?" + encodedExtraParams;
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray)
axios.all(urlArray).then(res => {
res.map((response) => {
if(response.status === 200){
let countData = {item:response.config[0], count:parseInt(response.data.data)}
statArray.push(countData);
}
})
this.setState({statArray})
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popup with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to get device count.",
});
}
});
};
render() {
const { DataView } = DataSet;
const { Html } = Guide;
const { statArray , loading} = this.state;
const dv = new DataView();
dv.source(statArray).transform({
type: "percent",
field: "count",
dimension: "item",
as: "percent"
});
const cols = {
percent: {
formatter: val => {
val = val * 100 + "%";
return val;
}
}
};
return (
<div>
<Chart
height={window.innerHeight/2}
data={dv}
scale={cols}
padding={[20, 25, 20, 20]}
forceFit
onPlotClick={this.onChartChange}
animate={true}
>
<Coord type={"theta"} radius={0.75} innerRadius={0.6} />
<Axis name="percent" />
<Legend
position="right"
offsetY={-window.innerHeight / 2 + 120}
offsetX={-100}
/>
<Tooltip
showTitle={false}
itemTpl="<li><span style=&quot;background-color:{color};&quot; class=&quot;g2-tooltip-marker&quot;></span>{name}: {value}</li>"
/>
<Guide>
<Html
position={["50%", "50%"]}
html="<div style=&quot;color:#8c8c8c;font-size:1.16em;text-align: center;width: 10em;&quot;>Total<br><span style=&quot;color:#262626;font-size:2.5em&quot;>200</span>台</div>"
alignX="middle"
alignY="middle"
/>
</Guide>
<div onClick={this.clicked}>
<Geom
type="intervalStack"
position="percent"
color="item"
tooltip={[
"item*percent",
(item, percent) => {
percent = percent * 100 + "%";
return {
name: item,
value: percent
};
}
]}
style={{
lineWidth: 1,
stroke: "#fff"
}}
>
<Label
content="percent"
formatter={(val, item) => {
return item.point.item + ": " + val;
}}/>
</Geom>
</div>
</Chart>
</div>
);
}
return (
<div>
<Chart
height={window.innerHeight / 2}
data={dv}
scale={cols}
padding={[20, 25, 20, 20]}
forceFit
onPlotClick={this.onChartChange}
animate={true}
>
<Coord type={'theta'} radius={0.75} innerRadius={0.6} />
<Axis name="percent" />
<Legend
position="right"
offsetY={-window.innerHeight / 2 + 120}
offsetX={-100}
/>
<Tooltip
showTitle={false}
itemTpl='<li><span style="background-color:{color};" class="g2-tooltip-marker"></span>{name}: {value}</li>'
/>
<Guide>
<Html
position={['50%', '50%']}
html='<div style="color:#8c8c8c;font-size:1.16em;text-align: center;width: 10em;">Total<br><span style="color:#262626;font-size:2.5em">200</span>台</div>'
alignX="middle"
alignY="middle"
/>
</Guide>
<div onClick={this.clicked}>
<Geom
type="intervalStack"
position="percent"
color="item"
tooltip={[
'item*percent',
(item, percent) => {
percent = percent * 100 + '%';
return {
name: item,
value: percent,
};
},
]}
style={{
lineWidth: 1,
stroke: '#fff',
}}
>
<Label
content="percent"
formatter={(val, item) => {
return item.point.item + ': ' + val;
}}
/>
</Geom>
</div>
</Chart>
</div>
);
}
}
export default withConfigContext(PieChart);
export default withConfigContext(PieChart);

View File

@ -1,340 +1,392 @@
import React from 'react';
import {Button, Form, Input, message, Modal, notification, Select, Tree} from "antd";
import {withConfigContext} from "../../context/ConfigContext";
import axios from "axios";
import {
Button,
Form,
Input,
message,
Modal,
notification,
Select,
Tree,
} from 'antd';
import { withConfigContext } from '../../context/ConfigContext';
import axios from 'axios';
const {Option} = Select;
const {TreeNode} = Tree;
const { Option } = Select;
const { TreeNode } = Tree;
class AddRole extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
this.expandKeys = [];
this.state = {
isAddRoleModalVisible: false,
isAddPermissionModalVisible: false,
roleName: '',
users: [],
nodeList: [],
expandedKeys: [],
autoExpandParent: true,
checkedKeys: [],
isNodeList: false,
};
}
constructor(props) {
super(props);
this.config = this.props.context;
this.expandKeys = [];
this.state = {
openAddModal = () => {
this.setState({
isAddRoleModalVisible: true,
});
};
onCancelHandler = e => {
this.setState({
isAddRoleModalVisible: false,
isAddPermissionModalVisible: false,
});
};
getCheckedPermissionsList = data => {
data.forEach(item => {
if (item !== null) {
this.expandKeys.push(item.resourcePath);
this.getCheckedPermissionsList(item.nodeList);
} else {
return null;
}
});
};
onAddRole = e => {
this.props.form.validateFields((err, values) => {
if (!err) {
this.onConfirmAddRole(values);
}
console.log(values);
});
};
onExpand = expandedKeys => {
this.setState({
expandedKeys,
autoExpandParent: false,
});
};
onCheck = checkedKeys => {
this.setState({ checkedKeys });
};
onConfirmAddRole = value => {
const roleData = {
roleName: value.roleName,
users: value.users,
};
this.setState({
roleName: value.roleName,
});
axios
.post(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles',
roleData,
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 201) {
this.props.fetchUsers();
this.setState({
isAddRoleModalVisible: false,
isAddPermissionModalVisible: false,
roleName: '',
users: [],
nodeList: [],
expandedKeys: [],
autoExpandParent: true,
checkedKeys: [],
isNodeList: false,
isAddPermissionModalVisible: true,
});
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully added the role.',
});
this.loadPermissionList();
}
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to add role.',
});
}
});
};
openAddModal = () => {
this.setState({
isAddRoleModalVisible: true
});
renderTreeNodes = data => {
return data.map(item => {
if (item !== null) {
if (item.hasOwnProperty('nodeList')) {
return (
<TreeNode
title={item.displayName}
key={item.resourcePath}
dataRef={item}
>
{this.renderTreeNodes(item.nodeList)}
</TreeNode>
);
}
return <TreeNode key={item.resourcePath} {...item} />;
}
// eslint-disable-next-line react/jsx-key
return <TreeNode />;
});
};
onAssignPermissions = () => {
const roleData = {
roleName: this.state.roleName,
permissions: this.state.checkedKeys,
};
onCancelHandler = e => {
this.setState({
isAddRoleModalVisible: false,
axios
.put(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles/' +
this.state.roleName,
roleData,
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully Updated the Permissions.',
});
this.setState({
isAddPermissionModalVisible: false,
});
};
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to add permissions.',
});
}
});
};
getCheckedPermissionsList = (data) =>{
data.forEach(item => {
if (item !== null) {
this.expandKeys.push(item.resourcePath);
this.getCheckedPermissionsList(item.nodeList);
}else{
return null;
}
});
};
loadPermissionList = () => {
let apiURL =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles/' +
this.state.roleName +
'/permissions';
onAddRole = e => {
this.props.form.validateFields((err, values) => {
if (!err) {
this.onConfirmAddRole(values);
}
console.log(values);
});
};
axios
.get(apiURL)
.then(res => {
if (res.status === 200) {
this.getCheckedPermissionsList(res.data.data.nodeList);
this.setState({
nodeList: res.data.data.nodeList,
isNodeList: true,
expandedKeys: this.expandKeys,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load permission.',
});
}
});
};
onExpand = expandedKeys => {
this.setState({
expandedKeys,
autoExpandParent: false,
});
};
loadUsersList = value => {
let apiURL =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/users/search/usernames?filter=' +
value +
'&domain=Primary';
axios
.get(apiURL)
.then(res => {
if (res.status === 200) {
let user = JSON.parse(res.data.data);
let users = [];
for (let i = 0; i < user.length; i++) {
users.push(
<Option key={user[i].username}>{user[i].username}</Option>,
);
}
this.setState({
users: users,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load users.',
});
}
});
};
onCheck = checkedKeys => {
this.setState({checkedKeys});
};
onConfirmAddRole = (value) => {
const roleData = {
roleName: value.roleName,
users: value.users,
};
this.setState({
roleName: value.roleName,
});
axios.post(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles",
roleData,
{headers: {'Content-Type': 'application-json'}}
).then(res => {
if (res.status === 201) {
this.props.fetchUsers();
this.setState({
isAddRoleModalVisible: false,
isAddPermissionModalVisible: true,
});
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully added the role.",
});
this.loadPermissionList();
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to add role.",
});
}
});
};
renderTreeNodes = (data) => {
return data.map(item => {
if (item !== null) {
if (item.hasOwnProperty("nodeList")) {
return (
<TreeNode title={item.displayName} key={item.resourcePath} dataRef={item}>
{this.renderTreeNodes(item.nodeList)}
</TreeNode>
);
}
return <TreeNode key={item.resourcePath} {...item}/>;
}
else{
return <TreeNode/>;
}
});
};
onAssignPermissions = () =>{
const roleData = {
roleName : this.state.roleName,
permissions : this.state.checkedKeys
};
axios.put(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ this.state.roleName,
roleData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully Updated the Permissions.",
});
this.setState({
isAddPermissionModalVisible : false
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to add permissions.",
});
}
});
};
loadPermissionList = () => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/roles/" + this.state.roleName + "/permissions";
axios.get(apiURL).then(res => {
if (res.status === 200) {
this.getCheckedPermissionsList(res.data.data.nodeList);
this.setState({
nodeList: res.data.data.nodeList,
isNodeList: true,
expandedKeys : this.expandKeys
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description: "Error occurred while trying to load permission.",
});
}
})
};
loadUsersList = (value) => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/users/search/usernames?filter=" + value + "&domain=Primary";
axios.get(apiURL).then(res => {
if (res.status === 200) {
let user = JSON.parse(res.data.data);
let users = [];
for (let i = 0; i < user.length; i++) {
users.push(<Option key={user[i].username}>{user[i].username}</Option>);
}
this.setState({
users: users
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description: "Error occurred while trying to load users.",
});
}
})
};
render() {
const {getFieldDecorator} = this.props.form;
return (
<div>
<div>
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal}
style={{marginBottom: '10px'}}>
Add Role
</Button>
</div>
<div>
<Modal
title="ADD NEW ROLE"
width="40%"
visible={this.state.isAddRoleModalVisible}
onOk={this.onAddRole}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onAddRole}>
Add Role
</Button>,
]}>
<div style={{alignItems: "center"}}>
<p>Create new user on IoT Server.</p>
<Form
labelCol={{span: 5}}
wrapperCol={{span: 18}}>
<Form.Item label="User Store Domain" style={{display: "block"}}>
{getFieldDecorator('userStoreDomain', {
initialValue: 'PRIMARY'
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>
)}
</Form.Item>
<Form.Item label="Role Name" style={{display: "block"}}>
{getFieldDecorator('roleName', {
rules: [
{
pattern: new RegExp("^(((?!(\\@|\\/|\\s)).){3,})*$"),
message: 'Role name should be in minimum 3 characters long and not ' +
'include any whitespaces or @ or /',
},
{
required: true,
message: 'This field is required.',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="User List" style={{display: "block"}}>
{getFieldDecorator('users', {})(<Select
mode="multiple"
style={{width: '100%'}}
onSearch={this.loadUsersList}>
{this.state.users}
</Select>)}
</Form.Item>
</Form>
</div>
</Modal>
</div>
<div>
<Modal
title="CHANGE ROLE PERMISSION"
width="40%"
visible={this.state.isAddPermissionModalVisible}
onOk={this.onAssignPermissions}
onCancel={this.onCancelHandler}
bodyStyle={{overflowY:"scroll", maxHeight:'500px', marginLeft:'10px'}}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onAssignPermissions}>
Assign
</Button>,
]}>
<div style={{alignItems: "center"}}>
<div>
{(this.state.isNodeList) && (
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
onCheck={this.onCheck}
checkedKeys={this.state.checkedKeys}>
{this.renderTreeNodes(this.state.nodeList)}
</Tree>
)}
</div>
</div>
</Modal>
</div>
render() {
const { getFieldDecorator } = this.props.form;
return (
<div>
<div>
<Button
type="primary"
icon="plus"
size={'default'}
onClick={this.openAddModal}
style={{ marginBottom: '10px' }}
>
Add Role
</Button>
</div>
<div>
<Modal
title="ADD NEW ROLE"
width="40%"
visible={this.state.isAddRoleModalVisible}
onOk={this.onAddRole}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onAddRole}>
Add Role
</Button>,
]}
>
<div style={{ alignItems: 'center' }}>
<p>Create new user on IoT Server.</p>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item
label="User Store Domain"
style={{ display: 'block' }}
>
{getFieldDecorator('userStoreDomain', {
initialValue: 'PRIMARY',
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>,
)}
</Form.Item>
<Form.Item label="Role Name" style={{ display: 'block' }}>
{getFieldDecorator('roleName', {
rules: [
{
pattern: new RegExp('^(((?!(\\@|\\/|\\s)).){3,})*$'),
message:
'Role name should be in minimum 3 characters long and not ' +
'include any whitespaces or @ or /',
},
{
required: true,
message: 'This field is required.',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="User List" style={{ display: 'block' }}>
{getFieldDecorator('users', {})(
<Select
mode="multiple"
style={{ width: '100%' }}
onSearch={this.loadUsersList}
>
{this.state.users}
</Select>,
)}
</Form.Item>
</Form>
</div>
);
}
</Modal>
</div>
<div>
<Modal
title="CHANGE ROLE PERMISSION"
width="40%"
visible={this.state.isAddPermissionModalVisible}
onOk={this.onAssignPermissions}
onCancel={this.onCancelHandler}
bodyStyle={{
overflowY: 'scroll',
maxHeight: '500px',
marginLeft: '10px',
}}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button
key="submit"
type="primary"
onClick={this.onAssignPermissions}
>
Assign
</Button>,
]}
>
<div style={{ alignItems: 'center' }}>
<div>
{this.state.isNodeList && (
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
onCheck={this.onCheck}
checkedKeys={this.state.checkedKeys}
>
{this.renderTreeNodes(this.state.nodeList)}
</Tree>
)}
</div>
</div>
</Modal>
</div>
</div>
);
}
}
export default withConfigContext(Form.create({name: 'add-role'})(AddRole))
export default withConfigContext(Form.create({ name: 'add-role' })(AddRole));

View File

@ -1,428 +1,489 @@
import React from 'react';
import {
Button,
Divider,
Form,
Icon,
Input,
message,
Modal,
notification,
Popconfirm,
Select,
Tooltip, Tree,
Typography
} from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
Button,
Divider,
Form,
Icon,
Input,
message,
Modal,
notification,
Popconfirm,
Select,
Tooltip,
Tree,
Typography,
} from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
const { Option } = Select;
const {Text} = Typography;
const { Text } = Typography;
const { TreeNode } = Tree;
class RoleAction extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
this.selected = [];
this.expandKeys = [];
this.state = {
roleData: [],
nodeList : [],
isNodeList: false,
users : [],
constructor(props) {
super(props);
this.config = this.props.context;
this.selected = [];
this.expandKeys = [];
this.state = {
roleData: [],
nodeList: [],
isNodeList: false,
users: [],
isEditRoleModalVisible: false,
isEditPermissionModalVisible: false,
expandedKeys: [],
autoExpandParent: true,
checkedKeys: [],
};
}
openEditRoleModal = () => {
let apiUrl =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles/' +
this.props.data;
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
this.setState({
roleData: res.data.data,
isEditRoleModalVisible: true,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load role.',
});
}
});
};
openEditPermissionModal = () => {
this.loadPermissionList();
this.setState({
isEditPermissionModalVisible: true,
});
};
loadPermissionList = () => {
let apiURL =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles/' +
this.props.data +
'/permissions';
axios
.get(apiURL)
.then(res => {
if (res.status === 200) {
this.getCheckedPermissions(res.data.data.nodeList);
this.setState({
nodeList: res.data.data.nodeList,
isNodeList: true,
checkedKeys: this.selected,
expandedKeys: this.expandKeys,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load permission.',
});
}
});
};
getCheckedPermissions = data => {
data.forEach(item => {
if (item !== null) {
this.expandKeys.push(item.resourcePath);
if (item.isSelected) {
this.selected.push(item.resourcePath);
}
this.getCheckedPermissions(item.nodeList);
} else {
return null;
}
});
};
onExpand = expandedKeys => {
this.setState({
expandedKeys,
autoExpandParent: false,
});
};
onCheck = checkedKeys => {
this.setState({ checkedKeys });
};
renderTreeNodes = data => {
return data.map(item => {
if (item !== null) {
if (item.hasOwnProperty('nodeList')) {
return (
<TreeNode
title={item.displayName}
key={item.resourcePath}
dataRef={item}
>
{this.renderTreeNodes(item.nodeList)}
</TreeNode>
);
}
return <TreeNode key={item.resourcePath} {...item} />;
}
// eslint-disable-next-line react/jsx-key
return <TreeNode />;
});
};
onUpdateRole = e => {
this.props.form.validateFields((err, values) => {
if (!err) {
this.onConfirmUpdateRole(values);
}
console.log(values);
});
};
onCancelHandler = e => {
this.setState({
isEditRoleModalVisible: false,
isEditPermissionModalVisible: false,
});
};
onConfirmUpdateRole = value => {
const roleData = {
roleName: value.roleName,
users: value.users,
};
axios
.put(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles/' +
this.props.data,
roleData,
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isEditRoleModalVisible: false,
});
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully Updated the role.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to add role.',
});
}
});
};
onAssignPermission = () => {
const roleData = {
roleName: this.props.data,
permissions: this.state.checkedKeys,
};
axios
.put(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles/' +
this.props.data,
roleData,
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully Updated the Permissions.',
});
this.setState({
isEditPermissionModalVisible: false,
expandedKeys: [],
autoExpandParent: true,
checkedKeys: [],
};
}
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to add permissions.',
});
}
});
};
openEditRoleModal = () =>{
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ this.props.data;
loadUsersList = value => {
let apiURL =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/users/search/usernames?filter=' +
value +
'&domain=Primary';
axios
.get(apiURL)
.then(res => {
if (res.status === 200) {
let user = JSON.parse(res.data.data);
let users = [];
for (let i = 0; i < user.length; i++) {
users.push(
<Option key={user[i].username}>{user[i].username}</Option>,
);
}
this.setState({
users: users,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load users.',
});
}
});
};
axios.get(apiUrl).then(res => {
if (res.status === 200) {
this.setState({
roleData : res.data.data,
isEditRoleModalVisible: true,
});
}
onDeleteRole = () => {
axios
.delete(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles/' +
this.props.data,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully deleted the Role.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to delete role.',
});
}
});
};
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load role.",
});
}
});
};
render() {
const isAdminRole = this.props.data === 'admin';
const { getFieldDecorator } = this.props.form;
return (
<div>
<div style={{ display: isAdminRole ? 'none' : 'inline' }}>
<Tooltip placement="top" title={'Edit Role'}>
<a>
<Icon type="edit" onClick={this.openEditRoleModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="top" title={'Edit Permissions'}>
<a>
<Icon type="file-add" onClick={this.openEditPermissionModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={'Remove Role'}>
<Popconfirm
placement="top"
title={'Are you sure?'}
onConfirm={this.onDeleteRole}
okText="Ok"
cancelText="Cancel"
>
<a>
<Text type="danger">
<Icon type="delete" />
</Text>
</a>
</Popconfirm>
</Tooltip>
</div>
openEditPermissionModal =()=>{
this.loadPermissionList();
this.setState({
isEditPermissionModalVisible: true,
});
};
loadPermissionList = () => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/roles/"+this.props.data+"/permissions";
axios.get(apiURL).then(res => {
if (res.status === 200) {
this.getCheckedPermissions(res.data.data.nodeList);
this.setState({
nodeList : res.data.data.nodeList,
isNodeList: true,
checkedKeys : this.selected,
expandedKeys : this.expandKeys
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load permission.",
});
}
})
};
getCheckedPermissions = (data) =>{
data.forEach(item => {
if (item !== null) {
this.expandKeys.push(item.resourcePath);
if (item.isSelected) {
this.selected.push(item.resourcePath);
}
this.getCheckedPermissions(item.nodeList);
}else{
return null;
}
});
};
onExpand = expandedKeys => {
this.setState({
expandedKeys,
autoExpandParent: false,
});
};
onCheck = checkedKeys => {
this.setState({checkedKeys});
};
renderTreeNodes = (data) => {
return data.map(item => {
if (item !== null) {
if (item.hasOwnProperty("nodeList")) {
return (
<TreeNode title={item.displayName} key={item.resourcePath} dataRef={item}>
{this.renderTreeNodes(item.nodeList)}
</TreeNode>
);
}
return <TreeNode key={item.resourcePath} {...item}/>;
} else{
return <TreeNode/>;
}
});
};
onUpdateRole = e => {
this.props.form.validateFields((err, values) => {
if (!err) {
this.onConfirmUpdateRole(values);
}
console.log(values);
});
};
onCancelHandler = e =>{
this.setState({
isEditRoleModalVisible: false,
isEditPermissionModalVisible:false,
})
};
onConfirmUpdateRole = (value) =>{
const roleData = {
roleName : value.roleName,
users : value.users,
};
axios.put(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ this.props.data,
roleData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isEditRoleModalVisible: false,
});
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully Updated the role.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to add role.",
});
}
});
};
onAssignPermission = () =>{
const roleData = {
roleName : this.props.data,
permissions : this.state.checkedKeys
};
axios.put(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ this.props.data,
roleData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully Updated the Permissions.",
});
this.setState({
isEditPermissionModalVisible : false
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to add permissions.",
});
}
});
};
loadUsersList = (value) => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/users/search/usernames?filter="+value+"&domain=Primary";
axios.get(apiURL).then(res => {
if (res.status === 200) {
let user = JSON.parse(res.data.data);
let users = [];
for(let i=0; i<user.length; i++){
users.push(<Option key={user[i].username}>{user[i].username}</Option>);
}
this.setState({
users : users
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load users.",
});
}
})
};
onDeleteRole = () => {
axios.delete(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/" + this.props.data,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully deleted the Role.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to delete role.",
});
}
});
};
render() {
const isAdminRole = this.props.data ==="admin";
const { getFieldDecorator } = this.props.form;
return (
<div>
<div style={{display:isAdminRole ? "none" : "inline"}}>
<Tooltip placement="top" title={"Edit Role"}>
<a><Icon type="edit" onClick={this.openEditRoleModal}/></a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="top" title={"Edit Permissions"}>
<a><Icon type="file-add" onClick={this.openEditPermissionModal}/></a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={"Remove Role"}>
<Popconfirm
placement="top"
title={"Are you sure?"}
onConfirm={this.onDeleteRole}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
</Popconfirm>
</Tooltip>
</div>
<div>
<Modal
title="EDIT ROLE"
width="40%"
visible={this.state.isEditRoleModalVisible}
onOk={this.onUpdateRole}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onUpdateRole}>
Add Role
</Button>,
]}>
<div style={{alignItems:"center"}}>
<p>Create new user on IoT Server.</p>
<Form
labelCol={{ span: 5 }}
wrapperCol={{ span: 18 }}>
<Form.Item label="User Store Domain" style={{display:"block"}}>
{getFieldDecorator('userStoreDomain', {
initialValue : 'PRIMARY'
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>
)}
</Form.Item>
<Form.Item label="Role Name" style={{display:"block"}}>
{getFieldDecorator('roleName', {
initialValue: this.state.roleData.roleName,
rules: [
{
pattern : new RegExp("^(((?!(\\@|\\/|\\s)).){3,})*$"),
message: 'Role name should be in minimum 3 characters long and not ' +
'include any whitespaces or @ or /',
},
{
required: true,
message: 'This field is required.',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="User List" style={{display:"block"}}>
{getFieldDecorator('users', {
initialValue: this.state.roleData.users,
})(<Select
mode="multiple"
style={{ width: '100%' }}
onSearch={this.loadUsersList}>
{this.state.users}
</Select>)}
</Form.Item>
</Form>
</div>
</Modal>
</div>
<div>
<Modal
title="CHANGE ROLE PERMISSION"
width="40%"
visible={this.state.isEditPermissionModalVisible}
onOk={this.onAssignPermission}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onAssignPermission}>
Assign
</Button>,
]}
bodyStyle={{overflowY:"scroll", maxHeight:'500px', marginLeft:'10px'}}>
<div>
{(this.state.isNodeList) &&(
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
onCheck={this.onCheck}
checkedKeys={this.state.checkedKeys}>
{this.renderTreeNodes(this.state.nodeList)}
</Tree>
)}
</div>
</Modal>
</div>
<div>
<Modal
title="EDIT ROLE"
width="40%"
visible={this.state.isEditRoleModalVisible}
onOk={this.onUpdateRole}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onUpdateRole}>
Add Role
</Button>,
]}
>
<div style={{ alignItems: 'center' }}>
<p>Create new user on IoT Server.</p>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item
label="User Store Domain"
style={{ display: 'block' }}
>
{getFieldDecorator('userStoreDomain', {
initialValue: 'PRIMARY',
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>,
)}
</Form.Item>
<Form.Item label="Role Name" style={{ display: 'block' }}>
{getFieldDecorator('roleName', {
initialValue: this.state.roleData.roleName,
rules: [
{
pattern: new RegExp('^(((?!(\\@|\\/|\\s)).){3,})*$'),
message:
'Role name should be in minimum 3 characters long and not ' +
'include any whitespaces or @ or /',
},
{
required: true,
message: 'This field is required.',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="User List" style={{ display: 'block' }}>
{getFieldDecorator('users', {
initialValue: this.state.roleData.users,
})(
<Select
mode="multiple"
style={{ width: '100%' }}
onSearch={this.loadUsersList}
>
{this.state.users}
</Select>,
)}
</Form.Item>
</Form>
</div>
);
}
</Modal>
</div>
<div>
<Modal
title="CHANGE ROLE PERMISSION"
width="40%"
visible={this.state.isEditPermissionModalVisible}
onOk={this.onAssignPermission}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button
key="submit"
type="primary"
onClick={this.onAssignPermission}
>
Assign
</Button>,
]}
bodyStyle={{
overflowY: 'scroll',
maxHeight: '500px',
marginLeft: '10px',
}}
>
<div>
{this.state.isNodeList && (
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
onCheck={this.onCheck}
checkedKeys={this.state.checkedKeys}
>
{this.renderTreeNodes(this.state.nodeList)}
</Tree>
)}
</div>
</Modal>
</div>
</div>
);
}
}
export default withConfigContext(Form.create({name: 'role-actions'})(RoleAction));
export default withConfigContext(
Form.create({ name: 'role-actions' })(RoleAction),
);

View File

@ -16,243 +16,251 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {
Button,
message,
Modal,
notification,
Table, List
} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { Button, message, Modal, notification, Table, List } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
import AddRole from "./AddRole";
import RoleAction from "./RoleAction";
import Filter from "../Utils/Filter/Filter";
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
import AddRole from './AddRole';
import RoleAction from './RoleAction';
import Filter from '../Utils/Filter/Filter';
const searchFields = [
{
name: 'filter',
placeholder: 'Name'
}
{
name: 'filter',
placeholder: 'Name',
},
];
class RolesTable extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
userData: [],
users : [],
isEditRoleModalVisible: false,
isUserListModalVisible :false,
};
}
constructor(props) {
super(props);
this.config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
userData: [],
users: [],
isEditRoleModalVisible: false,
isUserListModalVisible: false,
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows,
});
},
};
componentDidMount() {
this.fetchUsers();
}
openUserListModal = event => {
let apiUrl =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles/' +
event;
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
this.setState({
userData: res.data.data.users,
isUserListModalVisible: true,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load users.',
});
}
});
};
handleOk = e => {
this.setState({
isUserListModalVisible: false,
});
};
handleCancel = e => {
this.setState({
isUserListModalVisible: false,
});
};
// fetch data from api
fetchUsers = (params = {}, filters = {}) => {
// const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
...filters,
};
componentDidMount() {
this.fetchUsers();
}
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key])
.join('&');
openUserListModal = (event) => {
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ event;
let apiUrl =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles?' +
encodedExtraParams;
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
this.setState({
userData : res.data.data.users,
isUserListModalVisible: true,
});
}
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
data: res.data.data.roles,
pagination,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load users.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load users.",
});
}
});
};
this.setState({ loading: false });
});
};
handleOk = e => {
this.setState({
isUserListModalVisible: false,
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
handleCancel = e => {
this.setState({
isUserListModalVisible: false,
});
};
//fetch data from api
fetchUsers = (params = {}, filters={}) => {
// const config = this.props.context;
this.setState({loading: true});
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
...filters
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles?" + encodedExtraParams;
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data.roles,
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load users.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const columns = [
{
title: 'Role Name',
dataIndex: '',
key: "role",
width: "60%",
},
{
title: 'View',
dataIndex: '',
key: 'users',
render: (id, row) =>
<Button
type="primary"
size={"small"}
icon="book"
onClick={()=>this.openUserListModal(row)}>Users</Button>
},
{
title: 'Action',
dataIndex: 'id',
key: 'action',
render: (id, row) => (
<span>
<RoleAction data={row} fetchUsers={this.fetchUsers}/>
</span>
),
},
];
return (
render() {
const { data, pagination, loading } = this.state;
const columns = [
{
title: 'Role Name',
dataIndex: '',
key: 'role',
width: '60%',
},
{
title: 'View',
dataIndex: '',
key: 'users',
render: (id, row) => (
<Button
type="primary"
size={'small'}
icon="book"
onClick={() => this.openUserListModal(row)}
>
Users
</Button>
),
},
{
title: 'Action',
dataIndex: 'id',
key: 'action',
render: (id, row) => (
<span>
<RoleAction data={row} fetchUsers={this.fetchUsers} />
</span>
),
},
];
return (
<div>
<div style={{ background: '#f0f2f5' }}>
<AddRole fetchUsers={this.fetchUsers} />
</div>
<div style={{ textAlign: 'right' }}>
<Filter fields={searchFields} callback={this.fetchUsers} />
</div>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<Table
columns={columns}
rowKey={record => record}
dataSource={data}
pagination={{
...pagination,
size: 'small',
// position: "top",
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} groups`,
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
<div>
<Modal
title="USERS"
width="900px"
visible={this.state.isUserListModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<div>
<div style={{background: '#f0f2f5'}}>
<AddRole fetchUsers={this.fetchUsers}/>
</div>
<div style={{textAlign: 'right'}}>
<Filter fields={searchFields} callback={this.fetchUsers}/>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<Table
columns={columns}
rowKey={record => (record)}
dataSource={data}
pagination={{
...pagination,
size: "small",
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
<div>
<Modal
title="USERS"
width="900px"
visible={this.state.isUserListModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel} >
<div>
<List
size="small"
bordered
dataSource={this.state.userData}
renderItem={item => <List.Item>{item}</List.Item>}/>
</div>
</Modal>
</div>
<List
size="small"
bordered
dataSource={this.state.userData}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</div>
);
}
</Modal>
</div>
</div>
);
}
}
export default withConfigContext(RolesTable);

View File

@ -17,21 +17,28 @@
*/
import React from 'react';
import {Route} from 'react-router-dom';
class RouteWithSubRoutes extends React.Component{
props;
constructor(props){
super(props);
this.props = props;
}
render() {
return(
<Route path={this.props.path} exact={this.props.exact} render={(props) => (
<this.props.component {...props} {...this.props} routes={this.props.routes}/>
)}/>
);
}
import { Route } from 'react-router-dom';
class RouteWithSubRoutes extends React.Component {
props;
constructor(props) {
super(props);
this.props = props;
}
render() {
return (
<Route
path={this.props.path}
exact={this.props.exact}
render={props => (
<this.props.component
{...props}
{...this.props}
routes={this.props.routes}
/>
)}
/>
);
}
}
export default RouteWithSubRoutes;
export default RouteWithSubRoutes;

View File

@ -1,215 +1,245 @@
import React from 'react';
import {Button, Form, Select, Input, message, Modal, notification, Typography} from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
import {
Button,
Form,
Select,
Input,
message,
Modal,
notification,
} from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
const { Option } = Select;
const {Text} = Typography;
class AddUser extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
this.state = {
isModalVisible: false,
roles: [],
};
}
constructor(props) {
super(props);
this.config = this.props.context;
this.state = {
componentDidMount() {
this.getRole();
}
openAddModal = () => {
this.setState({
isModalVisible: true,
});
};
onSubmitHandler = e => {
this.props.form.validateFields((err, values) => {
if (!err) {
this.onConfirmAddUser(values);
}
});
};
onConfirmAddUser = value => {
const userData = {
username: value.userStoreDomain + '/' + value.userName,
firstname: value.firstName,
lastname: value.lastName,
emailAddress: value.email,
roles: value.userRoles,
};
axios
.post(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/users',
userData,
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 201) {
this.props.fetchUsers();
this.setState({
isModalVisible: false,
roles : []
});
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully added the user.',
});
}
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to add user.',
});
}
});
};
componentDidMount() {
this.getRole();
}
onCancelHandler = e => {
this.setState({
isModalVisible: false,
});
};
openAddModal = () => {
this.setState({
isModalVisible:true
});
};
getRole = () => {
let apiURL =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles?user-store=PRIMARY&limit=100';
onSubmitHandler = e => {
this.props.form.validateFields((err, values) => {
if (!err) {
this.onConfirmAddUser(values);
}
});
};
axios
.get(apiURL)
.then(res => {
if (res.status === 200) {
const roles = [];
for (let i = 0; i < res.data.data.roles.length; i++) {
roles.push(
<Option key={res.data.data.roles[i]}>
{res.data.data.roles[i]}
</Option>,
);
}
this.setState({
roles: roles,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
onConfirmAddUser = (value) =>{
const userData = {
username : value.userStoreDomain +"/"+value.userName,
firstname : value.firstName,
lastname : value.lastName,
emailAddress : value.email,
roles : value.userRoles
};
axios.post(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/users",
userData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
if (res.status === 201) {
this.props.fetchUsers();
this.setState({
isModalVisible: false,
});
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully added the user.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to add user.",
});
}
});
};
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load roles.',
});
}
});
};
onCancelHandler = e => {
this.setState({
isModalVisible: false,
});
};
getRole = () => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/roles?user-store=PRIMARY&limit=100";
axios.get(apiURL).then(res => {
if (res.status === 200) {
const roles = [];
for(let i=0; i<res.data.data.roles.length ; i++){
roles.push(<Option key={res.data.data.roles[i]}>{res.data.data.roles[i]}</Option>);
}
this.setState({
roles : roles
})
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load roles.",
});
}
})
};
render() {
const { getFieldDecorator } = this.props.form;
return (
<div>
<div>
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal} style={{marginBottom : '10px'}}>
Add User
</Button>
</div>
<div>
<Modal
title="ADD NEW USER"
width="40%"
visible={this.state.isModalVisible}
onOk={this.onSubmitHandler}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onSubmitHandler}>
Submit
</Button>,
]}>
<div style={{alignItems:"center"}}>
<p>Create new user on IoT Server.</p>
<Form
labelCol={{ span: 5 }}
wrapperCol={{ span: 18 }}>
<Form.Item label="User Store Domain" style={{display:"block"}}>
{getFieldDecorator('userStoreDomain', {
initialValue : 'PRIMARY'
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>
)}
</Form.Item>
<Form.Item label="User Name" style={{display:"block"}}>
{getFieldDecorator('userName', {
rules: [
{
required: true,
message: 'This field is required. Username should be at least 3 characters long with no white spaces.',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="First Name" style={{display:"block"}}>
{getFieldDecorator('firstName', {
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="Last Name" style={{display:"block"}}>
{getFieldDecorator('lastName', {
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="Email Address" style={{display:"block"}}>
{getFieldDecorator('email', {
rules: [
{
type: 'email',
message: 'Invalid Email Address',
},
{
required: true,
message: 'This field is required',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="User Roles" style={{display:"block"}}>
{getFieldDecorator('userRoles', {
})(<Select
mode="multiple"
style={{ width: '100%' }}>
{this.state.roles}
</Select>)}
</Form.Item>
</Form>
</div>
</Modal>
</div>
render() {
const { getFieldDecorator } = this.props.form;
return (
<div>
<div>
<Button
type="primary"
icon="plus"
size={'default'}
onClick={this.openAddModal}
style={{ marginBottom: '10px' }}
>
Add User
</Button>
</div>
<div>
<Modal
title="ADD NEW USER"
width="40%"
visible={this.state.isModalVisible}
onOk={this.onSubmitHandler}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button
key="submit"
type="primary"
onClick={this.onSubmitHandler}
>
Submit
</Button>,
]}
>
<div style={{ alignItems: 'center' }}>
<p>Create new user on IoT Server.</p>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item
label="User Store Domain"
style={{ display: 'block' }}
>
{getFieldDecorator('userStoreDomain', {
initialValue: 'PRIMARY',
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>,
)}
</Form.Item>
<Form.Item label="User Name" style={{ display: 'block' }}>
{getFieldDecorator('userName', {
rules: [
{
required: true,
message:
'This field is required. Username should be at least 3 characters long with no white spaces.',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="First Name" style={{ display: 'block' }}>
{getFieldDecorator('firstName', {
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="Last Name" style={{ display: 'block' }}>
{getFieldDecorator('lastName', {
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="Email Address" style={{ display: 'block' }}>
{getFieldDecorator('email', {
rules: [
{
type: 'email',
message: 'Invalid Email Address',
},
{
required: true,
message: 'This field is required',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="User Roles" style={{ display: 'block' }}>
{getFieldDecorator('userRoles', {})(
<Select mode="multiple" style={{ width: '100%' }}>
{this.state.roles}
</Select>,
)}
</Form.Item>
</Form>
</div>
);
}
</Modal>
</div>
</div>
);
}
}
export default withConfigContext(Form.create({name: 'add-user'})(AddUser))
export default withConfigContext(Form.create({ name: 'add-user' })(AddUser));

View File

@ -1,423 +1,472 @@
import React from 'react';
import {
Button,
Divider,
Form,
Icon,
Input,
message,
Modal,
notification,
Popconfirm,
Select,
Tooltip,
Typography } from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
Button,
Divider,
Form,
Icon,
Input,
message,
Modal,
notification,
Popconfirm,
Select,
Tooltip,
Typography,
} from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
const { Option } = Select;
const {Text} = Typography;
const { Text } = Typography;
class UserActions extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
this.state = {
isEditModalVisible: false,
isResetPasswordModalVisible: false,
rolesData: [],
}
constructor(props) {
super(props);
this.config = this.props.context;
this.state = {
isEditModalVisible: false,
isResetPasswordModalVisible: false,
rolesData: [],
};
}
openEditModal = () => {
this.setState({
isEditModalVisible: true,
});
this.fetchRoles(this.props.data.username);
};
openPasswordResetModal = () => {
this.setState({
isResetPasswordModalVisible: true,
});
};
onCancelHandler = () => {
this.setState({
isEditModalVisible: false,
isResetPasswordModalVisible: false,
});
};
compareToFirstPassword = (rule, value, callback) => {
if (value && value !== this.props.form.getFieldValue('password')) {
callback("New password doesn't match the confirmation.");
} else {
callback();
}
openEditModal = () =>{
this.setState({
isEditModalVisible: true,
});
this.fetchRoles(this.props.data.username);
};
};
openPasswordResetModal = () =>{
this.setState({
isResetPasswordModalVisible: true,
})
};
onSavePassword = () => {
this.props.form.validateFields(
['password', 'confirmPassword'],
(err, values) => {
if (!err) {
this.onResetPassword(values);
}
},
);
};
onCancelHandler = () =>{
this.setState({
isEditModalVisible: false,
onResetPassword = value => {
const password = {
newPassword: value.password,
};
axios
.post(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/admin/users/' +
this.props.data.username +
'/credentials',
password,
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isResetPasswordModalVisible: false,
})
};
compareToFirstPassword = (rule, value, callback) => {
if (value && value !== this.props.form.getFieldValue('password')) {
callback('New password doesn\'t match the confirmation.');
});
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully reset the password',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
callback();
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to reset password.',
});
}
});
};
componentDidMount() {
this.getRole();
}
getRole = () => {
let apiURL =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/roles?user-store=PRIMARY&limit=100';
axios
.get(apiURL)
.then(res => {
if (res.status === 200) {
const roles = [];
for (let i = 0; i < res.data.data.roles.length; i++) {
roles.push(
<Option key={res.data.data.roles[i]}>
{res.data.data.roles[i]}
</Option>,
);
}
this.setState({
roles: roles,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load roles.',
});
}
});
};
onConfirmDeleteUser = () => {
axios
.delete(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/users/' +
this.props.data.username,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully deleted the user.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to delete user.',
});
}
});
};
fetchRoles = username => {
let apiUrl =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/users/' +
username +
'/roles';
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
this.setState({
rolesData: res.data.data.roles,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load roles.',
});
}
});
};
handleEditOk = e => {
this.props.form.validateFields(
[
'userStoreDomain',
'userName',
'firstName',
'lastName',
'email',
'userRoles',
],
(err, values) => {
if (!err) {
this.onUpdateUser(values);
}
},
);
};
onUpdateUser = value => {
const userData = {
username: value.userStoreDomain + '/' + value.userName,
firstname: value.firstName,
lastname: value.lastName,
emailAddress: value.email,
roles: value.userRoles,
};
axios
.put(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
'/users/' +
this.props.data.username,
userData,
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isEditModalVisible: false,
});
notification.success({
message: 'Done',
duration: 4,
description: 'Successfully updated the user.',
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to update user.',
});
}
});
};
onSavePassword = () => {
this.props.form.validateFields((['password', 'confirmPassword']),(err, values) => {
if (!err) {
this.onResetPassword(values);
}
});
};
render() {
const isAdminUser = this.props.data.username === 'admin';
const { getFieldDecorator } = this.props.form;
return (
<div>
<div style={{ display: isAdminUser ? 'none' : 'inline' }}>
<Tooltip placement="top" title={'Edit User'}>
<a>
<Icon type="edit" onClick={this.openEditModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="top" title={'Reset Password'}>
<a>
<Icon type="key" onClick={this.openPasswordResetModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={'Remove User'}>
<Popconfirm
placement="top"
title={'Are you sure?'}
onConfirm={this.onConfirmDeleteUser}
okText="Ok"
cancelText="Cancel"
>
<a>
<Text type="danger">
<Icon type="delete" />
</Text>
</a>
</Popconfirm>
</Tooltip>
</div>
onResetPassword = (value) =>{
const password = {
newPassword : value.password,
};
axios.post(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/admin/users/"+this.props.data.username+"/credentials",
password,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isResetPasswordModalVisible: false,
});
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully reset the password",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to reset password.",
});
}
});
};
componentDidMount() {
this.getRole();
}
getRole = () => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/roles?user-store=PRIMARY&limit=100";
axios.get(apiURL).then(res => {
if (res.status === 200) {
const roles = [];
for(let i=0; i<res.data.data.roles.length ; i++){
roles.push(<Option key={res.data.data.roles[i]}>{res.data.data.roles[i]}</Option>);
}
this.setState({
roles : roles
})
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load roles.",
});
}
})
};
onConfirmDeleteUser = () => {
axios.delete(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/users/" + this.props.data.username,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully deleted the user.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to delete user.",
});
}
});
};
fetchRoles = (username) => {
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/users/" + username + "/roles";
axios.get(apiUrl).then(res => {
if (res.status === 200) {
this.setState({
rolesData: res.data.data.roles,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load roles.",
});
}
});
};
handleEditOk = e =>{
this.props.form.validateFields((['userStoreDomain', 'userName', 'firstName', 'lastName' , 'email', 'userRoles']),(err, values) => {
if (!err) {
this.onUpdateUser(values);
}
});
};
onUpdateUser = (value) =>{
const userData = {
username : value.userStoreDomain +"/"+value.userName,
firstname : value.firstName,
lastname : value.lastName,
emailAddress : value.email,
roles : value.userRoles
};
axios.put(
window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/users/"+ this.props.data.username,
userData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isEditModalVisible: false,
});
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully updated the user.",
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to update user.",
});
}
});
};
render() {
const isAdminUser = this.props.data.username ==="admin";
const { getFieldDecorator } = this.props.form;
return (
<div>
<div style={{display:isAdminUser ? "none" : "inline"}}>
<Tooltip placement="top" title={"Edit User"}>
<a><Icon type="edit" onClick={this.openEditModal}/></a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="top" title={"Reset Password"}>
<a><Icon type="key" onClick={this.openPasswordResetModal}/></a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={"Remove User"}>
<Popconfirm
placement="top"
title={"Are you sure?"}
onConfirm={this.onConfirmDeleteUser}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
</Popconfirm>
</Tooltip>
</div>
<div>
<Modal
title="Reset Password"
width="40%"
visible={this.state.isResetPasswordModalVisible}
onCancel={this.onCancelHandler}
onOk={this.onSavePassword}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onSavePassword} >
Save
</Button>,
]}>
<div style={{alignItems:"center"}}>
<Form
labelCol={{ span: 6 }}
wrapperCol={{ span: 17 }}>
<Form.Item label="New Password" style={{display:"block"}}>
{getFieldDecorator(
'password',
{
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input.Password/>)}
</Form.Item>
<Form.Item label="Retype New Password" style={{display:"block"}}>
{getFieldDecorator(
'confirmPassword',
{
rules: [
{
required: true,
message: 'This field is required',
},
{
validator: this.compareToFirstPassword,
},
],
})(<Input.Password/>)}
</Form.Item>
</Form>
</div>
</Modal>
</div>
<div>
<Modal
title="EDIT USER"
width="40%"
visible={this.state.isEditModalVisible}
onOk={this.handleEditOk}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.handleEditOk}>
Update
</Button>,
]}>
<div style={{alignItems:"center"}}>
<p>Create new user on IoT Server.</p>
<Form
labelCol={{ span: 5 }}
wrapperCol={{ span: 18 }}>
<Form.Item label="User Store Domain" style={{display:"block"}}>
{getFieldDecorator('userStoreDomain', {
initialValue : 'PRIMARY'
})(
<Select disabled={true}>
<Option key="PRIMARY">PRIMARY</Option>
</Select>
)}
</Form.Item>
<Form.Item label="User Name" style={{display:"block"}}>
{getFieldDecorator('userName', {
initialValue: this.props.data.username,
rules: [
{
required: true,
message: 'This field is required. Username should be at least 3 characters long with no white spaces.',
},
],
})(<Input disabled={true}/>)}
</Form.Item>
<Form.Item label="First Name" style={{display:"block"}}>
{getFieldDecorator('firstName', {
initialValue: this.props.data.firstname,
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="Last Name" style={{display:"block"}}>
{getFieldDecorator('lastName', {
initialValue: this.props.data.lastname,
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="Email Address" style={{display:"block"}}>
{getFieldDecorator('email', {
initialValue: this.props.data.emailAddress,
rules: [
{
type: 'email',
message: 'Invalid Email Address',
},
{
required: true,
message: 'This field is required',
},
],
})(<Input/>)}
</Form.Item>
<Form.Item label="User Roles" style={{display:"block"}}>
{getFieldDecorator('userRoles', {
initialValue: this.state.rolesData,
})(<Select
mode="multiple"
style={{ width: '100%' }}>
{this.state.roles}
</Select>)}
</Form.Item>
</Form>
</div>
</Modal>
</div>
<div>
<Modal
title="Reset Password"
width="40%"
visible={this.state.isResetPasswordModalVisible}
onCancel={this.onCancelHandler}
onOk={this.onSavePassword}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onSavePassword}>
Save
</Button>,
]}
>
<div style={{ alignItems: 'center' }}>
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 17 }}>
<Form.Item label="New Password" style={{ display: 'block' }}>
{getFieldDecorator('password', {
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input.Password />)}
</Form.Item>
<Form.Item
label="Retype New Password"
style={{ display: 'block' }}
>
{getFieldDecorator('confirmPassword', {
rules: [
{
required: true,
message: 'This field is required',
},
{
validator: this.compareToFirstPassword,
},
],
})(<Input.Password />)}
</Form.Item>
</Form>
</div>
);
}
</Modal>
</div>
<div>
<Modal
title="EDIT USER"
width="40%"
visible={this.state.isEditModalVisible}
onOk={this.handleEditOk}
onCancel={this.onCancelHandler}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.handleEditOk}>
Update
</Button>,
]}
>
<div style={{ alignItems: 'center' }}>
<p>Create new user on IoT Server.</p>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item
label="User Store Domain"
style={{ display: 'block' }}
>
{getFieldDecorator('userStoreDomain', {
initialValue: 'PRIMARY',
})(
<Select disabled={true}>
<Option key="PRIMARY">PRIMARY</Option>
</Select>,
)}
</Form.Item>
<Form.Item label="User Name" style={{ display: 'block' }}>
{getFieldDecorator('userName', {
initialValue: this.props.data.username,
rules: [
{
required: true,
message:
'This field is required. Username should be at least 3 characters long with no white spaces.',
},
],
})(<Input disabled={true} />)}
</Form.Item>
<Form.Item label="First Name" style={{ display: 'block' }}>
{getFieldDecorator('firstName', {
initialValue: this.props.data.firstname,
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="Last Name" style={{ display: 'block' }}>
{getFieldDecorator('lastName', {
initialValue: this.props.data.lastname,
rules: [
{
required: true,
message: 'This field is required',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="Email Address" style={{ display: 'block' }}>
{getFieldDecorator('email', {
initialValue: this.props.data.emailAddress,
rules: [
{
type: 'email',
message: 'Invalid Email Address',
},
{
required: true,
message: 'This field is required',
},
],
})(<Input />)}
</Form.Item>
<Form.Item label="User Roles" style={{ display: 'block' }}>
{getFieldDecorator('userRoles', {
initialValue: this.state.rolesData,
})(
<Select mode="multiple" style={{ width: '100%' }}>
{this.state.roles}
</Select>,
)}
</Form.Item>
</Form>
</div>
</Modal>
</div>
</div>
);
}
}
export default withConfigContext(Form.create({name: 'user-actions'})(UserActions));
export default withConfigContext(
Form.create({ name: 'user-actions' })(UserActions),
);

View File

@ -16,233 +16,245 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {Icon, message, notification, Table, Tag, Tooltip, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { Icon, message, notification, Table, Tag, Tooltip } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
const {Text} = Typography;
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
let config = null;
let apiUrl;
const columns = [
{
title: 'Device',
dataIndex: 'name',
width: 100,
},
{
title: 'Type',
dataIndex: 'type',
key: 'type',
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
let color = defaultPlatformIcons.default.color;
let theme = defaultPlatformIcons.default.theme;
{
title: 'Device',
dataIndex: 'name',
width: 100,
},
{
title: 'Type',
dataIndex: 'type',
key: 'type',
// eslint-disable-next-line react/display-name
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
let color = defaultPlatformIcons.default.color;
let theme = defaultPlatformIcons.default.theme;
if (defaultPlatformIcons.hasOwnProperty(type)) {
icon = defaultPlatformIcons[type].icon;
color = defaultPlatformIcons[type].color;
theme = defaultPlatformIcons[type].theme;
}
if (defaultPlatformIcons.hasOwnProperty(type)) {
icon = defaultPlatformIcons[type].icon;
color = defaultPlatformIcons[type].color;
theme = defaultPlatformIcons[type].theme;
}
return (
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
<Icon type={icon} theme={theme}/>
</span>
);
}
// todo add filtering options
return (
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
<Icon type={icon} theme={theme} />
</span>
);
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner
// todo add filtering options
// todo add filtering options
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner,
// todo add filtering options
},
{
title: 'Ownership',
dataIndex: 'enrolmentInfo',
key: 'ownership',
width: 100,
render: enrolmentInfo => enrolmentInfo.ownership,
// todo add filtering options
},
{
title: 'Status',
dataIndex: 'enrolmentInfo',
width: 100,
key: 'status',
// eslint-disable-next-line react/display-name
render: enrolmentInfo => {
const status = enrolmentInfo.status.toLowerCase();
let color = '#f9ca24';
switch (status) {
case 'active':
color = '#badc58';
break;
case 'created':
color = '#6ab04c';
break;
case 'removed':
color = '#ff7979';
break;
case 'inactive':
color = '#f9ca24';
break;
case 'blocked':
color = '#636e72';
break;
}
return <Tag color={color}>{status}</Tag>;
},
{
title: 'Ownership',
dataIndex: 'enrolmentInfo',
key: 'ownership',
width: 100,
render: enrolmentInfo => enrolmentInfo.ownership
// todo add filtering options
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
// eslint-disable-next-line react/display-name
render: data => {
const { dateOfLastUpdate } = data;
const timeAgoString = getTimeAgo(dateOfLastUpdate);
return (
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
{timeAgoString}
</Tooltip>
);
},
{
title: 'Status',
dataIndex: 'enrolmentInfo',
width: 100,
key: 'status',
render: (enrolmentInfo) => {
const status = enrolmentInfo.status.toLowerCase();
let color = "#f9ca24";
switch (status) {
case "active":
color = "#badc58";
break;
case "created":
color = "#6ab04c";
break;
case "removed":
color = "#ff7979";
break;
case "inactive":
color = "#f9ca24";
break;
case "blocked":
color = "#636e72";
break;
}
return <Tag color={color}>{status}</Tag>;
}
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
render: (data) => {
const {dateOfLastUpdate} = data;
const timeAgoString = getTimeAgo(dateOfLastUpdate);
return <Tooltip title={new Date(dateOfLastUpdate).toString()}>{timeAgoString}</Tooltip>;
}
// todo add filtering options
}
// todo add filtering options
},
];
const getTimeAgo = (time) => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
const getTimeAgo = time => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
};
class UsersDevices extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows,
});
},
};
componentDidMount() {
this.fetch();
}
// Rerender component when parameters change
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevProps.user !== this.props.user) {
this.fetch();
}
}
// fetch data from api
fetch = (params = {}) => {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
user: this.props.user,
requireDeviceInfo: true,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key])
.join('&');
// send request to the invoker
axios
.get(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/devices?' +
encodedExtraParams,
)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: []
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
data: res.data.data.devices,
pagination,
});
}
};
componentDidMount() {
this.fetch();
}
//Rerender component when parameters change
componentDidUpdate(prevProps, prevState, snapshot) {
if(prevProps.user !== this.props.user){
this.fetch();
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load devices.',
});
}
}
//fetch data from api
fetch = (params = {}) => {
const config = this.props.context;
this.setState({loading: true});
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
this.setState({ loading: false });
});
};
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
user: this.props.user,
requireDeviceInfo: true,
};
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
//send request to the invoker
axios.get(
window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/devices?" + encodedExtraParams,
).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data.devices,
pagination
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to load devices.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
dataSource={data}
showHeader={false}
size="small"
pagination={{
...pagination,
size: "small",
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
);
}
render() {
const { data, pagination, loading } = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record =>
record.deviceIdentifier +
record.enrolmentInfo.owner +
record.enrolmentInfo.ownership
}
dataSource={data}
showHeader={false}
size="small"
pagination={{
...pagination,
size: 'small',
// position: "top",
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} devices`,
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
);
}
}
export default withConfigContext(UsersDevices);
export default withConfigContext(UsersDevices);

View File

@ -16,305 +16,322 @@
* under the License.
*/
import React from "react";
import axios from "axios";
import {Button, Collapse, Icon, List, message, Modal, notification, Table, Tabs, Typography} from "antd";
import TimeAgo from 'javascript-time-ago'
import React from 'react';
import axios from 'axios';
import { Button, List, message, Modal, notification, Table } from 'antd';
import TimeAgo from 'javascript-time-ago';
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
import {withConfigContext} from "../../context/ConfigContext";
import UsersDevices from "./UsersDevices";
import AddUser from "./AddUser";
import UserActions from "./UserActions";
import Filter from "../Utils/Filter/Filter";
import en from 'javascript-time-ago/locale/en';
import { withConfigContext } from '../../context/ConfigContext';
import UsersDevices from './UsersDevices';
import AddUser from './AddUser';
import UserActions from './UserActions';
import Filter from '../Utils/Filter/Filter';
const ButtonGroup = Button.Group;
const {Text} = Typography;
let config = null;
let apiUrl;
const searchFields = [
{
name: 'username',
placeholder: 'Username'
},
{
name: 'firstName',
placeholder: 'First Name'
},
{
name: 'lastName',
placeholder: 'Last Name'
},
{
name: 'emailAddress',
placeholder: 'Email Address'
},
{
name: 'username',
placeholder: 'Username',
},
{
name: 'firstName',
placeholder: 'First Name',
},
{
name: 'lastName',
placeholder: 'Last Name',
},
{
name: 'emailAddress',
placeholder: 'Email Address',
},
];
class UsersTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
constructor(props) {
super(props);
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
rolesModalVisible: false,
devicesModalVisible: false,
rolesData: [],
user: '',
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows,
});
},
};
componentDidMount() {
this.fetchUsers();
}
// fetch data from api
fetchUsers = (params = {}, filters = {}) => {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
...filters,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key])
.join('&');
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/users/search?' +
encodedExtraParams;
// send request to the invokerss
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
selectedRows: [],
rolesModalVisible: false,
devicesModalVisible: false,
rolesData: [],
user:''
};
}
data: res.data.data.users,
pagination,
});
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
console.log(res.data.data);
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load users.',
});
}
};
componentDidMount() {
this.fetchUsers();
}
this.setState({ loading: false });
});
};
//fetch data from api
fetchUsers = (params = {}, filters = {}) => {
const config = this.props.context;
this.setState({loading: true});
fetchRoles = username => {
const config = this.props.context;
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
this.setState({
rolesModalVisible: true,
user: username,
});
const extraParams = {
offset: 10 * (currentPage - 1), //calculate the offset
limit: 10,
...filters
};
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
'/users/' +
username +
'/roles';
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
this.setState({
rolesData: res.data.data.roles,
});
}
})
.catch(error => {
if (error.hasOwnProperty('response') && error.response.status === 401) {
// todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to load roles.',
});
}
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/users/search?" + encodedExtraParams;
this.setState({ loading: false });
});
};
//send request to the invokerss
axios.get(apiUrl).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data.users,
pagination,
});
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
console.log(res.data.data)
}
handleOk = e => {
this.setState({
rolesModalVisible: false,
devicesModalVisible: false,
});
};
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load users.",
});
}
handleCancel = e => {
this.setState({
rolesModalVisible: false,
devicesModalVisible: false,
});
};
this.setState({loading: false});
});
};
openDeviceListModal = e => {
this.setState({
devicesModalVisible: true,
});
};
fetchRoles = (username) => {
const config = this.props.context;
this.setState({
rolesModalVisible: true,
user: username
});
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/users/" + username + "/roles";
axios.get(apiUrl).then(res => {
if (res.status === 200) {
this.setState({
rolesData: res.data.data.roles,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
message.error('You are not logged in');
window.location.href = window.location.origin + '/entgra/login';
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:"Error occurred while trying to load roles.",
});
}
this.setState({loading: false});
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
pagination: pager,
});
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
};
handleOk = e => {
this.setState({
rolesModalVisible: false,
devicesModalVisible: false
});
};
handleCancel = e => {
this.setState({
rolesModalVisible: false,
devicesModalVisible: false
});
};
openDeviceListModal = e =>{
this.setState({
devicesModalVisible: true,
})
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { Panel } = Collapse;
const { TabPane } = Tabs;
const columns = [
{
title: 'User Name',
dataIndex: 'username',
key: "username",
},
{
title: 'First Name',
dataIndex: 'firstname',
key: 'firstname',
},
{
title: 'Last Name',
dataIndex: 'lastname',
key: 'lastname',
},
{
title: 'Email',
dataIndex: 'emailAddress',
key: 'emailAddress',
},
{
title: 'View',
dataIndex: 'username',
key: 'roles',
render: (username) =>
<ButtonGroup>
<Button
type="primary"
size={"small"}
icon="book"
onClick={() => this.fetchRoles(username)}>Roles</Button>
<Button
type="primary"
size={"small"}
icon="desktop"
onClick={this.openDeviceListModal}>Devices</Button>
</ButtonGroup>
},
{
title: 'Action',
dataIndex: 'id',
key: 'action',
render: (id, row) => (
<span>
<UserActions data={row} fetchUsers={this.fetchUsers}/>
</span>
),
},
];
return (
render() {
const { data, pagination, loading } = this.state;
const columns = [
{
title: 'User Name',
dataIndex: 'username',
key: 'username',
},
{
title: 'First Name',
dataIndex: 'firstname',
key: 'firstname',
},
{
title: 'Last Name',
dataIndex: 'lastname',
key: 'lastname',
},
{
title: 'Email',
dataIndex: 'emailAddress',
key: 'emailAddress',
},
{
title: 'View',
dataIndex: 'username',
key: 'roles',
render: username => (
<ButtonGroup>
<Button
type="primary"
size={'small'}
icon="book"
onClick={() => this.fetchRoles(username)}
>
Roles
</Button>
<Button
type="primary"
size={'small'}
icon="desktop"
onClick={this.openDeviceListModal}
>
Devices
</Button>
</ButtonGroup>
),
},
{
title: 'Action',
dataIndex: 'id',
key: 'action',
render: (id, row) => (
<span>
<UserActions data={row} fetchUsers={this.fetchUsers} />
</span>
),
},
];
return (
<div>
<div style={{ background: '#f0f2f5' }}>
<AddUser fetchUsers={this.fetchUsers} />
</div>
<div style={{ textAlign: 'right' }}>
<Filter fields={searchFields} callback={this.fetchUsers} />
</div>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<Table
columns={columns}
rowKey={record => record.username}
dataSource={data}
pagination={{
...pagination,
size: 'small',
// position: "top",
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} groups`,
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
<div>
<Modal
title="ROLES"
width="900px"
visible={this.state.rolesModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<div>
<div style={{background: '#f0f2f5'}}>
<AddUser fetchUsers={this.fetchUsers}/>
</div>
<div style={{textAlign: 'right'}}>
<Filter fields={searchFields} callback={this.fetchUsers}/>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<Table
columns={columns}
rowKey={record => (record.username)}
dataSource={data}
pagination={{
...pagination,
size: "small",
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
rowSelection={this.rowSelection}
/>
</div>
<div>
<Modal
title="ROLES"
width="900px"
visible={this.state.rolesModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel} >
<div>
<List
size="small"
bordered
dataSource={this.state.rolesData}
renderItem={item => <List.Item>{item}</List.Item>}/>
</div>
</Modal>
</div>
<div>
<Modal
title="DEVICES"
width="900px"
visible={this.state.devicesModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel}>
<div>
<UsersDevices user={this.state.user}/>
</div>
</Modal>
</div>
<List
size="small"
bordered
dataSource={this.state.rolesData}
renderItem={item => <List.Item>{item}</List.Item>}
/>
</div>
);
}
</Modal>
</div>
<div>
<Modal
title="DEVICES"
width="900px"
visible={this.state.devicesModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<div>
<UsersDevices user={this.state.user} />
</div>
</Modal>
</div>
</div>
);
}
}
export default withConfigContext(UsersTable);

View File

@ -1,41 +1,38 @@
import React from "react";
import React from 'react';
import {Form, Icon, Input, Button} from 'antd';
const hasErrors = (fieldsError) => {
return Object.keys(fieldsError).some(field => fieldsError[field]);
};
import { Form, Input, Button } from 'antd';
class HorizontalLoginForm extends React.Component {
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
Object.keys(values).forEach(key => values[key] === undefined && delete values[key]);
this.props.callback({},values);
}
});
};
render() {
const {getFieldDecorator} = this.props.form;
return (
<Form layout="inline" onSubmit={this.handleSubmit}>
{this.props.fields.map((field) => (
<Form.Item key={field.name}>
{getFieldDecorator(field.name)(
<Input placeholder={field.placeholder}/>,
)}
</Form.Item>
))}
<Form.Item>
<Button htmlType='submit' shape="circle" icon="search" />
</Form.Item>
</Form>
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
Object.keys(values).forEach(
key => values[key] === undefined && delete values[key],
);
}
this.props.callback({}, values);
}
});
};
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form layout="inline" onSubmit={this.handleSubmit}>
{this.props.fields.map(field => (
<Form.Item key={field.name}>
{getFieldDecorator(field.name)(
<Input placeholder={field.placeholder} />,
)}
</Form.Item>
))}
<Form.Item>
<Button htmlType="submit" shape="circle" icon="search" />
</Form.Item>
</Form>
);
}
}
export default Form.create({name: 'horizontal_login'})(HorizontalLoginForm);
export default Form.create({ name: 'horizontal_login' })(HorizontalLoginForm);

View File

@ -16,19 +16,19 @@
* under the License.
*/
import React from "react";
import React from 'react';
const ConfigContext = React.createContext();
export const withConfigContext = Component => {
return props => (
<ConfigContext.Consumer>
{context => {
return <Component {...props} context={context}/>;
}}
</ConfigContext.Consumer>
);
// eslint-disable-next-line react/display-name
return props => (
<ConfigContext.Consumer>
{context => {
return <Component {...props} context={context} />;
}}
</ConfigContext.Consumer>
);
};
export default ConfigContext;

View File

@ -19,119 +19,117 @@
import React from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import App from "./App";
import Login from "./pages/Login";
import Dashboard from "./pages/Dashboard/Dashboard";
import App from './App';
import Login from './pages/Login';
import Dashboard from './pages/Dashboard/Dashboard';
import './index.css';
import Devices from "./pages/Dashboard/Devices/Devices";
import Reports from "./pages/Dashboard/Reports/Reports";
import Geo from "./pages/Dashboard/Geo/Geo";
import Groups from "./pages/Dashboard/Groups/Groups";
import Users from "./pages/Dashboard/Users/Users";
import Policies from "./pages/Dashboard/Policies/Policies";
import Roles from "./pages/Dashboard/Roles/Roles";
import DeviceTypes from "./pages/Dashboard/DeviceTypes/DeviceTypes";
import DeviceEnroll from "./pages/Dashboard/Devices/DeviceEnroll";
import AddNewPolicy from "./pages/Dashboard/Policies/AddNewPolicy";
import Certificates from "./pages/Dashboard/Configurations/Certificates/Certificates";
import ReportDurationItemList from "./pages/Dashboard/Reports/ReportDurationItemList";
import EnrollmentsVsUnenrollmentsReport from "./components/Reports/Templates/EnrollmentsVsUnenrollmentsReport";
import EnrollmentTypeReport from "./components/Reports/Templates/EnrollmentTypeReport";
import Devices from './pages/Dashboard/Devices/Devices';
import Reports from './pages/Dashboard/Reports/Reports';
import Geo from './pages/Dashboard/Geo/Geo';
import Groups from './pages/Dashboard/Groups/Groups';
import Users from './pages/Dashboard/Users/Users';
import Policies from './pages/Dashboard/Policies/Policies';
import Roles from './pages/Dashboard/Roles/Roles';
import DeviceTypes from './pages/Dashboard/DeviceTypes/DeviceTypes';
import DeviceEnroll from './pages/Dashboard/Devices/DeviceEnroll';
import AddNewPolicy from './pages/Dashboard/Policies/AddNewPolicy';
import Certificates from './pages/Dashboard/Configurations/Certificates/Certificates';
import ReportDurationItemList from './pages/Dashboard/Reports/ReportDurationItemList';
import EnrollmentsVsUnenrollmentsReport from './components/Reports/Templates/EnrollmentsVsUnenrollmentsReport';
import EnrollmentTypeReport from './components/Reports/Templates/EnrollmentTypeReport';
import DeviceStatusReport from './components/Reports/Templates/DeviceStatusReport';
const routes = [
{
path: '/entgra/login',
{
path: '/entgra/login',
exact: true,
component: Login,
},
{
path: '/entgra',
exact: false,
component: Dashboard,
routes: [
{
path: '/entgra/devices',
component: Devices,
exact: true,
component: Login
},
{
path: '/entgra',
exact: false,
component: Dashboard,
routes: [
{
path: '/entgra/devices',
component: Devices,
exact: true
},
{
path: '/entgra/devices/enroll',
component: DeviceEnroll,
exact: true
},
{
path: '/entgra/geo',
component: Geo,
exact: true
},
{
path: '/entgra/reports',
component: Reports,
exact: true
},
{
path: '/entgra/groups',
component: Groups,
exact: true
},
{
path: '/entgra/users',
component: Users,
exact: true
},
{
path: '/entgra/policies',
component: Policies,
exact: true
},
{
path: '/entgra/policy/add',
component: AddNewPolicy,
exact: true
},
{
path: '/entgra/roles',
component: Roles,
exact: true
},
{
path: '/entgra/devicetypes',
component: DeviceTypes,
exact: true
},
{
path: '/entgra/certificates',
component: Certificates,
exact: true
},
{
path: '/entgra/reportList',
component: ReportDurationItemList,
exact: true
},
{
path: '/entgra/enrollmentsvsunenrollments',
component: EnrollmentsVsUnenrollmentsReport,
exact: true
},
{
path: '/entgra/enrollmenttype',
component: EnrollmentTypeReport,
exact: true
},
{
path: '/entgra/devicestatus',
component: DeviceStatusReport,
exact: true
}
]
}
},
{
path: '/entgra/devices/enroll',
component: DeviceEnroll,
exact: true,
},
{
path: '/entgra/geo',
component: Geo,
exact: true,
},
{
path: '/entgra/reports',
component: Reports,
exact: true,
},
{
path: '/entgra/groups',
component: Groups,
exact: true,
},
{
path: '/entgra/users',
component: Users,
exact: true,
},
{
path: '/entgra/policies',
component: Policies,
exact: true,
},
{
path: '/entgra/policy/add',
component: AddNewPolicy,
exact: true,
},
{
path: '/entgra/roles',
component: Roles,
exact: true,
},
{
path: '/entgra/devicetypes',
component: DeviceTypes,
exact: true,
},
{
path: '/entgra/certificates',
component: Certificates,
exact: true,
},
{
path: '/entgra/reportList',
component: ReportDurationItemList,
exact: true,
},
{
path: '/entgra/enrollmentsvsunenrollments',
component: EnrollmentsVsUnenrollmentsReport,
exact: true,
},
{
path: '/entgra/enrollmenttype',
component: EnrollmentTypeReport,
exact: true,
},
{
path: '/entgra/devicestatus',
component: DeviceStatusReport,
exact: true,
},
],
},
];
ReactDOM.render(
<App routes={routes}/>,
document.getElementById('root'));
ReactDOM.render(<App routes={routes} />, document.getElementById('root'));
// If you want your app e and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.

View File

@ -16,52 +16,48 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon,
} from "antd";
import {Link} from "react-router-dom";
import DeviceTable from "../../../../components/Devices/DevicesTable";
import CertificateTable from "../../../../components/Configurations/Certificates/CertificateTable";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import CertificateTable from '../../../../components/Configurations/Certificates/CertificateTable';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class Certificates extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Configurations</Breadcrumb.Item>
<Breadcrumb.Item>Certificates</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Certificates</h3>
<Paragraph>Certificate configurations</Paragraph>
</div>
<div style={{backgroundColor: "#ffffff", borderRadius: 5}}>
<CertificateTable/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra/devices">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Configurations</Breadcrumb.Item>
<Breadcrumb.Item>Certificates</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Certificates</h3>
<Paragraph>Certificate configurations</Paragraph>
</div>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<CertificateTable />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default Certificates;

View File

@ -16,193 +16,197 @@
* under the License.
*/
import React from "react";
import {Layout, Menu, Icon} from 'antd';
import {Switch, Link} from "react-router-dom";
import RouteWithSubRoutes from "../../components/RouteWithSubRoutes"
import {Redirect} from 'react-router'
import "./Dashboard.css";
import {withConfigContext} from "../../context/ConfigContext";
import Logout from "./Logout/Logout";
import React from 'react';
import { Layout, Menu, Icon } from 'antd';
import { Switch, Link } from 'react-router-dom';
import RouteWithSubRoutes from '../../components/RouteWithSubRoutes';
import { Redirect } from 'react-router';
import './Dashboard.css';
import { withConfigContext } from '../../context/ConfigContext';
import Logout from './Logout/Logout';
const {Header, Content, Footer, Sider} = Layout;
const {SubMenu} = Menu;
const { Header, Content, Footer } = Layout;
const { SubMenu } = Menu;
class Dashboard extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
const mobileWidth = (window.innerWidth<=768 ? '0' : '80');
const mobileWidth = window.innerWidth <= 768 ? '0' : '80';
this.state = {
routes: props.routes,
selectedKeys: [],
deviceTypes: [],
isNavBarCollapsed: false,
mobileWidth
};
this.logo = this.props.context.theme.logo;
this.config = this.props.context;
}
toggle = () => {
console.log(this.config)
this.setState({
isNavBarCollapsed: !this.state.isNavBarCollapsed,
});
this.state = {
routes: props.routes,
selectedKeys: [],
deviceTypes: [],
isNavBarCollapsed: false,
mobileWidth,
};
this.logo = this.props.context.theme.logo;
this.config = this.props.context;
}
render() {
return (
<div>
<Layout className="layout" >
<Layout>
<Header style={{background: '#fff', padding: 0}}>
<div className="logo-image">
<Link to="/entgra/devices"><img alt="logo" src={this.logo}/></Link>
</div>
toggle = () => {
console.log(this.config);
this.setState({
isNavBarCollapsed: !this.state.isNavBarCollapsed,
});
};
<Menu
theme="light"
mode="horizontal"
style={{
lineHeight: '64px',
marginRight: 110
}}
>
<SubMenu
key="devices"
title={
<span>
<Icon type="appstore"/>
<span>Devices</span>
</span>}
>
<Menu.Item key="devices">
<Link to="/entgra/devices">
<span>View</span>
</Link>
</Menu.Item>
<Menu.Item key="deviceEnroll">
<Link to="/entgra/devices/enroll">
<span>Enroll</span>
</Link>
</Menu.Item>
</SubMenu>
<SubMenu
key="geo"
title={
<span>
<Icon type="environment"/>
<span>Geo</span>
</span>}
>
<Menu.Item key="singleDevice">
<Link to="/entgra/geo">
<span>Single Device View</span>
</Link>
</Menu.Item>
<Menu.Item key="deviceGroup">
<Link to="#">
<span>Device Group View</span>
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="reports">
<Link to="/entgra/reports">
<Icon type="bar-chart"/>
<span>Reports</span>
</Link>
</Menu.Item>
<Menu.Item key="groups">
<Link to="/entgra/groups">
<Icon type="deployment-unit"/>
<span>Groups</span>
</Link>
</Menu.Item>
<Menu.Item key="users">
<Link to="/entgra/users">
<Icon type="user"/>
<span>Users</span>
</Link>
</Menu.Item>
<SubMenu
key="policies"
title={
<span>
<Icon type="audit"/>
<span>Policies</span>
</span>}
>
<Menu.Item key="policiesList">
<Link to="/entgra/policies">
<span>View</span>
</Link>
</Menu.Item>
<Menu.Item key="addPolicy">
<Link to="/entgra/policy/add">
<span>Add New Policy</span>
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="roles">
<Link to="/entgra/roles">
<Icon type="book"/>
<span>Roles</span>
</Link>
</Menu.Item>
<Menu.Item key="devicetypes">
<Link to="/entgra/devicetypes">
<Icon type="desktop"/>
<span>Device Types</span>
</Link>
</Menu.Item>
<SubMenu
key="configurations"
title={
<span>
<Icon type="setting"/>
<span>Configurations</span>
</span>}
>
<Menu.Item key="certificates">
<Link to="/entgra/certificates">
<span>Certificates</span>
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="trigger">
</Menu.Item>
<SubMenu className="profile"
title={
<span className="submenu-title-wrapper">
<Icon type="user"/>
{this.config.user}
</span> }>
<Logout/>
</SubMenu>
render() {
return (
<div>
<Layout className="layout">
<Layout>
<Header style={{ background: '#fff', padding: 0 }}>
<div className="logo-image">
<Link to="/entgra/devices">
<img alt="logo" src={this.logo} />
</Link>
</div>
</Menu>
</Header>
<Menu
theme="light"
mode="horizontal"
style={{
lineHeight: '64px',
marginRight: 110,
}}
>
<SubMenu
key="devices"
title={
<span>
<Icon type="appstore" />
<span>Devices</span>
</span>
}
>
<Menu.Item key="devices">
<Link to="/entgra/devices">
<span>View</span>
</Link>
</Menu.Item>
<Menu.Item key="deviceEnroll">
<Link to="/entgra/devices/enroll">
<span>Enroll</span>
</Link>
</Menu.Item>
</SubMenu>
<SubMenu
key="geo"
title={
<span>
<Icon type="environment" />
<span>Geo</span>
</span>
}
>
<Menu.Item key="singleDevice">
<Link to="/entgra/geo">
<span>Single Device View</span>
</Link>
</Menu.Item>
<Menu.Item key="deviceGroup">
<Link to="#">
<span>Device Group View</span>
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="reports">
<Link to="/entgra/reports">
<Icon type="bar-chart" />
<span>Reports</span>
</Link>
</Menu.Item>
<Menu.Item key="groups">
<Link to="/entgra/groups">
<Icon type="deployment-unit" />
<span>Groups</span>
</Link>
</Menu.Item>
<Menu.Item key="users">
<Link to="/entgra/users">
<Icon type="user" />
<span>Users</span>
</Link>
</Menu.Item>
<SubMenu
key="policies"
title={
<span>
<Icon type="audit" />
<span>Policies</span>
</span>
}
>
<Menu.Item key="policiesList">
<Link to="/entgra/policies">
<span>View</span>
</Link>
</Menu.Item>
<Menu.Item key="addPolicy">
<Link to="/entgra/policy/add">
<span>Add New Policy</span>
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="roles">
<Link to="/entgra/roles">
<Icon type="book" />
<span>Roles</span>
</Link>
</Menu.Item>
<Menu.Item key="devicetypes">
<Link to="/entgra/devicetypes">
<Icon type="desktop" />
<span>Device Types</span>
</Link>
</Menu.Item>
<SubMenu
key="configurations"
title={
<span>
<Icon type="setting" />
<span>Configurations</span>
</span>
}
>
<Menu.Item key="certificates">
<Link to="/entgra/certificates">
<span>Certificates</span>
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="trigger"></Menu.Item>
<SubMenu
className="profile"
title={
<span className="submenu-title-wrapper">
<Icon type="user" />
{this.config.user}
</span>
}
>
<Logout />
</SubMenu>
</Menu>
</Header>
<Content style={{marginTop: 10}}>
<Switch>
<Redirect exact from="/entgra" to="/entgra/devices"/>
{this.state.routes.map((route) => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>
</Content>
<Content style={{ marginTop: 10 }}>
<Switch>
<Redirect exact from="/entgra" to="/entgra/devices" />
{this.state.routes.map(route => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>
</Content>
<Footer style={{textAlign: 'center'}}>
©2019 entgra.io
</Footer>
</Layout>
</Layout>
</div>
);
}
<Footer style={{ textAlign: 'center' }}>©2019 entgra.io</Footer>
</Layout>
</Layout>
</div>
);
}
}
export default withConfigContext(Dashboard);

View File

@ -16,50 +16,47 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon
} from "antd";
import {Link} from "react-router-dom";
import DeviceTypesTable from "../../../components/DeviceTypes/DeviceTypesTable";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import DeviceTypesTable from '../../../components/DeviceTypes/DeviceTypesTable';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class DeviceTypes extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Device Types</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Device Types</h3>
<Paragraph>All device types for device management.</Paragraph>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<DeviceTypesTable/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Device Types</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Device Types</h3>
<Paragraph>All device types for device management.</Paragraph>
</div>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<DeviceTypesTable />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default DeviceTypes;

View File

@ -1,50 +1,47 @@
import React from 'react';
import {
PageHeader,
Typography,
Breadcrumb,
Icon,
Button, Select
} from "antd";
import {Link} from "react-router-dom";
import AddDevice from "../../../components/Devices/AddDevice";
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import AddDevice from '../../../components/Devices/AddDevice';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class DeviceEnroll extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item><Link to="/entgra/devices">Devices</Link></Breadcrumb.Item>
<Breadcrumb.Item>Enroll Device</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Devices</h3>
<Paragraph>All enrolled devices</Paragraph>
</div>
<div style={{borderRadius: 5}}>
<AddDevice/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra/devices">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>
<Link to="/entgra/devices">Devices</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Enroll Device</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Devices</h3>
<Paragraph>All enrolled devices</Paragraph>
</div>
<div style={{ borderRadius: 5 }}>
<AddDevice />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default DeviceEnroll;
export default DeviceEnroll;

View File

@ -16,51 +16,47 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon,
Button, Select
} from "antd";
import {Link} from "react-router-dom";
import DeviceTable from "../../../components/Devices/DevicesTable";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import DeviceTable from '../../../components/Devices/DevicesTable';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class Devices extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Devices</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Devices</h3>
<Paragraph>All enrolled devices</Paragraph>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<DeviceTable/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra/devices">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Devices</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Devices</h3>
<Paragraph>All enrolled devices</Paragraph>
</div>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<DeviceTable />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default Devices;

View File

@ -16,49 +16,51 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon,
Card
} from "antd";
import {Link} from "react-router-dom";
import GeoDashboard from "../../../components/Geo/geo-dashboard/GeoDashboard";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import GeoDashboard from '../../../components/Geo/geo-dashboard/GeoDashboard';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class Geo extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Geo</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Geo</h3>
<Paragraph>Geo Location Service</Paragraph>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720, alignItems: "center"}}>
<GeoDashboard/>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Geo</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Geo</h3>
<Paragraph>Geo Location Service</Paragraph>
</div>
</PageHeader>
<div
style={{
background: '#f0f2f5',
padding: 24,
minHeight: 720,
alignItems: 'center',
}}
>
<GeoDashboard />
</div>
</div>
);
}
}
export default Geo;

View File

@ -16,47 +16,44 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon
} from "antd";
import {Link} from "react-router-dom";
import GroupsTable from "../../../components/Groups/GroupsTable";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import GroupsTable from '../../../components/Groups/GroupsTable';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class Groups extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Groups</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Groups</h3>
<Paragraph>All device groups.</Paragraph>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
<GroupsTable/>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Groups</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Groups</h3>
<Paragraph>All device groups.</Paragraph>
</div>
</PageHeader>
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
<GroupsTable />
</div>
</div>
);
}
}
export default Groups;

View File

@ -16,65 +16,66 @@
* under the License.
*/
import React from "react";
import {notification, Menu, Icon} from 'antd';
import React from 'react';
import { notification, Menu, Icon } from 'antd';
import axios from 'axios';
import {withConfigContext} from "../../../context/ConfigContext";
import { withConfigContext } from '../../../context/ConfigContext';
/*
This class for call the logout api by sending request
*/
class Logout extends React.Component {
constructor(props) {
super(props);
this.state = {
inValid: false,
loading: false
};
}
/*
constructor(props) {
super(props);
this.state = {
inValid: false,
loading: false,
};
}
/*
This function call the logout api when the request is success
*/
handleSubmit = () => {
handleSubmit = () => {
const thisForm = this;
const config = this.props.context;
const thisForm = this;
const config = this.props.context;
thisForm.setState({
inValid: false,
});
thisForm.setState({
inValid: false
});
axios
.post(window.location.origin + config.serverConfig.logoutUri)
.then(res => {
// if the api call status is correct then user will logout and then it goes to login page
if (res.status === 200) {
window.location = window.location.origin + '/entgra/login';
}
})
.catch(function(error) {
if (error.hasOwnProperty('response') && error.response.status === 400) {
thisForm.setState({
inValid: true,
});
} else {
notification.error({
message: 'There was a problem',
duration: 0,
description: 'Error occurred while trying to logout.',
});
}
});
};
axios.post(window.location.origin + config.serverConfig.logoutUri
).then(res => {
//if the api call status is correct then user will logout and then it goes to login page
if (res.status === 200) {
window.location = window.location.origin + "/entgra/login";
}
}).catch(function (error) {
if (error.hasOwnProperty("response") && error.response.status === 400) {
thisForm.setState({
inValid: true
});
} else {
notification["error"]({
message: "There was a problem",
duration: 0,
description:
"Error occurred while trying to logout.",
});
}
});
};
render() {
return (
<Menu>
<Menu.Item key="1" onClick={this.handleSubmit}><Icon type="logout"/>Logout</Menu.Item>
</Menu>
);
}
render() {
return (
<Menu>
<Menu.Item key="1" onClick={this.handleSubmit}>
<Icon type="logout" />
Logout
</Menu.Item>
</Menu>
);
}
}
export default withConfigContext(Logout);

View File

@ -16,50 +16,47 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon
} from "antd";
import {Link} from "react-router-dom";
import AddPolicy from "../../../components/Policies/AddPolicy";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import AddPolicy from '../../../components/Policies/AddPolicy';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class AddNewPolicy extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Policies</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Policies</h3>
<Paragraph>Create new policy on IoT Server.</Paragraph>
</div>
<div style={{ borderRadius: 5}}>
<AddPolicy/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Policies</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Policies</h3>
<Paragraph>Create new policy on IoT Server.</Paragraph>
</div>
<div style={{ borderRadius: 5 }}>
<AddPolicy />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default AddNewPolicy;

View File

@ -16,50 +16,47 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon
} from "antd";
import {Link} from "react-router-dom";
import PoliciesTable from "../../../components/Policies/PoliciesTable";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import PoliciesTable from '../../../components/Policies/PoliciesTable';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class Policies extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Policies</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Policies</h3>
<Paragraph>All policies for device management</Paragraph>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<PoliciesTable/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Policies</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Policies</h3>
<Paragraph>All policies for device management</Paragraph>
</div>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<PoliciesTable />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default Policies;

View File

@ -16,137 +16,181 @@
* under the License.
*/
import React from "react";
import {
Icon,
Col,
Row, Select,
Radio, Card,
Button
} from "antd";
import React from 'react';
import { Icon, Col, Row, Card } from 'antd';
import {Link} from "react-router-dom";
import moment from "moment";
const { Option } = Select;
import { Link } from 'react-router-dom';
import moment from 'moment';
class ReportDurationItemList extends React.Component {
constructor(props) {
super(props);
this.state = {
reportParams: ['ACTIVE', 'INACTIVE', 'REMOVED'],
enrollmentsVsUnenrollmentsParams: ['Enrollments', 'Unenrollments'],
enrollmentTypeParams: ['BYOD', 'COPE'],
};
}
constructor(props) {
super(props);
this.state = {
reportParams:["ACTIVE","INACTIVE","REMOVED"],
enrollmentsVsUnenrollmentsParams:["Enrollments", "Unenrollments"],
enrollmentTypeParams:["BYOD", "COPE"]
}
}
durationItemArray = [
{
name: 'Daily Report',
description: 'Enrollments of today',
duration: [
moment().format('YYYY-MM-DD'),
moment()
.add(1, 'days')
.format('YYYY-MM-DD'),
],
},
{
name: 'Weekly Report',
description: 'Enrollments of last 7 days',
duration: [
moment()
.subtract(6, 'days')
.format('YYYY-MM-DD'),
moment()
.add(1, 'days')
.format('YYYY-MM-DD'),
],
},
{
name: 'Monthly Report',
description: 'Enrollments of last month',
duration: [
moment()
.subtract(29, 'days')
.format('YYYY-MM-DD'),
moment()
.add(1, 'days')
.format('YYYY-MM-DD'),
],
},
];
durationItemArray = [
{name:"Daily Report", description:"Enrollments of today", duration:[moment().format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]},
{name:"Weekly Report", description:"Enrollments of last 7 days", duration:[moment().subtract(6, 'days').format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]},
{name:"Monthly Report", description:"Enrollments of last month", duration:[moment().subtract(29, 'days').format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]}]
render(){
let itemStatus = this.durationItemArray.map((data) =>
<Col key={data.name} span={6}>
<Link
to={{
//Path to respective report page
pathname: "/entgra/devicestatus",
reportData: {
duration: data.duration,
reportType: data.reportType,
params: this.state.reportParams,
paramsType: data.paramsType
}
}}>
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
<div align='center'>
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
<h2><b>{data.name}</b></h2>
<p>{data.description}</p>
{/*<p>{data.duration}</p>*/}
</div>
</Card>
</Link>
</Col>
);
let itemEnrollmentsVsUnenrollments = this.durationItemArray.map((data) =>
<Col key={data.name} span={6}>
<Link
to={{
//Path to respective report page
pathname: "/entgra/enrollmentsvsunenrollments",
reportData: {
duration: data.duration,
reportType: data.reportType,
params: this.state.enrollmentsVsUnenrollmentsParams,
paramsType: data.paramsType
}
}}>
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
<div align='center'>
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
<h2><b>{data.name}</b></h2>
<p>{data.description}</p>
</div>
</Card>
</Link>
</Col>
);
let itemEnrollmentType = this.durationItemArray.map((data) =>
<Col key={data.name} span={6}>
<Link
to={{
//Path to respective report page
pathname: "/entgra/enrollmenttype",
reportData: {
duration: data.duration,
reportType: data.reportType,
params: this.state.enrollmentTypeParams,
paramsType: data.paramsType
}
}}>
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
<div align='center'>
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
<h2><b>{data.name}</b></h2>
<p>{data.description}</p>
</div>
</Card>
</Link>
</Col>
);
return(
<div>
<div style={{borderRadius: 5}}>
<Row gutter={16} >
{itemStatus}
</Row>
</div>
<div style={{borderRadius: 5}}>
<Row gutter={16} >
{itemEnrollmentsVsUnenrollments}
</Row>
</div>
<div style={{borderRadius: 5}}>
<Row gutter={16} >
{itemEnrollmentType}
</Row>
</div>
render() {
let itemStatus = this.durationItemArray.map(data => (
<Col key={data.name} span={6}>
<Link
to={{
// Path to respective report page
pathname: '/entgra/devicestatus',
reportData: {
duration: data.duration,
reportType: data.reportType,
params: this.state.reportParams,
paramsType: data.paramsType,
},
}}
>
<Card
key={data.name}
bordered={true}
hoverable={true}
style={{ borderRadius: 10, marginBottom: 16 }}
>
<div align="center">
<Icon
type="desktop"
style={{ fontSize: '25px', color: '#08c' }}
/>
<h2>
<b>{data.name}</b>
</h2>
<p>{data.description}</p>
{/* <p>{data.duration}</p>*/}
</div>
)
}
</Card>
</Link>
</Col>
));
let itemEnrollmentsVsUnenrollments = this.durationItemArray.map(data => (
<Col key={data.name} span={6}>
<Link
to={{
// Path to respective report page
pathname: '/entgra/enrollmentsvsunenrollments',
reportData: {
duration: data.duration,
reportType: data.reportType,
params: this.state.enrollmentsVsUnenrollmentsParams,
paramsType: data.paramsType,
},
}}
>
<Card
key={data.name}
bordered={true}
hoverable={true}
style={{ borderRadius: 10, marginBottom: 16 }}
>
<div align="center">
<Icon
type="desktop"
style={{ fontSize: '25px', color: '#08c' }}
/>
<h2>
<b>{data.name}</b>
</h2>
<p>{data.description}</p>
</div>
</Card>
</Link>
</Col>
));
let itemEnrollmentType = this.durationItemArray.map(data => (
<Col key={data.name} span={6}>
<Link
to={{
// Path to respective report page
pathname: '/entgra/enrollmenttype',
reportData: {
duration: data.duration,
reportType: data.reportType,
params: this.state.enrollmentTypeParams,
paramsType: data.paramsType,
},
}}
>
<Card
key={data.name}
bordered={true}
hoverable={true}
style={{ borderRadius: 10, marginBottom: 16 }}
>
<div align="center">
<Icon
type="desktop"
style={{ fontSize: '25px', color: '#08c' }}
/>
<h2>
<b>{data.name}</b>
</h2>
<p>{data.description}</p>
</div>
</Card>
</Link>
</Col>
));
return (
<div>
<div style={{ borderRadius: 5 }}>
<Row gutter={16}>{itemStatus}</Row>
</div>
<div style={{ borderRadius: 5 }}>
<Row gutter={16}>{itemEnrollmentsVsUnenrollments}</Row>
</div>
<div style={{ borderRadius: 5 }}>
<Row gutter={16}>{itemEnrollmentType}</Row>
</div>
</div>
);
}
}
export default ReportDurationItemList;
export default ReportDurationItemList;

View File

@ -16,80 +16,69 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon
} from "antd";
import {Link} from "react-router-dom";
import ReportDurationItemList from "./ReportDurationItemList";
const {Paragraph} = Typography;
import React from 'react';
import { PageHeader, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import ReportDurationItemList from './ReportDurationItemList';
class Reports extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
this.state = {
paramsObject:{},
}
}
//Get modified value from datepicker and set it to paramsObject
updateDurationValue = (modifiedFromDate,modifiedToDate) => {
let tempParamObj = this.state.paramsObject;
tempParamObj.from = modifiedFromDate;
tempParamObj.to = modifiedToDate;
this.setState({paramsObject:tempParamObj});
constructor(props) {
super(props);
this.routes = props.routes;
this.state = {
paramsObject: {},
};
}
// Get modified value from datepicker and set it to paramsObject
updateDurationValue = (modifiedFromDate, modifiedToDate) => {
let tempParamObj = this.state.paramsObject;
tempParamObj.from = modifiedFromDate;
tempParamObj.to = modifiedToDate;
this.setState({ paramsObject: tempParamObj });
};
//Get modified value from filters and set it to paramsObject
updateFiltersValue = (modifiedValue,filterType) => {
let tempParamObj = this.state.paramsObject;
if(filterType=="Device Status"){
tempParamObj.status = modifiedValue;
if(modifiedValue=="ALL" && tempParamObj.status){
delete tempParamObj.status;
}
}else{
tempParamObj.ownership = modifiedValue;
if(modifiedValue=="ALL" && tempParamObj.ownership){
delete tempParamObj.ownership;
}
}
this.setState({paramsObject:tempParamObj});
};
render() {
//Arrays for filters
const statusObj = ['ALL','ACTIVE','INACTIVE','REMOVED'];
const ownershipObj = ['ALL','BYOD','COPE'];
const params = {...this.state.paramsObject};
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Reports</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Reports</h3>
<ReportDurationItemList/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
// Get modified value from filters and set it to paramsObject
updateFiltersValue = (modifiedValue, filterType) => {
let tempParamObj = this.state.paramsObject;
if (filterType == 'Device Status') {
tempParamObj.status = modifiedValue;
if (modifiedValue == 'ALL' && tempParamObj.status) {
delete tempParamObj.status;
}
} else {
tempParamObj.ownership = modifiedValue;
if (modifiedValue == 'ALL' && tempParamObj.ownership) {
delete tempParamObj.ownership;
}
}
this.setState({ paramsObject: tempParamObj });
};
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Reports</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Reports</h3>
<ReportDurationItemList />
</div>
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default Reports;

View File

@ -16,47 +16,44 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon
} from "antd";
import {Link} from "react-router-dom";
import RolesTable from "../../../components/Roles/RolesTable";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import RolesTable from '../../../components/Roles/RolesTable';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class Roles extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Roles</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Roles</h3>
<Paragraph>All user roles</Paragraph>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
<RolesTable/>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Roles</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Roles</h3>
<Paragraph>All user roles</Paragraph>
</div>
</PageHeader>
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
<RolesTable />
</div>
</div>
);
}
}
export default Roles;

View File

@ -16,48 +16,45 @@
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon
} from "antd";
import {Link} from "react-router-dom";
import UsersTable from "../../../components/Users/UsersTable";
import React from 'react';
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
import { Link } from 'react-router-dom';
import UsersTable from '../../../components/Users/UsersTable';
const {Paragraph} = Typography;
const { Paragraph } = Typography;
class Users extends React.Component {
routes;
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Users</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Users</h3>
<Paragraph>All users for device management.</Paragraph>
</div>
<UsersTable/>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
render() {
return (
<div>
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Users</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Users</h3>
<Paragraph>All users for device management.</Paragraph>
</div>
<UsersTable />
</PageHeader>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}
}
export default Users;

View File

@ -16,161 +16,180 @@
* under the License.
*/
import React from "react";
import {Typography, Row, Col, Form, Icon, Input, Button, Checkbox} from 'antd';
import React from 'react';
import {
Typography,
Row,
Col,
Form,
Icon,
Input,
Button,
Checkbox,
} from 'antd';
import './Login.css';
import axios from 'axios';
import {withConfigContext} from "../context/ConfigContext";
import { withConfigContext } from '../context/ConfigContext';
const {Title} = Typography;
const {Text} = Typography;
const { Title } = Typography;
const { Text } = Typography;
class Login extends React.Component {
render() {
const config = this.props.context;
return (
<div>
<div className="background">
</div>
<div className="content">
<Row>
<Col xs={3} sm={3} md={10}>
</Col>
<Col xs={18} sm={18} md={4}>
<Row style={{marginBottom: 20}}>
<Col style={{textAlign: "center"}}>
<img style={
{
marginTop: 36,
height: 60
}
}
src={config.theme.logo}/>
</Col>
</Row>
<Title level={2}>Login</Title>
<WrappedNormalLoginForm/>
</Col>
</Row>
<Row>
<Col span={4} offset={10}>
</Col>
</Row>
</div>
</div>
);
}
render() {
const config = this.props.context;
return (
<div>
<div className="background"></div>
<div className="content">
<Row>
<Col xs={3} sm={3} md={10}></Col>
<Col xs={18} sm={18} md={4}>
<Row style={{ marginBottom: 20 }}>
<Col style={{ textAlign: 'center' }}>
<img
style={{
marginTop: 36,
height: 60,
}}
src={config.theme.logo}
/>
</Col>
</Row>
<Title level={2}>Login</Title>
<WrappedNormalLoginForm />
</Col>
</Row>
<Row>
<Col span={4} offset={10}></Col>
</Row>
</div>
</div>
);
}
}
class NormalLoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
inValid: false,
loading: false
};
}
handleSubmit = (e) => {
const thisForm = this;
const config = this.props.context;
console.log(config);
e.preventDefault();
this.props.form.validateFields((err, values) => {
thisForm.setState({
inValid: false
});
if (!err) {
thisForm.setState({
loading: true
});
const parameters = {
username: values.username,
password: values.password,
platform: "entgra"
};
const request = Object.keys(parameters).map(key => key + '=' + parameters[key]).join('&');
axios.post(window.location.origin+ config.serverConfig.loginUri, request
).then(res => {
if (res.status === 200) {
let redirectUrl = window.location.origin + "/entgra";
const searchParams = new URLSearchParams(window.location.search);
if (searchParams.has("redirect")) {
redirectUrl = searchParams.get("redirect");
}
window.location = redirectUrl;
}
}).catch(function (error) {
if (error.response.status === 400) {
thisForm.setState({
inValid: true,
loading: false
});
}
});
}
});
constructor(props) {
super(props);
this.state = {
inValid: false,
loading: false,
};
}
render() {
const {getFieldDecorator} = this.props.form;
let errorMsg = "";
if (this.state.inValid) {
errorMsg = <Text type="danger">Invalid Login Details</Text>;
}
let loading = "";
if (this.state.loading) {
loading = <Text type="secondary">Loading..</Text>;
}
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<Form.Item>
{getFieldDecorator('username', {
rules: [{required: true, message: 'Please input your username!'}],
})(
<Input name="username" style={{height: 32}}
prefix={<Icon type="user" style={{color: 'rgba(0,0,0,.25)'}}/>}
placeholder="Username"/>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [{required: true, message: 'Please input your Password!'}],
})(
<Input name="password" style={{height: 32}}
prefix={<Icon type="lock" style={{color: 'rgba(0,0,0,.25)'}}/>} type="password"
placeholder="Password"/>
)}
</Form.Item>
{loading}
{errorMsg}
<Form.Item>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(
<Checkbox>Remember me</Checkbox>
)}
<br/>
<a className="login-form-forgot" href="">Forgot password</a>
<Button loading={this.state.loading} block type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
</Form.Item>
</Form>
);
handleSubmit = e => {
const thisForm = this;
const config = this.props.context;
console.log(config);
e.preventDefault();
this.props.form.validateFields((err, values) => {
thisForm.setState({
inValid: false,
});
if (!err) {
thisForm.setState({
loading: true,
});
const parameters = {
username: values.username,
password: values.password,
platform: 'entgra',
};
const request = Object.keys(parameters)
.map(key => key + '=' + parameters[key])
.join('&');
axios
.post(window.location.origin + config.serverConfig.loginUri, request)
.then(res => {
if (res.status === 200) {
let redirectUrl = window.location.origin + '/entgra';
const searchParams = new URLSearchParams(window.location.search);
if (searchParams.has('redirect')) {
redirectUrl = searchParams.get('redirect');
}
window.location = redirectUrl;
}
})
.catch(function(error) {
if (error.response.status === 400) {
thisForm.setState({
inValid: true,
loading: false,
});
}
});
}
});
};
render() {
const { getFieldDecorator } = this.props.form;
let errorMsg = '';
if (this.state.inValid) {
errorMsg = <Text type="danger">Invalid Login Details</Text>;
}
let loading = '';
if (this.state.loading) {
loading = <Text type="secondary">Loading..</Text>;
}
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<Form.Item>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input
name="username"
style={{ height: 32 }}
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username"
/>,
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input
name="password"
style={{ height: 32 }}
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
type="password"
placeholder="Password"
/>,
)}
</Form.Item>
{loading}
{errorMsg}
<Form.Item>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(<Checkbox>Remember me</Checkbox>)}
<br />
<a className="login-form-forgot" href="">
Forgot password
</a>
<Button
loading={this.state.loading}
block
type="primary"
htmlType="submit"
className="login-form-button"
>
Log in
</Button>
</Form.Item>
</Form>
);
}
}
const WrappedNormalLoginForm = withConfigContext(Form.create({name: 'normal_login'})(NormalLoginForm));
const WrappedNormalLoginForm = withConfigContext(
Form.create({ name: 'normal_login' })(NormalLoginForm),
);
export default withConfigContext(Login);

View File

@ -34,8 +34,8 @@ const isLocalhost = Boolean(
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
),
);
export function register(config) {
@ -61,7 +61,7 @@ export function register(config) {
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
'worker. To learn more, visit https://bit.ly/CRA-PWA',
);
});
} else {
@ -89,7 +89,7 @@ function registerValidSW(swUrl, config) {
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
);
// Execute callback
@ -139,7 +139,7 @@ function checkValidServiceWorker(swUrl, config) {
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
'No internet connection found. App is running in offline mode.',
);
});
}

View File

@ -16,119 +16,119 @@
* under the License.
*/
var path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const configurations = require("./public/conf/config.json");
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const configurations = require('./public/conf/config.json');
const config = {
devtool: "source-map",
output: {
publicPath: '/entgra/'
devtool: 'source-map',
output: {
publicPath: '/entgra/',
},
watch: false,
resolve: {
alias: {
AppData: path.resolve(__dirname, 'source/src/app/common/'),
AppComponents: path.resolve(__dirname, 'source/src/app/components/'),
},
watch: false,
resolve: {
alias: {
AppData: path.resolve(__dirname, 'source/src/app/common/'),
AppComponents: path.resolve(__dirname, 'source/src/app/components/')
},
extensions: ['.jsx', '.js', '.ttf', '.woff', '.woff2', '.svg']
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
extensions: ['.jsx', '.js', '.ttf', '.woff', '.woff2', '.svg'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
},
],
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: { minimize: true },
},
],
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
},
{
test: /\.scss$/,
use: ['style-loader', 'scss-loader'],
},
{
test: /\.less$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
{
loader: 'less-loader',
options: {
modifyVars: {
'primary-color': configurations.theme.primaryColor,
'link-color': configurations.theme.primaryColor,
},
javascriptEnabled: true,
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
],
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000',
},
{
test: /\.(png|jpe?g)/i,
use: [
{
loader: 'url-loader',
options: {
name: './img/[name].[ext]',
limit: 10000,
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader"
]
},
{
test: /\.scss$/,
use: [ 'style-loader', 'scss-loader' ]
},
{
test: /\.less$/,
use: [
{
loader: "style-loader"
},
{
loader: "css-loader",
},
{
loader: "less-loader",
options: {
modifyVars: {
'primary-color': configurations.theme.primaryColor,
'link-color': configurations.theme.primaryColor,
},
javascriptEnabled: true,
},
}
]
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000',
},
{
test: /\.(png|jpe?g)/i,
use: [
{
loader: "url-loader",
options: {
name: "./img/[name].[ext]",
limit: 10000
}
},
{
loader: "img-loader"
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
},
{
loader: 'img-loader',
},
],
},
],
externals: {
'Config': JSON.stringify(require('./public/conf/config.json'))
}
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html',
filename: './index.html',
}),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
externals: {
Config: JSON.stringify(require('./public/conf/config.json')),
},
};
if (process.env.NODE_ENV === "development") {
config.watch = true;
if (process.env.NODE_ENV === 'development') {
config.watch = true;
}
module.exports = config;