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

@ -18,12 +18,11 @@
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,26 +16,25 @@
* 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 loadingView = (
<Layout>
<Content style={{
<Content
style={{
padding: '0 0',
paddingTop: 300,
backgroundColor: '#fff',
textAlign: 'center'
}}>
textAlign: 'center',
}}
>
<Spin tip="Loading..." />
</Content>
</Layout>
@ -44,7 +43,7 @@ const loadingView = (
const errorView = (
<Result
style={{
paddingTop: 200
paddingTop: 200,
}}
status="500"
title="Error occurred while loading the configuration"
@ -53,100 +52,104 @@ const errorView = (
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
error: false,
config: {}
}
config: {},
};
}
componentDidMount() {
axios.get(
window.location.origin + "/entgra/public/conf/config.json",
).then(res => {
axios
.get(window.location.origin + '/entgra/public/conf/config.json')
.then(res => {
const config = res.data;
this.checkUserLoggedIn(config);
}).catch((error) => {
})
.catch(error => {
this.setState({
loading: false,
error: true
})
error: true,
});
});
}
checkUserLoggedIn = (config) => {
axios.post(
window.location.origin + "/entgra-ui-request-handler/user",
"platform=entgra"
).then(res => {
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/`;
if (lastURLSegment === 'login') {
window.location.href = window.location.origin + '/entgra/';
} else {
this.setState({
loading: false,
config: config
config: config,
});
}
this.getDeviceTypes(config);
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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}`;
if (lastURLSegment !== 'login') {
window.location.href =
window.location.origin + `/entgra/login?redirect=${redirectUrl}`;
} else {
this.setState({
loading: false,
config: config
})
config: config,
});
}
} else {
this.setState({
loading: false,
error: true
})
error: true,
});
}
});
};
getDeviceTypes = (config) => {
axios.get(
window.location.origin + "/entgra-ui-request-handler/invoke/device-mgt/v1.0/device-types",
).then(res => {
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,
});
}).catch((error) => {
notification["error"]({
message: "There was a problem",
})
.catch(error => {
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load device types.",
description: 'Error occurred while trying to load device types.',
});
});
};
render() {
const { loading, error } = this.state;
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) => (
{this.props.routes.map(route => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>

View File

@ -16,14 +16,22 @@
* 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;
@ -49,42 +57,45 @@ class CertificateTable extends React.Component {
fetch = (params = {}) => {
this.setState({ loading: true });
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
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('&');
.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 => {
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,
data: res.data.data.certificates,
pagination
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to load devices.",
description: 'Error occurred while trying to load devices.',
});
}
@ -107,100 +118,118 @@ class CertificateTable extends React.Component {
});
};
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 => {
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",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully deleted the certificate.",
description: 'Successfully deleted the certificate.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to delete the certificate.",
'Error occurred while trying to delete the certificate.',
});
}
});
};
columns = [
{
title: 'Serial Number',
dataIndex: 'serialNumber'
dataIndex: 'serialNumber',
},
{
title: 'Username',
dataIndex: 'username'
dataIndex: 'username',
},
{
title: 'Certificate Version',
dataIndex: 'certificateVersion'
dataIndex: 'certificateVersion',
},
{
title: 'Certificate Serial',
dataIndex: 'certificateserial'
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} />
)
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>
)
<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>
)
<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"}>
render: serialNumber => (
<Tooltip placement="bottom" title={'Remove User'}>
<Popconfirm
placement="top"
title={"Are you sure?"}
onConfirm={() => {this.deleteCertificate(serialNumber)}}
title={'Are you sure?'}
onConfirm={() => {
this.deleteCertificate(serialNumber);
}}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
cancelText="Cancel"
>
<a>
<Text type="danger">
<Icon type="delete" />
</Text>
</a>
</Popconfirm>
</Tooltip>
)
}
),
},
];
render() {
@ -215,9 +244,10 @@ class CertificateTable extends React.Component {
dataSource={data}
pagination={{
...pagination,
size: "small",
size: 'small',
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} devices`,
// showQuickJumper: true
}}
loading={loading}

View File

@ -16,29 +16,25 @@
* 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: {},
loading: false,
selectedRows: []
selectedRows: [],
};
}
@ -51,23 +47,16 @@ class DeviceTypesTable extends React.Component {
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 +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/device-types";
'/device-types';
// send request to the invokerss
axios.get(apiUrl).then(res => {
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
@ -76,17 +65,17 @@ class DeviceTypesTable extends React.Component {
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load device types.",
description: 'Error occurred while trying to load device types.',
});
}
@ -110,10 +99,9 @@ class DeviceTypesTable extends React.Component {
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { data } = this.state;
const { Meta } = Card;
const itemCard = data.map((data) =>
const itemCard = data.map(data => (
<Col span={5} key={data.id}>
<Card
size="default"
@ -121,21 +109,19 @@ class DeviceTypesTable extends React.Component {
bordered={true}
actions={[
<Icon type="setting" key="setting" />,
<Icon type="edit" key="edit" />,]}
<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>
<Row gutter={16}>{itemCard}</Row>
</div>
);
}

View File

@ -1,37 +1,28 @@
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";
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,
}
};
}
onClickType = () => {
this.setState({
current: 1,
})
};
openAddDeviceModal = () =>{
this.setState({
isAddDeviceModalVisible : true,
})
});
};
render() {
const {loading, current, isError, supportedOsVersions, errorText, forbiddenErrors} = this.state;
const { getFieldDecorator } = this.props.form;
const { current } = this.state;
return (
<div>
<Row>
@ -43,24 +34,23 @@ class AddDevice extends React.Component {
</Steps>
</Col>
<Col span={16} offset={4}>
<Card style={{ marginTop: 24 }}>
<div style={{display: (current === 0 ? 'unset' : 'none')}}>
<div style={{ display: current === 0 ? 'unset' : 'none' }}>
<DeviceType onClickType={this.onClickType} />
</div>
<div style={{display: (current === 1 ? 'unset' : 'none')}}>
<div style={{ display: current === 1 ? 'unset' : 'none' }}>
<EnrollAgent />
</div>
<div style={{display: (current === 2 ? 'unset' : 'none')}}>
</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,31 +16,30 @@
* 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,
}
};
}
// 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"){
if (this.props.selectedRows[i].enrolmentInfo.status != 'REMOVED') {
tempDeleteState = false;
break;
}
tempDeleteState = true;
}
this.setState({canDelete:tempDeleteState})
this.setState({ canDelete: tempDeleteState });
};
onConfirmDelete = () => {
@ -55,69 +54,79 @@ class BulkActionBar extends React.Component {
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'}}>
<div style={{ display: isSelected ? 'inline' : 'none', padding: '11px' }}>
<Tooltip
placement="bottom"
title={"Delete Device"}
autoAdjustOverflow={true}>
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"}
this.state.canDelete
? 'Are you sure you want to delete?'
: 'You can only delete disenrolled devices'
}
onConfirm={this.onConfirmDelete}
okText="Ok"
cancelText="Cancel">
cancelText="Cancel"
>
<Button
type="link"
shape="circle"
icon="delete"
size={'default'}
onClick={this.onDeleteDeviceCall}
disabled={isSelected ? false : true}
style={{margin: "2px"}}/>
disabled={!isSelected}
style={{ margin: '2px' }}
/>
</Popconfirm>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={"Disenroll Device"}>
<Tooltip placement="bottom" title={'Disenroll Device'}>
<Popconfirm
placement="topLeft"
title={"Are you sure?"}
title={'Are you sure?'}
onConfirm={this.onConfirmDisenroll}
okText="Ok"
disabled={isSelectedSingle ? false : true}
cancelText="Cancel">
disabled={!isSelectedSingle}
cancelText="Cancel"
>
<Button
type="link"
shape="circle"
icon="close"
size={'default'}
style={{display:isSelectedSingle ? "inline" : "none", margin: "2px"}}/>
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"}>
<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"}}/>
style={{ margin: '2px' }}
/>
</Tooltip>
</div>
)
);
}
}

View File

@ -16,29 +16,25 @@
* 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: {},
loading: false,
selectedRows: []
selectedRows: [],
};
}
@ -46,7 +42,7 @@ class DeviceType extends React.Component {
this.fetchUsers();
}
onClickCard = (data) =>{
onClickCard = data => {
console.log(data);
this.props.onClickType();
};
@ -56,23 +52,16 @@ class DeviceType extends React.Component {
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 +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/device-types";
'/device-types';
// send request to the invokerss
axios.get(apiUrl).then(res => {
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
@ -81,17 +70,17 @@ class DeviceType extends React.Component {
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load device types.",
description: 'Error occurred while trying to load device types.',
});
}
@ -115,31 +104,35 @@ class DeviceType extends React.Component {
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { data } = this.state;
const { Meta } = Card;
const itemCard = data.map((data) =>
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}
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>
<Row gutter={16}>{itemCard}</Row>
</div>
);
}

View File

@ -16,16 +16,23 @@
* 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;
@ -39,6 +46,7 @@ const columns = [
title: 'Type',
dataIndex: 'type',
key: 'type',
// eslint-disable-next-line react/display-name
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
@ -52,74 +60,79 @@ const columns = [
}
return (
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
<Icon type={icon} theme={theme} />
</span>
);
}
},
// todo add filtering options
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner
render: enrolmentInfo => enrolmentInfo.owner,
// todo add filtering options
},
{
title: 'Ownership',
dataIndex: 'enrolmentInfo',
key: 'ownership',
render: enrolmentInfo => enrolmentInfo.ownership
render: enrolmentInfo => enrolmentInfo.ownership,
// todo add filtering options
},
{
title: 'Status',
dataIndex: 'enrolmentInfo',
key: 'status',
render: (enrolmentInfo) => {
// eslint-disable-next-line react/display-name
render: enrolmentInfo => {
const status = enrolmentInfo.status.toLowerCase();
let color = "#f9ca24";
let color = '#f9ca24';
switch (status) {
case "active":
color = "#badc58";
case 'active':
color = '#badc58';
break;
case "created":
color = "#6ab04c";
case 'created':
color = '#6ab04c';
break;
case "removed":
color = "#ff7979";
case 'removed':
color = '#ff7979';
break;
case "inactive":
color = "#f9ca24";
case 'inactive':
color = '#f9ca24';
break;
case "blocked":
color = "#636e72";
case 'blocked':
color = '#636e72';
break;
}
return <Tag color={color}>{status}</Tag>;
}
},
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
render: (data) => {
// 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>;
}
return (
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
{timeAgoString}
</Tooltip>
);
},
// todo add filtering options
}
},
];
const getTimeAgo = (time) => {
const getTimeAgo = time => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
};
class DeviceTable extends React.Component {
constructor(props) {
super(props);
@ -133,7 +146,7 @@ class DeviceTable extends React.Component {
deviceGroups: [],
groupModalVisible: false,
selectedGroupId: [],
selectedRowKeys:[]
selectedRowKeys: [],
};
}
@ -146,7 +159,7 @@ class DeviceTable extends React.Component {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
@ -155,34 +168,38 @@ class DeviceTable extends React.Component {
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
.map(key => key + '=' + extraParams[key])
.join('&');
// send request to the invoker
axios.get(
window.location.origin + config.serverConfig.invoker.uri +
axios
.get(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/devices?" + encodedExtraParams,
).then(res => {
'/devices?' +
encodedExtraParams,
)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
data: res.data.data.devices,
pagination
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to load devices.",
description: 'Error occurred while trying to load devices.',
});
}
@ -197,27 +214,30 @@ class DeviceTable extends React.Component {
const deviceData = this.state.selectedRows.map(obj => obj.deviceIdentifier);
// send request to the invoker
axios.put(
window.location.origin + config.serverConfig.invoker.uri +
axios
.put(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/admin/devices/permanent-delete",
'/admin/devices/permanent-delete',
deviceData,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.fetch();
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to delete devices.",
description: 'Error occurred while trying to delete devices.',
});
}
@ -232,36 +252,40 @@ class DeviceTable extends React.Component {
const deviceData = this.state.selectedRows[0];
// send request to the invoker
axios.delete(
window.location.origin + config.serverConfig.invoker.uri +
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 => {
'/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",
selectedRowKeys: [],
});
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully dis-enrolled the device.",
description: 'Successfully dis-enrolled the device.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to dis-enroll devices.",
description: 'Error occurred while trying to dis-enroll devices.',
});
}
@ -269,63 +293,78 @@ class DeviceTable extends React.Component {
});
};
addDevicesToGroup = (groupId) => {
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 +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/device/assign";
'/groups/device/assign';
deviceData = {
deviceIdentifier: {
id: this.state.selectedRows[0].deviceIdentifier,
type: this.state.selectedRows[0].type
type: this.state.selectedRows[0].type,
},
deviceGroupIds: groupId
}
deviceGroupIds: groupId,
};
} else if (!groupId[0]) {
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
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}));
'/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 +
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}));
'/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 => {
axios
.post(apiUrl, deviceData, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => {
if (res.status === 200) {
this.setState({
loading: false
loading: false,
});
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully added to the device group.",
description: 'Successfully added to the device group.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while adding to the device group.",
description: 'Error occurred while adding to the device group.',
});
}
@ -335,26 +374,29 @@ class DeviceTable extends React.Component {
getGroups = () => {
this.setState({
groupModalVisible: true
groupModalVisible: true,
});
// send request to the invoker
axios.get(
window.location.origin + config.serverConfig.invoker.uri +
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) {
'/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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while retrieving device groups.",
description: 'Error occurred while retrieving device groups.',
});
}
@ -366,17 +408,15 @@ class DeviceTable extends React.Component {
if (this.state.selectedGroupId) {
this.addDevicesToGroup(this.state.selectedGroupId);
this.setState({
groupModalVisible: false
groupModalVisible: false,
});
} else {
notification["error"]({
message: "There was a problem",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Please select a group.",
description: 'Please select a group.',
});
}
};
handleCancel = e => {
@ -385,7 +425,7 @@ class DeviceTable extends React.Component {
});
};
onGroupSelectChange = (value) => {
onGroupSelectChange = value => {
this.setState({ selectedGroupId: value });
};
@ -407,19 +447,26 @@ class DeviceTable extends React.Component {
onSelectChange = (selectedRowKeys, selectedRows) => {
this.setState({
selectedRowKeys,
selectedRows: selectedRows
selectedRows: selectedRows,
});
};
render() {
const {data, pagination, loading, selectedRows, selectedRowKeys} = this.state;
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"
selectedText = 'You have selected 1 device';
} else {
selectedText = "You have selected " + this.state.selectedRows.length + " devices"
selectedText =
'You have selected ' + this.state.selectedRows.length + ' devices';
}
const rowSelection = {
@ -428,29 +475,34 @@ class DeviceTable extends React.Component {
onChange: this.onSelectChange,
};
let item = this.state.deviceGroups.map((data) =>
<Select.Option
value={data.id}
key={data.id}>
let item = this.state.deviceGroups.map(data => (
<Select.Option value={data.id} key={data.id}>
{data.name}
</Select.Option>);
</Select.Option>
));
return (
<div>
<BulkActionBar
deleteDevice={this.deleteDevice}
getGroups={this.getGroups}
disenrollDevice={this.disenrollDevice}
selectedRows={this.state.selectedRows}/>
selectedRows={this.state.selectedRows}
/>
<div>
<Table
columns={columns}
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
rowKey={record =>
record.deviceIdentifier +
record.enrolmentInfo.owner +
record.enrolmentInfo.ownership
}
dataSource={data}
pagination={{
...pagination,
size: "small",
size: 'small',
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} devices`,
// showQuickJumper: true
}}
loading={loading}
@ -468,9 +520,9 @@ class DeviceTable extends React.Component {
>
<p>{selectedText}</p>
<Select
mode={isSelectedSingle ? "multiple" : "default"}
mode={isSelectedSingle ? 'multiple' : 'default'}
showSearch
style={{display:"block"}}
style={{ display: 'block' }}
placeholder="Select Group"
optionFilterProp="children"
onChange={this.onGroupSelectChange}

View File

@ -1,10 +1,9 @@
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) {
@ -16,39 +15,38 @@ class EnrollAgent extends React.Component {
pagination: {},
loading: false,
selectedRows: [],
visibleSelector: {display : 'none'}
visibleSelector: { display: 'none' },
};
}
componentDidMount() {
this.getConfigData();
};
}
onGetEnrollmentQR = () => {
this.setState({
visibleSelector: {display : 'block'}
})
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) {
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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while retrieving device groups.",
description: 'Error occurred while retrieving device groups.',
});
}
});
};
@ -57,25 +55,37 @@ class EnrollAgent extends React.Component {
<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>
<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"}>
<Button type="primary" size={'default'}>
Get Android Agent
</Button>
</div>
<Divider orientation="left">Step 02 - Enroll the Android Agent.</Divider>
<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>
<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}>
<Button
type="primary"
size={'default'}
onClick={this.onGetEnrollmentQR}
>
Enroll Using QR
</Button>
</div>

View File

@ -16,15 +16,13 @@
* 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;
@ -39,6 +37,7 @@ const columns = [
title: 'Type',
dataIndex: 'type',
key: 'type',
// eslint-disable-next-line react/display-name
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
@ -52,69 +51,75 @@ const columns = [
}
return (
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
<Icon type={icon} theme={theme} />
</span>
);
}
},
// todo add filtering options
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner
render: enrolmentInfo => enrolmentInfo.owner,
// todo add filtering options
},
{
title: 'Ownership',
dataIndex: 'enrolmentInfo',
key: 'ownership',
render: enrolmentInfo => enrolmentInfo.ownership
render: enrolmentInfo => enrolmentInfo.ownership,
// todo add filtering options
},
{
title: 'Status',
dataIndex: 'enrolmentInfo',
key: 'status',
render: (enrolmentInfo) => {
// eslint-disable-next-line react/display-name
render: enrolmentInfo => {
const status = enrolmentInfo.status.toLowerCase();
let color = "#f9ca24";
let color = '#f9ca24';
switch (status) {
case "active":
color = "#badc58";
case 'active':
color = '#badc58';
break;
case "created":
color = "#6ab04c";
case 'created':
color = '#6ab04c';
break;
case "removed":
color = "#ff7979";
case 'removed':
color = '#ff7979';
break;
case "inactive":
color = "#f9ca24";
case 'inactive':
color = '#f9ca24';
break;
case "blocked":
color = "#636e72";
case 'blocked':
color = '#636e72';
break;
}
return <Tag color={color}>{status}</Tag>;
}
},
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
render: (data) => {
// 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>;
}
return (
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
{timeAgoString}
</Tooltip>
);
},
// todo add filtering options
}
},
];
const getTimeAgo = (time) => {
const getTimeAgo = time => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
};
@ -129,16 +134,16 @@ class ReportDeviceTable extends React.Component {
pagination: {},
loading: false,
selectedRows: [],
paramsObj:{}
paramsObj: {},
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
}
selectedRows: selectedRows,
});
},
};
componentDidMount() {
@ -157,27 +162,38 @@ class ReportDeviceTable extends React.Component {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
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('&');
.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 +
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;
'/devices?' +
encodedExtraParams;
} else {
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices?" + encodedExtraParams;
'/reports/devices?' +
encodedExtraParams;
}
// send request to the invokerss
axios.get(apiUrl).then(res => {
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
@ -186,17 +202,17 @@ class ReportDeviceTable extends React.Component {
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load devices.",
description: 'Error occurred while trying to load devices.',
});
}
@ -220,19 +236,23 @@ class ReportDeviceTable extends React.Component {
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { data, pagination, loading } = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
rowKey={record =>
record.deviceIdentifier +
record.enrolmentInfo.owner +
record.enrolmentInfo.ownership
}
dataSource={data}
pagination={{
...pagination,
size: "small",
size: 'small',
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} devices`,
// showQuickJumper: true
}}
loading={loading}

View File

@ -16,17 +16,18 @@
* 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";
Polyline,
Popup,
Tooltip,
} from 'react-leaflet';
import { withConfigContext } from '../../../context/ConfigContext';
class GeoCustomMap extends Component {
constructor(props) {
super(props);
}
@ -36,19 +37,19 @@ class GeoCustomMap extends Component {
* @param locationData - location data object
* @returns content
*/
polylineMarker = (locationData) => {
const polyMarkers = locationData
.map(locationPoint => {
return [locationPoint.latitude, locationPoint.longitude]
polylineMarker = locationData => {
const polyMarkers = locationData.map(locationPoint => {
return [locationPoint.latitude, locationPoint.longitude];
});
return (
<div style={{display: "none"}}>{
<div style={{ display: 'none' }}>
{
<Polyline color="green" positions={polyMarkers}>
<Popup>on the way</Popup>
</Polyline>
}</div>
}
</div>
);
};
@ -60,12 +61,9 @@ class GeoCustomMap extends Component {
const startingPoint = [locationData[0].latitude, locationData[0].longitude];
const zoom = config.geoMap.defaultZoomLevel;
return (
<div style={{backgroundColor: "#ffffff", borderRadius: 5, padding: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5, padding: 5 }}>
<Map center={startingPoint} zoom={zoom}>
<TileLayer
url={url}
attribution={attribution}
/>
<TileLayer url={url} attribution={attribution} />
<Fragment>
{this.polylineMarker(locationData)}
<Marker position={startingPoint}>

View File

@ -16,24 +16,40 @@
* 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)
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");
.add(1, 'days')
.subtract(1, 'seconds');
this.state = {
deviceData: [],
selectedDevice: '',
@ -41,7 +57,7 @@ class GeoDashboard extends React.Component {
loading: false,
start: start,
end: end,
buttonTooltip: "Fetch Locations",
buttonTooltip: 'Fetch Locations',
};
}
@ -56,10 +72,10 @@ class GeoDashboard extends React.Component {
* @param endDate - end date
*/
applyCallback = (dates, dateStrings) => {
console.log("Apply Callback");
console.log('Apply Callback');
this.setState({
start: dateStrings[0],
end: dateStrings[1]
end: dateStrings[1],
});
};
@ -67,7 +83,6 @@ class GeoDashboard extends React.Component {
* 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);
@ -76,9 +91,22 @@ class GeoDashboard extends React.Component {
const config = this.props.context;
this.setState({ loading: true });
axios.get(window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt
+ "/devices/" + deviceType + "/" + deviceId + "/location-history?" + "from=" + fromInMills + "&to=" +
toInMills,).then(res => {
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({
@ -86,16 +114,20 @@ class GeoDashboard extends React.Component {
locationData,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to fetch locations......",
'Error occurred while trying to fetch locations......',
});
}
@ -103,11 +135,10 @@ class GeoDashboard extends React.Component {
console.log(error);
});
} else {
notification["error"]({
message: "There was a problem",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Please provide a date range and a device.",
description: 'Please provide a date range and a device.',
});
}
};
@ -116,9 +147,9 @@ class GeoDashboard extends React.Component {
* Device dropdown list handler
* @param e - selected device data
*/
handleDeviceList = (e) => {
handleDeviceList = e => {
let selectedDevice = this.state.deviceData[e];
this.setState({selectedDevice})
this.setState({ selectedDevice });
};
/**
@ -126,19 +157,18 @@ class GeoDashboard extends React.Component {
*/
fetchLocationButton = () => {
let flag;
let toolTip = "";
if (this.state.selectedDevice === "") {
let toolTip = '';
if (this.state.selectedDevice === '') {
flag = true;
toolTip = "Please select a Device";
toolTip = 'Please select a Device';
}
return (
<Tooltip placement="rightBottom" title={toolTip}>
<Button disabled={flag}
onClick={this.handleApiCall}>
<Button disabled={flag} onClick={this.handleApiCall}>
Fetch Locations
</Button>
</Tooltip>);
</Tooltip>
);
};
/**
@ -148,26 +178,30 @@ class GeoDashboard extends React.Component {
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 => {
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) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to load devices.",
description: 'Error occurred while trying to load devices.',
});
}
@ -179,26 +213,25 @@ class GeoDashboard extends React.Component {
* 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)
new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0),
);
let end = moment(start)
.add(1, "days")
.subtract(1, "seconds");
.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")
'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)],
'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)],
};
let { deviceData } = this.state;
@ -212,7 +245,6 @@ class GeoDashboard extends React.Component {
format="YYYY-MM-DD HH:mm:ss"
defaultValue={[this.state.start, this.state.end]}
onChange={this.applyCallback}
/>
<Select
@ -222,13 +254,16 @@ class GeoDashboard extends React.Component {
optionFilterProp="children"
onChange={this.handleDeviceList}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >=
0
}
>
{deviceData.map((device, index) =>
{deviceData.map((device, index) => (
<Select.Option key={index} value={index}>
{device.name + " "}{this.statusTag(device)}
</Select.Option>)}
{device.name + ' '}
{this.statusTag(device)}
</Select.Option>
))}
</Select>
{this.fetchLocationButton()}
@ -240,26 +275,25 @@ class GeoDashboard extends React.Component {
* Creates color based tags on device status
* @param device - device object
*/
statusTag = (device) => {
statusTag = device => {
const status = device.enrolmentInfo.status.toLowerCase();
let color = "#f9ca24";
let color = '#f9ca24';
switch (status) {
case "active":
color = "#badc58";
case 'active':
color = '#badc58';
break;
case "created":
color = "#6ab04c";
case 'created':
color = '#6ab04c';
break;
case "inactive":
color = "#f9ca24";
case 'inactive':
color = '#f9ca24';
break;
case "blocked":
color = "#636e72";
case 'blocked':
color = '#636e72';
break;
}
return <Tag color={color}>{status}</Tag>
return <Tag color={color}>{status}</Tag>;
};
render() {
@ -268,11 +302,11 @@ class GeoDashboard extends React.Component {
return (
<div className="container">
{this.controllerBar()}
{(locationData.length > 0) ?
{locationData.length > 0 ? (
<GeoCustomMap locationData={locationData} />
:
) : (
<Empty />
}
)}
</div>
);
}

View File

@ -16,24 +16,19 @@
* 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);
config = this.props.context;
this.state = {
addModalVisible: false,
name: '',
description: '',
}
};
}
onConfirmAdGroup = () => {
@ -41,37 +36,39 @@ class AddGroup extends React.Component {
const groupData = {
name: this.state.name,
description: this.state.description
}
description: this.state.description,
};
// send request to the invoker
axios.post(
window.location.origin + config.serverConfig.invoker.uri +
axios
.post(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups",
'/groups',
groupData,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 201) {
this.props.fetchGroups();
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully added the group.",
description: 'Successfully added the group.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to add group.",
description: 'Error occurred while trying to add group.',
});
}
});
@ -79,8 +76,8 @@ class AddGroup extends React.Component {
openAddModal = () => {
this.setState({
addModalVisible:true
})
addModalVisible: true,
});
};
handleAddOk = e => {
@ -100,16 +97,16 @@ class AddGroup extends React.Component {
});
};
onChangeName = (e) => {
onChangeName = e => {
this.setState({
name:e.currentTarget.value
})
name: e.currentTarget.value,
});
};
onChangeDescription = (e) => {
onChangeDescription = e => {
this.setState({
description:e.currentTarget.value
})
description: e.currentTarget.value,
});
};
render() {
@ -117,7 +114,12 @@ class AddGroup extends React.Component {
return (
<div>
<div>
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal}>
<Button
type="primary"
icon="plus"
size={'default'}
onClick={this.openAddModal}
>
Add Group
</Button>
</div>
@ -137,13 +139,10 @@ class AddGroup extends React.Component {
</Button>,
]}
>
<div style={{alignItems:"center"}}>
<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"}}>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item label="Name" style={{ display: 'block' }}>
{getFieldDecorator('name', {
rules: [
{
@ -153,7 +152,7 @@ class AddGroup extends React.Component {
],
})(<Input onChange={this.onChangeName} />)}
</Form.Item>
<Form.Item label="Description" style={{display:"block"}}>
<Form.Item label="Description" style={{ display: 'block' }}>
{getFieldDecorator('description', {
rules: [
{
@ -168,7 +167,7 @@ class AddGroup extends React.Component {
</Modal>
</div>
</div>
)
);
}
}

View File

@ -16,7 +16,7 @@
* under the License.
*/
import React from "react";
import React from 'react';
import {
Button,
Divider,
@ -29,19 +29,16 @@ import {
Popconfirm,
Select,
Tooltip,
Typography
} from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
Typography,
} from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
const { Text } = Typography;
let config = null;
class GroupActions extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
this.state = {
editModalVisible: false,
shareModalVisible: false,
@ -49,76 +46,81 @@ class GroupActions extends React.Component {
description: this.props.data.description,
groupDataObject: {},
rolesData: [],
shareRolesData:[]
}
shareRolesData: [],
};
}
onConfirmDeleteGroup = () => {
const config = this.props.context;
// send request to the invoker
axios.delete(
window.location.origin + config.serverConfig.invoker.uri +
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 => {
'/groups/id/' +
this.props.data.id,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully deleted the group.",
description: 'Successfully deleted the group.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to delete group.",
description: 'Error occurred while trying to delete group.',
});
}
});
};
onConfirmUpdateGroup = (data) => {
onConfirmUpdateGroup = data => {
const config = this.props.context;
// send request to the invoker
axios.put(
window.location.origin + config.serverConfig.invoker.uri +
axios
.put(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/id/" + this.props.data.id,
data
).then(res => {
'/groups/id/' +
this.props.data.id,
data,
)
.then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully updated the group.",
description: 'Successfully updated the group.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to update group.",
description: 'Error occurred while trying to update group.',
});
}
});
@ -127,88 +129,100 @@ class GroupActions extends React.Component {
fetchUserRoles = (params = {}) => {
const config = this.props.context;
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
const apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/roles";
'/roles';
// send request to the invokerss
axios.get(apiUrl).then(res => {
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) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load roles.",
description: 'Error occurred while trying to load roles.',
});
}
});
};
onConfirmShareGroup = (data) => {
onConfirmShareGroup = data => {
const config = this.props.context;
// send request to the invoker
axios.post(
window.location.origin + config.serverConfig.invoker.uri +
axios
.post(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/groups/id/" + this.props.data.id + "/share",
data
).then(res => {
'/groups/id/' +
this.props.data.id +
'/share',
data,
)
.then(res => {
if (res.status === 200) {
this.props.fetchGroups();
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully shared the group.",
description: 'Successfully shared the group.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to share group.",
description: 'Error occurred while trying to share group.',
});
}
});
}
};
openEditModal = () => {
this.setState({
editModalVisible:true
})
editModalVisible: true,
});
};
openShareModal = () => {
this.fetchUserRoles();
this.setState({
shareModalVisible:true
})
}
shareModalVisible: true,
});
};
handleEditOk = e => {
this.state.groupDataObject = {
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
groupProperties: this.props.data.groupProperties,
};
this.setState({ groupDataObject });
this.props.form.validateFields(err => {
if (!err) {
this.onConfirmUpdateGroup(this.state.groupDataObject);
@ -238,53 +252,60 @@ class GroupActions extends React.Component {
});
};
onChangeName = (e) => {
onChangeName = e => {
this.setState({
name:e.currentTarget.value
})
name: e.currentTarget.value,
});
};
onChangeDescription = (e) => {
onChangeDescription = e => {
this.setState({
description:e.currentTarget.value
})
description: e.currentTarget.value,
});
};
handleRolesDropdownChange = (value) => {
handleRolesDropdownChange = value => {
this.setState({
shareRolesData:value
})
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}>
let item = this.state.rolesData.map(data => (
<Select.Option value={data} key={data}>
{data}
</Select.Option>);
</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>
<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 placement="top" title={'Edit Group'}>
<a>
<Icon type="edit" onClick={this.openEditModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={"Delete Group"}>
<Tooltip placement="bottom" title={'Delete Group'}>
<Popconfirm
placement="top"
title={"Are you sure?"}
title={'Are you sure?'}
onConfirm={this.onConfirmDeleteGroup}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
cancelText="Cancel"
>
<a>
<Text type="danger">
<Icon type="delete" />
</Text>
</a>
</Popconfirm>
</Tooltip>
</div>
@ -304,16 +325,11 @@ class GroupActions extends React.Component {
</Button>,
]}
>
<div style={{alignItems:"center"}}>
<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',
{
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item label="Name" style={{ display: 'block' }}>
{getFieldDecorator('name', {
initialValue: this.props.data.name,
rules: [
{
@ -321,13 +337,10 @@ class GroupActions extends React.Component {
message: 'Please input group name',
},
],
})(<Input
onChange={this.onChangeName}/>)}
})(<Input onChange={this.onChangeName} />)}
</Form.Item>
<Form.Item label="Description" style={{display:"block"}}>
{getFieldDecorator(
'description',
{
<Form.Item label="Description" style={{ display: 'block' }}>
{getFieldDecorator('description', {
initialValue: this.props.data.description,
rules: [
{
@ -335,8 +348,7 @@ class GroupActions extends React.Component {
message: 'Please input group description',
},
],
})(<Input
onChange={this.onChangeDescription}/>)}
})(<Input onChange={this.onChangeDescription} />)}
</Form.Item>
</Form>
</div>
@ -364,16 +376,20 @@ class GroupActions extends React.Component {
<p>Select user role(s)</p>
<Select
mode="multiple"
defaultValue={"admin"}
defaultValue={'admin'}
style={{ width: '100%' }}
onChange={this.handleRolesDropdownChange}>
onChange={this.handleRolesDropdownChange}
>
{item}
</Select>,
</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,48 +16,39 @@
* 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'
placeholder: 'Name',
},
{
name: 'owner',
placeholder: '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: {},
loading: false,
selectedRows: []
selectedRows: [],
};
}
@ -96,9 +87,9 @@ class GroupsTable extends React.Component {
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
}
selectedRows: selectedRows,
});
},
};
componentDidMount() {
@ -111,23 +102,29 @@ class GroupsTable extends React.Component {
this.setState({ loading: true });
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
...filters
...filters,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
.map(key => key + '=' + extraParams[key])
.join('&');
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/admin/groups?" + encodedExtraParams;
'/admin/groups?' +
encodedExtraParams;
// send request to the invokerss
axios.get(apiUrl).then(res => {
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
@ -136,17 +133,17 @@ class GroupsTable extends React.Component {
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load device groups.",
description: 'Error occurred while trying to load device groups.',
});
}
@ -154,8 +151,6 @@ class GroupsTable extends React.Component {
});
};
handleTableChange = (pagination, filters, sorter) => {
const pager = { ...this.state.pagination };
pager.current = pagination.current;
@ -172,28 +167,31 @@ class GroupsTable extends React.Component {
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { data, pagination, loading } = this.state;
return (
<div>
<div style={{ background: '#f0f2f5' }}>
<AddGroup fetchGroups={this.fetchGroups} style={{marginBottom:"10px"}}/>
<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}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<Table
columns={this.columns}
rowKey={record => (record.id)}
rowKey={record => record.id}
dataSource={data.deviceGroups}
pagination={{
...pagination,
size: "small",
size: 'small',
total: data.count,
pageSize: 10,
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} groups`,
}}
loading={loading}
onChange={this.handleTableChange}

View File

@ -1,27 +1,24 @@
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";
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,
}
};
}
onClickType = () => {
this.setState({
current: 1,
})
});
};
next() {
@ -34,15 +31,8 @@ class AddPolicy extends React.Component {
this.setState({ current });
}
openAddDeviceModal = () =>{
this.setState({
isAddDeviceModalVisible : true,
})
};
render() {
const {loading, current, isError, supportedOsVersions, errorText, forbiddenErrors} = this.state;
const { getFieldDecorator } = this.props.form;
const { current } = this.state;
return (
<div>
<Row>
@ -58,20 +48,16 @@ class AddPolicy extends React.Component {
</Col>
<Col span={16} offset={4}>
<Card style={{ marginTop: 24 }}>
<div style={{display: (current === 0 ? 'unset' : 'none')}}>
<div style={{ display: current === 0 ? 'unset' : 'none' }}>
<SelectPlatform onClickType={this.onClickType} />
</div>
<div style={{display: (current === 1 ? 'unset' : 'none')}}>
<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>
<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}>
@ -86,19 +72,15 @@ class AddPolicy extends React.Component {
Next
</Button>
)}
{current === 5 && (
<Button type="primary">
Done
</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,13 +1,27 @@
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 { TextArea } = Input;
const policyConfigurationsList = jsonResponse.PolicyConfigurations;
@ -18,45 +32,39 @@ class ConfigureProfile extends React.Component {
this.config = this.props.context;
this.policies = policyConfigurationsList.androidPolicy.Policy;
this.state = {
isDisplayMain: "none",
activeKeys: []
}
isDisplayMain: 'none',
activeKeys: [],
};
componentDidMount() {
}
onChange = (e) =>{
componentDidMount() {}
onChange = e => {
console.log(`checked = ${e.target.id}`);
};
onChecked = (e, i) => {
if (e) {
this.setState({
isDisplayMain: "block",
isDisplayMain: 'block',
});
} else {
this.setState({
isDisplayMain: "none",
isDisplayMain: 'none',
});
}
};
onClickSwitch = (e) =>{
onClickSwitch = e => {};
};
getPanelItems = (panel)=>{
getPanelItems = panel => {
const { getFieldDecorator } = this.props.form;
return (
panel.map((item,k)=>{
return panel.map((item, k) => {
switch (item._type) {
case "select":
case 'select':
return (
<Form.Item key={k}
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
@ -65,23 +73,23 @@ class ConfigureProfile extends React.Component {
</Tooltip>
</span>
}
style={{display: "block"}}>
style={{ display: 'block' }}
>
{getFieldDecorator(`${item._id}`, {
initialValue: `${item.Optional.Option[0]}`
initialValue: `${item.Optional.Option[0]}`,
})(
<Select>
{item.Optional.Option.map((option)=>{
return(
<Option key={option}>{option}</Option>
);
{item.Optional.Option.map(option => {
return <Option key={option}>{option}</Option>;
})}
</Select>
</Select>,
)}
</Form.Item>
);
case "input":
case 'input':
return (
<Form.Item key={k}
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
@ -90,7 +98,8 @@ class ConfigureProfile extends React.Component {
</Tooltip>
</span>
}
style={{display: "block"}}>
style={{ display: 'block' }}
>
{getFieldDecorator(`${item._id}`, {
rules: [
{
@ -98,12 +107,10 @@ class ConfigureProfile extends React.Component {
message: `${item.Optional.rules.validationMsg}`,
},
],
})(
<Input placeholder={item.Optional.Placeholder}/>
)}
})(<Input placeholder={item.Optional.Placeholder} />)}
</Form.Item>
);
case "checkbox":
case 'checkbox':
return (
<Form.Item key={k}>
{getFieldDecorator(`${item._id}`, {
@ -120,13 +127,14 @@ class ConfigureProfile extends React.Component {
<Icon type="question-circle-o" />
</Tooltip>
</span>
</Checkbox>
</Checkbox>,
)}
</Form.Item>
);
case "textArea":
case 'textArea':
return (
<Form.Item key={k}
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
@ -135,18 +143,20 @@ class ConfigureProfile extends React.Component {
</Tooltip>
</span>
}
style={{display: "block"}}>
{getFieldDecorator(`${item._id}`, {
})(
<TextArea placeholder={item.Optional.Placeholder}
rows={item.Optional.Row} />
style={{ display: 'block' }}
>
{getFieldDecorator(`${item._id}`, {})(
<TextArea
placeholder={item.Optional.Placeholder}
rows={item.Optional.Row}
/>,
)}
</Form.Item>
);
case "radioGroup":
case 'radioGroup':
return (
<Form.Item key={k}
<Form.Item
key={k}
label={
<span>
{item.Label}&nbsp;
@ -155,39 +165,41 @@ class ConfigureProfile extends React.Component {
</Tooltip>
</span>
}
style={{display: "block"}}>
{getFieldDecorator(`${item._id}`, {
})(
style={{ display: 'block' }}
>
{getFieldDecorator(`${item._id}`, {})(
<Radio.Group>
{item.Optional.Radio.map((option)=>{
{item.Optional.Radio.map(option => {
return (
<Radio value={option}>{option}</Radio>
<Radio key={option} value={option}>
{option}
</Radio>
);
})}
</Radio.Group>
</Radio.Group>,
)}
</Form.Item>
);
case "title":
case 'title':
return (
<Title key={k} level={4}>{item.Label} </Title>
<Title key={k} level={4}>
{item.Label}{' '}
</Title>
);
case "paragraph":
case 'paragraph':
return (
<Paragraph key={k} style={{marginTop:20}}>{item.Label} </Paragraph>
<Paragraph key={k} style={{ marginTop: 20 }}>
{item.Label}{' '}
</Paragraph>
);
case "alert":
case 'alert':
return (
<Alert
<Alert key={k} description={item.Label} type="warning" showIcon />
);
case 'upload':
return (
<Form.Item
key={k}
description={item.Label}
type="warning"
showIcon
/>
);
case "upload":
return(
<Form.Item key={k}
label={
<span>
{item.Label}&nbsp;
@ -197,10 +209,7 @@ class ConfigureProfile extends React.Component {
</span>
}
>
{getFieldDecorator('upload', {
})(
{getFieldDecorator('upload', {})(
<Upload>
<Button>
<Icon type="upload" /> Click to upload
@ -212,17 +221,15 @@ class ConfigureProfile extends React.Component {
default:
return null;
}
})
)
});
};
render() {
return (
<div>
<Tabs tabPosition={"left"} size={"large"}>
<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) => {
@ -246,19 +253,14 @@ class ConfigureProfile extends React.Component {
<Row>{panel.description}</Row>
</div>
<div style={{ display: `${this.state.isDisplayMain}` }}>
<Form >
{this.getPanelItems(panel.PanelItem)}
</Form>
<Form>{this.getPanelItems(panel.PanelItem)}</Form>
</div>
</div>
);
})
}
})}
</TabPane>
)
})
}
);
})}
</Tabs>
</div>
);

View File

@ -16,18 +16,15 @@
* 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 = [
@ -56,33 +53,27 @@ const columns = [
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: {},
loading: false,
selectedRows: []
selectedRows: [],
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
}
selectedRows: selectedRows,
});
},
};
componentDidMount() {
@ -95,7 +86,7 @@ class PoliciesTable extends React.Component {
this.setState({ loading: true });
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
@ -103,14 +94,20 @@ class PoliciesTable extends React.Component {
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
.map(key => key + '=' + extraParams[key])
.join('&');
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/policies?" + encodedExtraParams;
'/policies?' +
encodedExtraParams;
// send request to the invokerss
axios.get(apiUrl).then(res => {
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
@ -119,17 +116,17 @@ class PoliciesTable extends React.Component {
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load policies.",
description: 'Error occurred while trying to load policies.',
});
}
@ -153,19 +150,19 @@ class PoliciesTable extends React.Component {
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { data, pagination, loading } = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record => (record.id)}
rowKey={record => record.id}
dataSource={data}
pagination={{
...pagination,
size: "small",
size: 'small',
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} groups`,
// showQuickJumper: true
}}
loading={loading}

View File

@ -16,29 +16,25 @@
* 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: {},
loading: false,
selectedRows: []
selectedRows: [],
};
}
@ -46,7 +42,7 @@ class SelectPlatform extends React.Component {
this.fetchUsers();
}
onClickCard = (data) =>{
onClickCard = data => {
console.log(data);
this.props.onClickType();
};
@ -56,23 +52,16 @@ class SelectPlatform extends React.Component {
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 +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/device-types";
'/device-types';
// send request to the invokerss
axios.get(apiUrl).then(res => {
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
@ -81,17 +70,17 @@ class SelectPlatform extends React.Component {
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load device types.",
description: 'Error occurred while trying to load device types.',
});
}
@ -115,31 +104,35 @@ class SelectPlatform extends React.Component {
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { data } = this.state;
const { Meta } = Card;
const itemCard = data.map((data) =>
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}
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>
<Row gutter={16}>{itemCard}</Row>
</div>
);
}

View File

@ -16,12 +16,11 @@
* 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);
}
@ -29,36 +28,34 @@ class DateRangePicker extends React.Component {
// 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': [
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')],
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')]
moment()
.subtract(1, 'month')
.startOf('month'),
moment()
.subtract(1, 'month')
.endOf('month'),
],
}}
format="YYYY-MM-DD"
onChange={this.onChange}
/>
)
);
}
}

View File

@ -16,38 +16,38 @@
* under the License.
*/
import React from "react";
import React from 'react';
import { Select } from 'antd';
class Filter extends React.Component {
constructor(props) {
super(props);
const { Option } = Select;
this.state = {
selectedItem:null
}
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");
if (this.props.dropDownName == 'Device Status') {
this.props.updateFiltersValue(this.state.selectedItem, 'Device Status');
} else {
this.props.updateFiltersValue(this.state.selectedItem, "Device Ownership");
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}>
let item = this.props.dropDownItems.map(data => (
<Select.Option value={data} key={data}>
{data}
</Select.Option>);
</Select.Option>
));
return (
<Select
showSearch
@ -57,10 +57,11 @@ class Filter extends React.Component {
onChange={this.onChange}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}>
}
>
{item}
</Select>
)
);
}
}

View File

@ -16,32 +16,15 @@
* 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;
@ -49,33 +32,34 @@ class DeviceStatusReport extends React.Component {
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]
to: reportData.duration[1],
},
statsObject: {},
statArray:[{item:"ACTIVE",count:0},{item:"INACTIVE",count:0},{item:"REMOVED",count:0}]
statArray: [
{ item: 'ACTIVE', count: 0 },
{ item: 'INACTIVE', count: 0 },
{ item: 'REMOVED', count: 0 },
],
};
}
onClickPieChart = (value) => {
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)
console.log(this.state.paramsObject);
};
render() {
const { statArray } = this.state;
const { reportData } = this.props.location;
const params = { ...this.state.paramsObject };
@ -84,19 +68,30 @@ class DeviceStatusReport extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<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}}>
<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>
<Button
onClick={this.onSubmitReport}
style={{ marginLeft: 10 }}
type="primary"
>
Generate Report
</Button>
</div>
</div>
@ -104,19 +99,26 @@ class DeviceStatusReport extends React.Component {
<Card
bordered={true}
hoverable={true}
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData}/>
style={{
borderRadius: 5,
marginBottom: 10,
height: window.innerHeight * 0.5,
}}
>
<PieChart
onClickPieChart={this.onClickPieChart}
reportData={reportData}
/>
</Card>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<ReportDeviceTable paramsObject={params} />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,32 +16,13 @@
* 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;
@ -49,38 +30,22 @@ class EnrollmentTypeReport extends React.Component {
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]
}
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;
}
}
};
onClickPieChart = (value) => {
onClickPieChart = value => {
const chartValue = value.data.point.item;
let tempParamObj = this.state.paramsObject;
console.log(chartValue)
console.log(chartValue);
tempParamObj.ownership = chartValue;
@ -96,35 +61,40 @@ class EnrollmentTypeReport extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<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}/>
style={{
borderRadius: 5,
marginBottom: 10,
height: window.innerHeight * 0.5,
}}
>
<PieChart
onClickPieChart={this.onClickPieChart}
reportData={reportData}
/>
</Card>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<ReportDeviceTable paramsObject={params} />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,32 +16,13 @@
* 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;
@ -49,121 +30,94 @@ class EnrollmentsVsUnenrollmentsReport extends React.Component {
constructor(props) {
super(props);
this.routes = props.routes;
config = this.props.context;
const { reportData } = this.props.location;
this.state = {
paramsObject: {
from:reportData? reportData.duration[0]: "2019-01-01",
to:reportData? reportData.duration[1]: "2019-01-01"
from: reportData ? reportData.duration[0] : '2019-01-01',
to: reportData ? reportData.duration[1] : '2019-01-01',
},
redirect: false
redirect: false,
};
this.redirectToHome();
console.log(this.state.paramsObject);
}
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;
}
}
};
redirectToHome = () => {
return <Redirect to="/entgra" />
return <Redirect to="/entgra" />;
};
setRedirect = (reportData) => {
if(!reportData){
this.setState({
redirect: true
})
}
};
renderRedirect = () => {
if (this.state.redirect) {
return <Redirect to='/entgra' />
}
}
onClickPieChart = (value) => {
onClickPieChart = value => {
const chartValue = value.data.point.item;
let tempParamObj = this.state.paramsObject;
console.log(chartValue)
console.log(chartValue);
// tempParamObj.status = chartValue;
if(chartValue==="Enrollments"){
tempParamObj.status = "ACTIVE&status=INACTIVE"
if (chartValue === 'Enrollments') {
tempParamObj.status = 'ACTIVE&status=INACTIVE';
} else {
tempParamObj.status = "REMOVED"
tempParamObj.status = 'REMOVED';
}
this.setState({ paramsObject: tempParamObj });
};
render() {
const { reportData } = this.props.location;
console.log("======")
console.log(reportData)
console.log("======")
console.log('======');
console.log(reportData);
console.log('======');
let reportDataClone = {
params: ["ACTIVE"],
duration: ["2020-01-01","2020-01-01"]
params: ['ACTIVE'],
duration: ['2020-01-01', '2020-01-01'],
};
const params = { ...this.state.paramsObject };
return (
<div>
<div>{!reportData ? (
<Redirect to='/entgra/reports' />
<div>
{!reportData ? (
<Redirect to="/entgra/reports" />
) : (
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<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}/>
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}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<ReportDeviceTable paramsObject={params} />
</div>
</PageHeader>
)}</div>
)}
</div>
</div>
);
}

View File

@ -1,62 +1,46 @@
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:[]
}
statArray: [],
};
}
componentDidMount() {
this.setState({statArray:this.props.statArray})
console.log("$$$$")
console.log(this.props.statArray)
this.setState({ statArray: this.props.statArray });
console.log('$$$$');
console.log(this.props.statArray);
}
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>
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>
<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>;
}
}

View File

@ -1,6 +1,5 @@
import React from "react";
import React from 'react';
import {
G2,
Chart,
Geom,
Axis,
@ -8,50 +7,43 @@ import {
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";
} 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:[]
statArray: [],
};
}
componentDidMount() {
let { statArray } = this.state;
const { reportData } = this.props;
let params = {
status: reportData.params[0],
from: reportData.duration[0],
to: reportData.duration[1]
to: reportData.duration[1],
};
const urlSet = {
paramsList: reportData.params,
duration:reportData.duration
duration: reportData.duration,
};
console.log(urlSet)
console.log(urlSet);
if(reportData.params[0]==="Enrollments"){
this.getEnrollmentsVsUnenrollmentsCount(params, urlSet)
}else if(reportData.params[0]==="BYOD"){
if (reportData.params[0] === 'Enrollments') {
this.getEnrollmentsVsUnenrollmentsCount(params, urlSet);
} else if (reportData.params[0] === 'BYOD') {
this.getEnrollmentTypeCount(params, urlSet);
} else {
this.getCount(params, urlSet);
@ -59,10 +51,10 @@ class PieChart extends React.Component {
}
clicked = () => {
console.log("Clicked...!!")
console.log('Clicked...!!');
};
onChartChange = (data) => {
onChartChange = data => {
this.props.onClickPieChart(data);
};
@ -70,7 +62,6 @@ class PieChart extends React.Component {
// 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;
@ -79,44 +70,53 @@ class PieChart extends React.Component {
const urlArray = [];
urlSet.paramsList.map((data) => {
urlSet.paramsList.map(data => {
const paramsObj = {
status: data,
from: urlSet.duration[0],
to:urlSet.duration[1]
}
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 +
.map(key => key + '=' + paramsObj[key])
.join('&');
const apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices/count?" + encodedExtraParams;
'/reports/devices/count?' +
encodedExtraParams;
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray)
console.log(urlArray);
axios.all(urlArray).then(res => {
res.map((response) => {
axios
.all(urlArray)
.then(res => {
res.map(response => {
if (response.status === 200) {
let countData = {item:response.config[0], count:parseInt(response.data.data)}
let countData = {
item: response.config[0],
// eslint-disable-next-line radix
count: parseInt(response.data.data),
};
statArray.push(countData);
}
});
this.setState({ statArray });
})
this.setState({statArray})
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to get device count.",
description: 'Error occurred while trying to get device count.',
});
}
});
@ -124,7 +124,6 @@ class PieChart extends React.Component {
// 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;
@ -133,49 +132,62 @@ class PieChart extends React.Component {
const urlArray = [];
urlSet.paramsList.map((data) => {
urlSet.paramsList.map(data => {
const paramsObj = {
from: urlSet.duration[0],
to:urlSet.duration[1]
}
to: urlSet.duration[1],
};
const encodedExtraParams = Object.keys(paramsObj)
.map(key => key + '=' + paramsObj[key]).join('&');
.map(key => key + '=' + paramsObj[key])
.join('&');
let apiUrl;
if(data==="Enrollments"){
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
if (data === 'Enrollments') {
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices/count?status=ACTIVE&status=INACTIVE&" + encodedExtraParams;
'/reports/devices/count?status=ACTIVE&status=INACTIVE&' +
encodedExtraParams;
} else {
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices/count?status=REMOVED&" + encodedExtraParams;
'/reports/devices/count?status=REMOVED&' +
encodedExtraParams;
}
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray)
console.log(urlArray);
axios.all(urlArray).then(res => {
res.map((response) => {
axios
.all(urlArray)
.then(res => {
res.map(response => {
if (response.status === 200) {
let countData = {item:response.config[0], count:parseInt(response.data.data)}
let countData = {
item: response.config[0],
// eslint-disable-next-line radix
count: parseInt(response.data.data),
};
statArray.push(countData);
}
});
this.setState({ statArray });
})
this.setState({statArray})
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to get device count.",
description: 'Error occurred while trying to get device count.',
});
}
});
@ -183,7 +195,6 @@ class PieChart extends React.Component {
// 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;
@ -192,42 +203,52 @@ class PieChart extends React.Component {
const urlArray = [];
urlSet.paramsList.map((data) => {
urlSet.paramsList.map(data => {
const paramsObj = {
ownership: data,
from: urlSet.duration[0],
to:urlSet.duration[1]
}
to: urlSet.duration[1],
};
const encodedExtraParams = Object.keys(paramsObj)
.map(key => key + '=' + paramsObj[key]).join('&');
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
.map(key => key + '=' + paramsObj[key])
.join('&');
const apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/reports/devices/count?" + encodedExtraParams;
'/reports/devices/count?' +
encodedExtraParams;
urlArray.push(axios.get(apiUrl, data));
});
console.log(urlArray)
console.log(urlArray);
axios.all(urlArray).then(res => {
res.map((response) => {
axios
.all(urlArray)
.then(res => {
res.map(response => {
if (response.status === 200) {
let countData = {item:response.config[0], count:parseInt(response.data.data)}
let countData = {
item: response.config[0],
// eslint-disable-next-line radix
count: parseInt(response.data.data),
};
statArray.push(countData);
}
});
this.setState({ statArray });
})
this.setState({statArray})
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to get device count.",
description: 'Error occurred while trying to get device count.',
});
}
});
@ -236,22 +257,22 @@ class PieChart extends React.Component {
render() {
const { DataView } = DataSet;
const { Html } = Guide;
const { statArray , loading} = this.state;
const { statArray } = this.state;
const dv = new DataView();
dv.source(statArray).transform({
type: "percent",
field: "count",
dimension: "item",
as: "percent"
type: 'percent',
field: 'count',
dimension: 'item',
as: 'percent',
});
const cols = {
percent: {
formatter: val => {
val = val * 100 + "%";
val = val * 100 + '%';
return val;
}
}
},
},
};
return (
@ -265,7 +286,7 @@ class PieChart extends React.Component {
onPlotClick={this.onChartChange}
animate={true}
>
<Coord type={"theta"} radius={0.75} innerRadius={0.6} />
<Coord type={'theta'} radius={0.75} innerRadius={0.6} />
<Axis name="percent" />
<Legend
position="right"
@ -274,12 +295,12 @@ class PieChart extends React.Component {
/>
<Tooltip
showTitle={false}
itemTpl="<li><span style=&quot;background-color:{color};&quot; class=&quot;g2-tooltip-marker&quot;></span>{name}: {value}</li>"
itemTpl='<li><span style="background-color:{color};" class="g2-tooltip-marker"></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>"
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"
/>
@ -289,30 +310,29 @@ class PieChart extends React.Component {
type="intervalStack"
position="percent"
color="item"
tooltip={[
"item*percent",
'item*percent',
(item, percent) => {
percent = percent * 100 + "%";
percent = percent * 100 + '%';
return {
name: item,
value: percent
value: percent,
};
}
},
]}
style={{
lineWidth: 1,
stroke: "#fff"
stroke: '#fff',
}}
>
<Label
content="percent"
formatter={(val, item) => {
return item.point.item + ": " + val;
}}/>
return item.point.item + ': ' + val;
}}
/>
</Geom>
</div>
</Chart>
</div>
);

View File

@ -1,13 +1,21 @@
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;
class AddRole extends React.Component {
constructor(props) {
super(props);
this.config = this.props.context;
@ -22,12 +30,12 @@ class AddRole extends React.Component {
autoExpandParent: true,
checkedKeys: [],
isNodeList: false,
}
};
}
openAddModal = () => {
this.setState({
isAddRoleModalVisible: true
isAddRoleModalVisible: true,
});
};
@ -38,7 +46,7 @@ class AddRole extends React.Component {
});
};
getCheckedPermissionsList = (data) =>{
getCheckedPermissionsList = data => {
data.forEach(item => {
if (item !== null) {
this.expandKeys.push(item.resourcePath);
@ -69,7 +77,7 @@ class AddRole extends React.Component {
this.setState({ checkedKeys });
};
onConfirmAddRole = (value) => {
onConfirmAddRole = value => {
const roleData = {
roleName: value.roleName,
users: value.users,
@ -77,159 +85,183 @@ class AddRole extends React.Component {
this.setState({
roleName: value.roleName,
});
axios.post(
window.location.origin + this.config.serverConfig.invoker.uri +
axios
.post(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles",
'/roles',
roleData,
{headers: {'Content-Type': 'application-json'}}
).then(res => {
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 201) {
this.props.fetchUsers();
this.setState({
isAddRoleModalVisible: false,
isAddPermissionModalVisible: true,
});
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully added the role.",
description: 'Successfully added the role.',
});
this.loadPermissionList();
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to add role.",
description: 'Error occurred while trying to add role.',
});
}
});
};
renderTreeNodes = (data) => {
renderTreeNodes = data => {
return data.map(item => {
if (item !== null) {
if (item.hasOwnProperty("nodeList")) {
if (item.hasOwnProperty('nodeList')) {
return (
<TreeNode title={item.displayName} key={item.resourcePath} dataRef={item}>
<TreeNode
title={item.displayName}
key={item.resourcePath}
dataRef={item}
>
{this.renderTreeNodes(item.nodeList)}
</TreeNode>
);
}
return <TreeNode key={item.resourcePath} {...item} />;
}
else{
// eslint-disable-next-line react/jsx-key
return <TreeNode />;
}
});
};
onAssignPermissions = () => {
const roleData = {
roleName: this.state.roleName,
permissions : this.state.checkedKeys
permissions: this.state.checkedKeys,
};
axios.put(
window.location.origin + this.config.serverConfig.invoker.uri +
axios
.put(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ this.state.roleName,
'/roles/' +
this.state.roleName,
roleData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully Updated the Permissions.",
description: 'Successfully Updated the Permissions.',
});
this.setState({
isAddPermissionModalVisible : false
isAddPermissionModalVisible: false,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to add permissions.",
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";
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 => {
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
expandedKeys: this.expandKeys,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description: "Error occurred while trying to load permission.",
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 => {
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>);
users.push(
<Option key={user[i].username}>{user[i].username}</Option>,
);
}
this.setState({
users: users
users: users,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description: "Error occurred while trying to load users.",
description: 'Error occurred while trying to load users.',
});
}
})
});
};
render() {
@ -237,8 +269,13 @@ class AddRole extends React.Component {
return (
<div>
<div>
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal}
style={{marginBottom: '10px'}}>
<Button
type="primary"
icon="plus"
size={'default'}
onClick={this.openAddModal}
style={{ marginBottom: '10px' }}
>
Add Role
</Button>
</div>
@ -256,44 +293,49 @@ class AddRole extends React.Component {
<Button key="submit" type="primary" onClick={this.onAddRole}>
Add Role
</Button>,
]}>
<div style={{alignItems: "center"}}>
]}
>
<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"}}>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item
label="User Store Domain"
style={{ display: 'block' }}
>
{getFieldDecorator('userStoreDomain', {
initialValue: 'PRIMARY'
initialValue: 'PRIMARY',
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>
</Select>,
)}
</Form.Item>
<Form.Item label="Role Name" style={{display: "block"}}>
<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 ' +
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
<Form.Item label="User List" style={{ display: 'block' }}>
{getFieldDecorator('users', {})(
<Select
mode="multiple"
style={{ width: '100%' }}
onSearch={this.loadUsersList}>
onSearch={this.loadUsersList}
>
{this.state.users}
</Select>)}
</Select>,
)}
</Form.Item>
</Form>
</div>
@ -306,25 +348,35 @@ class AddRole extends React.Component {
visible={this.state.isAddPermissionModalVisible}
onOk={this.onAssignPermissions}
onCancel={this.onCancelHandler}
bodyStyle={{overflowY:"scroll", maxHeight:'500px', marginLeft:'10px'}}
bodyStyle={{
overflowY: 'scroll',
maxHeight: '500px',
marginLeft: '10px',
}}
footer={[
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onAssignPermissions}>
<Button
key="submit"
type="primary"
onClick={this.onAssignPermissions}
>
Assign
</Button>,
]}>
<div style={{alignItems: "center"}}>
]}
>
<div style={{ alignItems: 'center' }}>
<div>
{(this.state.isNodeList) && (
{this.state.isNodeList && (
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
onCheck={this.onCheck}
checkedKeys={this.state.checkedKeys}>
checkedKeys={this.state.checkedKeys}
>
{this.renderTreeNodes(this.state.nodeList)}
</Tree>
)}
@ -337,4 +389,4 @@ class AddRole extends React.Component {
}
}
export default withConfigContext(Form.create({name: 'add-role'})(AddRole))
export default withConfigContext(Form.create({ name: 'add-role' })(AddRole));

View File

@ -10,11 +10,12 @@ import {
notification,
Popconfirm,
Select,
Tooltip, Tree,
Typography
} from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
Tooltip,
Tree,
Typography,
} from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
const { Option } = Select;
const { Text } = Typography;
const { TreeNode } = Tree;
@ -39,28 +40,33 @@ class RoleAction extends React.Component {
}
openEditRoleModal = () => {
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
let apiUrl =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ this.props.data;
'/roles/' +
this.props.data;
axios.get(apiUrl).then(res => {
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) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load role.",
description: 'Error occurred while trying to load role.',
});
}
});
@ -74,35 +80,43 @@ class RoleAction extends React.Component {
};
loadPermissionList = () => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/roles/"+this.props.data+"/permissions";
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 => {
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
expandedKeys: this.expandKeys,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load permission.",
description: 'Error occurred while trying to load permission.',
});
}
})
});
};
getCheckedPermissions = (data) =>{
getCheckedPermissions = data => {
data.forEach(item => {
if (item !== null) {
this.expandKeys.push(item.resourcePath);
@ -127,20 +141,24 @@ class RoleAction extends React.Component {
this.setState({ checkedKeys });
};
renderTreeNodes = (data) => {
renderTreeNodes = data => {
return data.map(item => {
if (item !== null) {
if (item.hasOwnProperty("nodeList")) {
if (item.hasOwnProperty('nodeList')) {
return (
<TreeNode title={item.displayName} key={item.resourcePath} dataRef={item}>
<TreeNode
title={item.displayName}
key={item.resourcePath}
dataRef={item}
>
{this.renderTreeNodes(item.nodeList)}
</TreeNode>
);
}
return <TreeNode key={item.resourcePath} {...item} />;
} else{
return <TreeNode/>;
}
// eslint-disable-next-line react/jsx-key
return <TreeNode />;
});
};
@ -157,44 +175,47 @@ class RoleAction extends React.Component {
this.setState({
isEditRoleModalVisible: false,
isEditPermissionModalVisible: false,
})
});
};
onConfirmUpdateRole = (value) =>{
onConfirmUpdateRole = value => {
const roleData = {
roleName: value.roleName,
users: value.users,
};
axios.put(
window.location.origin + this.config.serverConfig.invoker.uri +
axios
.put(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ this.props.data,
'/roles/' +
this.props.data,
roleData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isEditRoleModalVisible: false,
});
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully Updated the role.",
description: 'Successfully Updated the role.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to add role.",
description: 'Error occurred while trying to add role.',
});
}
});
@ -203,128 +224,151 @@ class RoleAction extends React.Component {
onAssignPermission = () => {
const roleData = {
roleName: this.props.data,
permissions : this.state.checkedKeys
permissions: this.state.checkedKeys,
};
axios.put(
window.location.origin + this.config.serverConfig.invoker.uri +
axios
.put(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ this.props.data,
'/roles/' +
this.props.data,
roleData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully Updated the Permissions.",
description: 'Successfully Updated the Permissions.',
});
this.setState({
isEditPermissionModalVisible : false
isEditPermissionModalVisible: false,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to add permissions.",
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 => {
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>);
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.",
users: 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) {
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to delete role.",
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 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>
<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 placement="top" title={'Edit Permissions'}>
<a>
<Icon type="file-add" onClick={this.openEditPermissionModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={"Remove Role"}>
<Tooltip placement="bottom" title={'Remove Role'}>
<Popconfirm
placement="top"
title={"Are you sure?"}
title={'Are you sure?'}
onConfirm={this.onDeleteRole}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
cancelText="Cancel"
>
<a>
<Text type="danger">
<Icon type="delete" />
</Text>
</a>
</Popconfirm>
</Tooltip>
</div>
@ -343,47 +387,52 @@ class RoleAction extends React.Component {
<Button key="submit" type="primary" onClick={this.onUpdateRole}>
Add Role
</Button>,
]}>
<div style={{alignItems:"center"}}>
]}
>
<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"}}>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item
label="User Store Domain"
style={{ display: 'block' }}
>
{getFieldDecorator('userStoreDomain', {
initialValue : 'PRIMARY'
initialValue: 'PRIMARY',
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>
</Select>,
)}
</Form.Item>
<Form.Item label="Role Name" style={{display:"block"}}>
<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 ' +
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"}}>
<Form.Item label="User List" style={{ display: 'block' }}>
{getFieldDecorator('users', {
initialValue: this.state.roleData.users,
})(<Select
})(
<Select
mode="multiple"
style={{ width: '100%' }}
onSearch={this.loadUsersList}>
onSearch={this.loadUsersList}
>
{this.state.users}
</Select>)}
</Select>,
)}
</Form.Item>
</Form>
</div>
@ -400,20 +449,30 @@ class RoleAction extends React.Component {
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onAssignPermission}>
<Button
key="submit"
type="primary"
onClick={this.onAssignPermission}
>
Assign
</Button>,
]}
bodyStyle={{overflowY:"scroll", maxHeight:'500px', marginLeft:'10px'}}>
bodyStyle={{
overflowY: 'scroll',
maxHeight: '500px',
marginLeft: '10px',
}}
>
<div>
{(this.state.isNodeList) &&(
{this.state.isNodeList && (
<Tree
checkable
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
onCheck={this.onCheck}
checkedKeys={this.state.checkedKeys}>
checkedKeys={this.state.checkedKeys}
>
{this.renderTreeNodes(this.state.nodeList)}
</Tree>
)}
@ -425,4 +484,6 @@ class RoleAction extends React.Component {
}
}
export default withConfigContext(Form.create({name: 'role-actions'})(RoleAction));
export default withConfigContext(
Form.create({ name: 'role-actions' })(RoleAction),
);

View File

@ -16,31 +16,24 @@
* 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'
}
placeholder: 'Name',
},
];
class RolesTable extends React.Component {
constructor(props) {
super(props);
@ -61,39 +54,44 @@ class RolesTable extends React.Component {
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
}
selectedRows: selectedRows,
});
},
};
componentDidMount() {
this.fetchUsers();
}
openUserListModal = (event) => {
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
openUserListModal = event => {
let apiUrl =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles/"+ event;
'/roles/' +
event;
// send request to the invokerss
axios.get(apiUrl).then(res => {
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) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load users.",
description: 'Error occurred while trying to load users.',
});
}
});
@ -117,23 +115,29 @@ class RolesTable extends React.Component {
this.setState({ loading: true });
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
...filters
...filters,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
.map(key => key + '=' + extraParams[key])
.join('&');
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
let apiUrl =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/roles?" + encodedExtraParams;
'/roles?' +
encodedExtraParams;
// send request to the invokerss
axios.get(apiUrl).then(res => {
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
@ -142,17 +146,17 @@ class RolesTable extends React.Component {
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load users.",
description: 'Error occurred while trying to load users.',
});
}
@ -176,25 +180,28 @@ class RolesTable extends React.Component {
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { data, pagination, loading } = this.state;
const columns = [
{
title: 'Role Name',
dataIndex: '',
key: "role",
width: "60%",
key: 'role',
width: '60%',
},
{
title: 'View',
dataIndex: '',
key: 'users',
render: (id, row) =>
render: (id, row) => (
<Button
type="primary"
size={"small"}
size={'small'}
icon="book"
onClick={()=>this.openUserListModal(row)}>Users</Button>
onClick={() => this.openUserListModal(row)}
>
Users
</Button>
),
},
{
title: 'Action',
@ -206,7 +213,6 @@ class RolesTable extends React.Component {
</span>
),
},
];
return (
<div>
@ -216,16 +222,17 @@ class RolesTable extends React.Component {
<div style={{ textAlign: 'right' }}>
<Filter fields={searchFields} callback={this.fetchUsers} />
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<Table
columns={columns}
rowKey={record => (record)}
rowKey={record => record}
dataSource={data}
pagination={{
...pagination,
size: "small",
size: 'small',
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} groups`,
// showQuickJumper: true
}}
loading={loading}
@ -239,18 +246,19 @@ class RolesTable extends React.Component {
width="900px"
visible={this.state.isUserListModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel} >
onCancel={this.handleCancel}
>
<div>
<List
size="small"
bordered
dataSource={this.state.userData}
renderItem={item => <List.Item>{item}</List.Item>}/>
renderItem={item => <List.Item>{item}</List.Item>}
/>
</div>
</Modal>
</div>
</div>
);
}
}

View File

@ -26,12 +26,19 @@ class RouteWithSubRoutes extends React.Component{
}
render() {
return (
<Route path={this.props.path} exact={this.props.exact} render={(props) => (
<this.props.component {...props} {...this.props} routes={this.props.routes}/>
)}/>
<Route
path={this.props.path}
exact={this.props.exact}
render={props => (
<this.props.component
{...props}
{...this.props}
routes={this.props.routes}
/>
)}
/>
);
}
}
export default RouteWithSubRoutes;

View File

@ -1,19 +1,25 @@
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 : []
}
roles: [],
};
}
componentDidMount() {
@ -22,7 +28,7 @@ class AddUser extends React.Component {
openAddModal = () => {
this.setState({
isModalVisible:true
isModalVisible: true,
});
};
@ -34,44 +40,46 @@ class AddUser extends React.Component {
});
};
onConfirmAddUser = (value) =>{
onConfirmAddUser = value => {
const userData = {
username : value.userStoreDomain +"/"+value.userName,
username: value.userStoreDomain + '/' + value.userName,
firstname: value.firstName,
lastname: value.lastName,
emailAddress: value.email,
roles : value.userRoles
roles: value.userRoles,
};
axios.post(
window.location.origin + this.config.serverConfig.invoker.uri +
axios
.post(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/users",
'/users',
userData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 201) {
this.props.fetchUsers();
this.setState({
isModalVisible: false,
});
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully added the user.",
description: 'Successfully added the user.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to add user.",
description: 'Error occurred while trying to add user.',
});
}
});
@ -84,33 +92,43 @@ class AddUser extends React.Component {
};
getRole = () => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/roles?user-store=PRIMARY&limit=100";
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 => {
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>);
roles.push(
<Option key={res.data.data.roles[i]}>
{res.data.data.roles[i]}
</Option>,
);
}
this.setState({
roles : roles
})
roles: roles,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load roles.",
description: 'Error occurred while trying to load roles.',
});
}
})
});
};
render() {
@ -118,7 +136,13 @@ class AddUser extends React.Component {
return (
<div>
<div>
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal} style={{marginBottom : '10px'}}>
<Button
type="primary"
icon="plus"
size={'default'}
onClick={this.openAddModal}
style={{ marginBottom: '10px' }}
>
Add User
</Button>
</div>
@ -133,35 +157,42 @@ class AddUser extends React.Component {
<Button key="cancel" onClick={this.onCancelHandler}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={this.onSubmitHandler}>
<Button
key="submit"
type="primary"
onClick={this.onSubmitHandler}
>
Submit
</Button>,
]}>
<div style={{alignItems:"center"}}>
]}
>
<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"}}>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item
label="User Store Domain"
style={{ display: 'block' }}
>
{getFieldDecorator('userStoreDomain', {
initialValue : 'PRIMARY'
initialValue: 'PRIMARY',
})(
<Select>
<Option key="PRIMARY">PRIMARY</Option>
</Select>
</Select>,
)}
</Form.Item>
<Form.Item label="User Name" style={{display:"block"}}>
<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.',
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"}}>
<Form.Item label="First Name" style={{ display: 'block' }}>
{getFieldDecorator('firstName', {
rules: [
{
@ -171,7 +202,7 @@ class AddUser extends React.Component {
],
})(<Input />)}
</Form.Item>
<Form.Item label="Last Name" style={{display:"block"}}>
<Form.Item label="Last Name" style={{ display: 'block' }}>
{getFieldDecorator('lastName', {
rules: [
{
@ -181,7 +212,7 @@ class AddUser extends React.Component {
],
})(<Input />)}
</Form.Item>
<Form.Item label="Email Address" style={{display:"block"}}>
<Form.Item label="Email Address" style={{ display: 'block' }}>
{getFieldDecorator('email', {
rules: [
{
@ -195,13 +226,12 @@ class AddUser extends React.Component {
],
})(<Input />)}
</Form.Item>
<Form.Item label="User Roles" style={{display:"block"}}>
{getFieldDecorator('userRoles', {
})(<Select
mode="multiple"
style={{ width: '100%' }}>
<Form.Item label="User Roles" style={{ display: 'block' }}>
{getFieldDecorator('userRoles', {})(
<Select mode="multiple" style={{ width: '100%' }}>
{this.state.roles}
</Select>)}
</Select>,
)}
</Form.Item>
</Form>
</div>
@ -212,4 +242,4 @@ class AddUser extends React.Component {
}
}
export default withConfigContext(Form.create({name: 'add-user'})(AddUser))
export default withConfigContext(Form.create({ name: 'add-user' })(AddUser));

View File

@ -11,9 +11,10 @@ import {
Popconfirm,
Select,
Tooltip,
Typography } from "antd";
import axios from "axios";
import {withConfigContext} from "../../context/ConfigContext";
Typography,
} from 'antd';
import axios from 'axios';
import { withConfigContext } from '../../context/ConfigContext';
const { Option } = Select;
const { Text } = Typography;
@ -25,82 +26,87 @@ class UserActions extends React.Component {
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.');
callback("New password doesn't match the confirmation.");
} else {
callback();
}
};
onSavePassword = () => {
this.props.form.validateFields((['password', 'confirmPassword']),(err, values) => {
this.props.form.validateFields(
['password', 'confirmPassword'],
(err, values) => {
if (!err) {
this.onResetPassword(values);
}
});
},
);
};
onResetPassword = (value) =>{
onResetPassword = value => {
const password = {
newPassword: value.password,
};
axios.post(
window.location.origin + this.config.serverConfig.invoker.uri +
axios
.post(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/admin/users/"+this.props.data.username+"/credentials",
'/admin/users/' +
this.props.data.username +
'/credentials',
password,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isResetPasswordModalVisible: false,
});
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully reset the password",
description: 'Successfully reset the password',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to reset password.",
description: 'Error occurred while trying to reset password.',
});
}
});
};
componentDidMount() {
@ -108,168 +114,208 @@ class UserActions extends React.Component {
}
getRole = () => {
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt + "/roles?user-store=PRIMARY&limit=100";
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 => {
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>);
roles.push(
<Option key={res.data.data.roles[i]}>
{res.data.data.roles[i]}
</Option>,
);
}
this.setState({
roles : roles
})
roles: roles,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load roles.",
description: 'Error occurred while trying to load roles.',
});
}
})
});
};
onConfirmDeleteUser = () => {
axios.delete(
window.location.origin + this.config.serverConfig.invoker.uri +
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 => {
'/users/' +
this.props.data.username,
{ headers: { 'Content-Type': 'application/json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully deleted the user.",
description: 'Successfully deleted the user.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to delete user.",
description: 'Error occurred while trying to delete user.',
});
}
});
};
fetchRoles = (username) => {
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
fetchRoles = username => {
let apiUrl =
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/users/" + username + "/roles";
'/users/' +
username +
'/roles';
axios.get(apiUrl).then(res => {
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) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load roles.",
description: 'Error occurred while trying to load roles.',
});
}
});
};
handleEditOk = e => {
this.props.form.validateFields((['userStoreDomain', 'userName', 'firstName', 'lastName' , 'email', 'userRoles']),(err, values) => {
this.props.form.validateFields(
[
'userStoreDomain',
'userName',
'firstName',
'lastName',
'email',
'userRoles',
],
(err, values) => {
if (!err) {
this.onUpdateUser(values);
}
});
},
);
};
onUpdateUser = (value) =>{
onUpdateUser = value => {
const userData = {
username : value.userStoreDomain +"/"+value.userName,
username: value.userStoreDomain + '/' + value.userName,
firstname: value.firstName,
lastname: value.lastName,
emailAddress: value.email,
roles : value.userRoles
roles: value.userRoles,
};
axios.put(
window.location.origin + this.config.serverConfig.invoker.uri +
axios
.put(
window.location.origin +
this.config.serverConfig.invoker.uri +
this.config.serverConfig.invoker.deviceMgt +
"/users/"+ this.props.data.username,
'/users/' +
this.props.data.username,
userData,
{headers: {'Content-Type' : 'application-json'}}
).then(res => {
{ headers: { 'Content-Type': 'application-json' } },
)
.then(res => {
if (res.status === 200) {
this.props.fetchUsers();
this.setState({
isEditModalVisible: false,
});
notification["success"]({
message: "Done",
notification.success({
message: 'Done',
duration: 4,
description:
"Successfully updated the user.",
description: 'Successfully updated the user.',
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to update user.",
description: 'Error occurred while trying to update user.',
});
}
});
};
render() {
const isAdminUser = this.props.data.username ==="admin";
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>
<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 placement="top" title={'Reset Password'}>
<a>
<Icon type="key" onClick={this.openPasswordResetModal} />
</a>
</Tooltip>
<Divider type="vertical" />
<Tooltip placement="bottom" title={"Remove User"}>
<Tooltip placement="bottom" title={'Remove User'}>
<Popconfirm
placement="top"
title={"Are you sure?"}
title={'Are you sure?'}
onConfirm={this.onConfirmDeleteUser}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
cancelText="Cancel"
>
<a>
<Text type="danger">
<Icon type="delete" />
</Text>
</a>
</Popconfirm>
</Tooltip>
</div>
@ -288,15 +334,12 @@ class UserActions extends React.Component {
<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',
{
]}
>
<div style={{ alignItems: 'center' }}>
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 17 }}>
<Form.Item label="New Password" style={{ display: 'block' }}>
{getFieldDecorator('password', {
rules: [
{
required: true,
@ -305,10 +348,11 @@ class UserActions extends React.Component {
],
})(<Input.Password />)}
</Form.Item>
<Form.Item label="Retype New Password" style={{display:"block"}}>
{getFieldDecorator(
'confirmPassword',
{
<Form.Item
label="Retype New Password"
style={{ display: 'block' }}
>
{getFieldDecorator('confirmPassword', {
rules: [
{
required: true,
@ -339,33 +383,36 @@ class UserActions extends React.Component {
<Button key="submit" type="primary" onClick={this.handleEditOk}>
Update
</Button>,
]}>
<div style={{alignItems:"center"}}>
]}
>
<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"}}>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
<Form.Item
label="User Store Domain"
style={{ display: 'block' }}
>
{getFieldDecorator('userStoreDomain', {
initialValue : 'PRIMARY'
initialValue: 'PRIMARY',
})(
<Select disabled={true}>
<Option key="PRIMARY">PRIMARY</Option>
</Select>
</Select>,
)}
</Form.Item>
<Form.Item label="User Name" style={{display:"block"}}>
<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.',
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"}}>
<Form.Item label="First Name" style={{ display: 'block' }}>
{getFieldDecorator('firstName', {
initialValue: this.props.data.firstname,
rules: [
@ -376,7 +423,7 @@ class UserActions extends React.Component {
],
})(<Input />)}
</Form.Item>
<Form.Item label="Last Name" style={{display:"block"}}>
<Form.Item label="Last Name" style={{ display: 'block' }}>
{getFieldDecorator('lastName', {
initialValue: this.props.data.lastname,
rules: [
@ -387,7 +434,7 @@ class UserActions extends React.Component {
],
})(<Input />)}
</Form.Item>
<Form.Item label="Email Address" style={{display:"block"}}>
<Form.Item label="Email Address" style={{ display: 'block' }}>
{getFieldDecorator('email', {
initialValue: this.props.data.emailAddress,
rules: [
@ -402,14 +449,14 @@ class UserActions extends React.Component {
],
})(<Input />)}
</Form.Item>
<Form.Item label="User Roles" style={{display:"block"}}>
<Form.Item label="User Roles" style={{ display: 'block' }}>
{getFieldDecorator('userRoles', {
initialValue: this.state.rolesData,
})(<Select
mode="multiple"
style={{ width: '100%' }}>
})(
<Select mode="multiple" style={{ width: '100%' }}>
{this.state.roles}
</Select>)}
</Select>,
)}
</Form.Item>
</Form>
</div>
@ -420,4 +467,6 @@ class UserActions extends React.Component {
}
}
export default withConfigContext(Form.create({name: 'user-actions'})(UserActions));
export default withConfigContext(
Form.create({ name: 'user-actions' })(UserActions),
);

View File

@ -16,18 +16,15 @@
* 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 = [
{
@ -39,6 +36,7 @@ const columns = [
title: 'Type',
dataIndex: 'type',
key: 'type',
// eslint-disable-next-line react/display-name
render: type => {
const defaultPlatformIcons = config.defaultPlatformIcons;
let icon = defaultPlatformIcons.default.icon;
@ -52,18 +50,18 @@ const columns = [
}
return (
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
<Icon type={icon} theme={theme} />
</span>
);
}
},
// todo add filtering options
},
{
title: 'Owner',
dataIndex: 'enrolmentInfo',
key: 'owner',
render: enrolmentInfo => enrolmentInfo.owner
render: enrolmentInfo => enrolmentInfo.owner,
// todo add filtering options
},
{
@ -71,7 +69,7 @@ const columns = [
dataIndex: 'enrolmentInfo',
key: 'ownership',
width: 100,
render: enrolmentInfo => enrolmentInfo.ownership
render: enrolmentInfo => enrolmentInfo.ownership,
// todo add filtering options
},
{
@ -79,44 +77,50 @@ const columns = [
dataIndex: 'enrolmentInfo',
width: 100,
key: 'status',
render: (enrolmentInfo) => {
// eslint-disable-next-line react/display-name
render: enrolmentInfo => {
const status = enrolmentInfo.status.toLowerCase();
let color = "#f9ca24";
let color = '#f9ca24';
switch (status) {
case "active":
color = "#badc58";
case 'active':
color = '#badc58';
break;
case "created":
color = "#6ab04c";
case 'created':
color = '#6ab04c';
break;
case "removed":
color = "#ff7979";
case 'removed':
color = '#ff7979';
break;
case "inactive":
color = "#f9ca24";
case 'inactive':
color = '#f9ca24';
break;
case "blocked":
color = "#636e72";
case 'blocked':
color = '#636e72';
break;
}
return <Tag color={color}>{status}</Tag>;
}
},
// todo add filtering options
},
{
title: 'Last Updated',
dataIndex: 'enrolmentInfo',
key: 'dateOfLastUpdate',
render: (data) => {
// 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>;
}
return (
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
{timeAgoString}
</Tooltip>
);
},
// todo add filtering options
}
},
];
const getTimeAgo = (time) => {
const getTimeAgo = time => {
const timeAgo = new TimeAgo('en-US');
return timeAgo.format(time);
};
@ -130,16 +134,16 @@ class UsersDevices extends React.Component {
data: [],
pagination: {},
loading: false,
selectedRows: []
selectedRows: [],
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
}
selectedRows: selectedRows,
});
},
};
componentDidMount() {
@ -158,7 +162,7 @@ class UsersDevices extends React.Component {
const config = this.props.context;
this.setState({ loading: true });
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
@ -168,34 +172,38 @@ class UsersDevices extends React.Component {
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
.map(key => key + '=' + extraParams[key])
.join('&');
// send request to the invoker
axios.get(
window.location.origin + config.serverConfig.invoker.uri +
axios
.get(
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/devices?" + encodedExtraParams,
).then(res => {
'/devices?' +
encodedExtraParams,
)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
loading: false,
data: res.data.data.devices,
pagination
pagination,
});
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to load devices.",
description: 'Error occurred while trying to load devices.',
});
}
@ -219,21 +227,25 @@ class UsersDevices extends React.Component {
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { data, pagination, loading } = this.state;
return (
<div>
<Table
columns={columns}
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
rowKey={record =>
record.deviceIdentifier +
record.enrolmentInfo.owner +
record.enrolmentInfo.ownership
}
dataSource={data}
showHeader={false}
size="small"
pagination={{
...pagination,
size: "small",
size: 'small',
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} devices`,
// showQuickJumper: true
}}
loading={loading}

View File

@ -16,46 +16,43 @@
* 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'
placeholder: 'Username',
},
{
name: 'firstName',
placeholder: 'First Name'
placeholder: 'First Name',
},
{
name: 'lastName',
placeholder: 'Last Name'
placeholder: 'Last Name',
},
{
name: 'emailAddress',
placeholder: 'Email Address'
placeholder: 'Email Address',
},
];
class UsersTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
@ -65,16 +62,16 @@ class UsersTable extends React.Component {
rolesModalVisible: false,
devicesModalVisible: false,
rolesData: [],
user:''
user: '',
};
}
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
selectedRows: selectedRows
})
}
selectedRows: selectedRows,
});
},
};
componentDidMount() {
@ -87,23 +84,29 @@ class UsersTable extends React.Component {
this.setState({ loading: true });
// get current page
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
const extraParams = {
offset: 10 * (currentPage - 1), // calculate the offset
limit: 10,
...filters
...filters,
};
const encodedExtraParams = Object.keys(extraParams)
.map(key => key + '=' + extraParams[key]).join('&');
.map(key => key + '=' + extraParams[key])
.join('&');
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/users/search?" + encodedExtraParams;
'/users/search?' +
encodedExtraParams;
// send request to the invokerss
axios.get(apiUrl).then(res => {
axios
.get(apiUrl)
.then(res => {
if (res.status === 200) {
const pagination = { ...this.state.pagination };
this.setState({
@ -112,19 +115,19 @@ class UsersTable extends React.Component {
pagination,
});
console.log(res.data.data)
console.log(res.data.data);
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load users.",
description: 'Error occurred while trying to load users.',
});
}
@ -132,35 +135,41 @@ class UsersTable extends React.Component {
});
};
fetchRoles = (username) => {
fetchRoles = username => {
const config = this.props.context;
this.setState({
rolesModalVisible: true,
user: username
user: username,
});
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
apiUrl =
window.location.origin +
config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
"/users/" + username + "/roles";
'/users/' +
username +
'/roles';
axios.get(apiUrl).then(res => {
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) {
})
.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",
notification.error({
message: 'There was a problem',
duration: 0,
description:"Error occurred while trying to load roles.",
description: 'Error occurred while trying to load roles.',
});
}
@ -186,32 +195,30 @@ class UsersTable extends React.Component {
handleOk = e => {
this.setState({
rolesModalVisible: false,
devicesModalVisible: false
devicesModalVisible: false,
});
};
handleCancel = e => {
this.setState({
rolesModalVisible: false,
devicesModalVisible: false
devicesModalVisible: false,
});
};
openDeviceListModal = e => {
this.setState({
devicesModalVisible: true,
})
});
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
const { Panel } = Collapse;
const { TabPane } = Tabs;
const { data, pagination, loading } = this.state;
const columns = [
{
title: 'User Name',
dataIndex: 'username',
key: "username",
key: 'username',
},
{
title: 'First Name',
@ -232,19 +239,26 @@ class UsersTable extends React.Component {
title: 'View',
dataIndex: 'username',
key: 'roles',
render: (username) =>
render: username => (
<ButtonGroup>
<Button
type="primary"
size={"small"}
size={'small'}
icon="book"
onClick={() => this.fetchRoles(username)}>Roles</Button>
onClick={() => this.fetchRoles(username)}
>
Roles
</Button>
<Button
type="primary"
size={"small"}
size={'small'}
icon="desktop"
onClick={this.openDeviceListModal}>Devices</Button>
onClick={this.openDeviceListModal}
>
Devices
</Button>
</ButtonGroup>
),
},
{
title: 'Action',
@ -256,7 +270,6 @@ class UsersTable extends React.Component {
</span>
),
},
];
return (
<div>
@ -266,16 +279,17 @@ class UsersTable extends React.Component {
<div style={{ textAlign: 'right' }}>
<Filter fields={searchFields} callback={this.fetchUsers} />
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<Table
columns={columns}
rowKey={record => (record.username)}
rowKey={record => record.username}
dataSource={data}
pagination={{
...pagination,
size: "small",
size: 'small',
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
showTotal: (total, range) =>
`showing ${range[0]}-${range[1]} of ${total} groups`,
// showQuickJumper: true
}}
loading={loading}
@ -289,13 +303,15 @@ class UsersTable extends React.Component {
width="900px"
visible={this.state.rolesModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel} >
onCancel={this.handleCancel}
>
<div>
<List
size="small"
bordered
dataSource={this.state.rolesData}
renderItem={item => <List.Item>{item}</List.Item>}/>
renderItem={item => <List.Item>{item}</List.Item>}
/>
</div>
</Modal>
</div>
@ -306,7 +322,8 @@ class UsersTable extends React.Component {
width="900px"
visible={this.state.devicesModalVisible}
onOk={this.handleOk}
onCancel={this.handleCancel}>
onCancel={this.handleCancel}
>
<div>
<UsersDevices user={this.state.user} />
</div>

View File

@ -1,17 +1,15 @@
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]);
Object.keys(values).forEach(
key => values[key] === undefined && delete values[key],
);
this.props.callback({}, values);
}
});
@ -20,10 +18,9 @@ class HorizontalLoginForm extends React.Component {
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form layout="inline" onSubmit={this.handleSubmit}>
{this.props.fields.map((field) => (
{this.props.fields.map(field => (
<Form.Item key={field.name}>
{getFieldDecorator(field.name)(
<Input placeholder={field.placeholder} />,
@ -31,7 +28,7 @@ class HorizontalLoginForm extends React.Component {
</Form.Item>
))}
<Form.Item>
<Button htmlType='submit' shape="circle" icon="search" />
<Button htmlType="submit" shape="circle" icon="search" />
</Form.Item>
</Form>
);

View File

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

View File

@ -19,30 +19,31 @@
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',
exact: true,
component: Login
component: Login,
},
{
path: '/entgra',
@ -52,86 +53,83 @@ const routes = [
{
path: '/entgra/devices',
component: Devices,
exact: true
exact: true,
},
{
path: '/entgra/devices/enroll',
component: DeviceEnroll,
exact: true
exact: true,
},
{
path: '/entgra/geo',
component: Geo,
exact: true
exact: true,
},
{
path: '/entgra/reports',
component: Reports,
exact: true
exact: true,
},
{
path: '/entgra/groups',
component: Groups,
exact: true
exact: true,
},
{
path: '/entgra/users',
component: Users,
exact: true
exact: true,
},
{
path: '/entgra/policies',
component: Policies,
exact: true
exact: true,
},
{
path: '/entgra/policy/add',
component: AddNewPolicy,
exact: true
exact: true,
},
{
path: '/entgra/roles',
component: Roles,
exact: true
exact: true,
},
{
path: '/entgra/devicetypes',
component: DeviceTypes,
exact: true
exact: true,
},
{
path: '/entgra/certificates',
component: Certificates,
exact: true
exact: true,
},
{
path: '/entgra/reportList',
component: ReportDurationItemList,
exact: true
exact: true,
},
{
path: '/entgra/enrollmentsvsunenrollments',
component: EnrollmentsVsUnenrollmentsReport,
exact: true
exact: true,
},
{
path: '/entgra/enrollmenttype',
component: EnrollmentTypeReport,
exact: true
exact: true,
},
{
path: '/entgra/devicestatus',
component: DeviceStatusReport,
exact: true
}
]
}
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,16 +16,10 @@
* 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;
@ -43,7 +37,9 @@ class Certificates extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
<Link to="/entgra/devices">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Configurations</Breadcrumb.Item>
<Breadcrumb.Item>Certificates</Breadcrumb.Item>
@ -52,13 +48,13 @@ class Certificates extends React.Component {
<h3>Certificates</h3>
<Paragraph>Certificate configurations</Paragraph>
</div>
<div style={{backgroundColor: "#ffffff", borderRadius: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<CertificateTable />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,37 +16,37 @@
* under the License.
*/
import React from "react";
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 { 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 { Header, Content, Footer } = Layout;
const { SubMenu } = Menu;
class Dashboard extends React.Component {
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
mobileWidth,
};
this.logo = this.props.context.theme.logo;
this.config = this.props.context;
}
toggle = () => {
console.log(this.config)
console.log(this.config);
this.setState({
isNavBarCollapsed: !this.state.isNavBarCollapsed,
});
@ -59,7 +59,9 @@ class Dashboard extends React.Component {
<Layout>
<Header style={{ background: '#fff', padding: 0 }}>
<div className="logo-image">
<Link to="/entgra/devices"><img alt="logo" src={this.logo}/></Link>
<Link to="/entgra/devices">
<img alt="logo" src={this.logo} />
</Link>
</div>
<Menu
@ -67,7 +69,7 @@ class Dashboard extends React.Component {
mode="horizontal"
style={{
lineHeight: '64px',
marginRight: 110
marginRight: 110,
}}
>
<SubMenu
@ -76,7 +78,8 @@ class Dashboard extends React.Component {
<span>
<Icon type="appstore" />
<span>Devices</span>
</span>}
</span>
}
>
<Menu.Item key="devices">
<Link to="/entgra/devices">
@ -95,7 +98,8 @@ class Dashboard extends React.Component {
<span>
<Icon type="environment" />
<span>Geo</span>
</span>}
</span>
}
>
<Menu.Item key="singleDevice">
<Link to="/entgra/geo">
@ -132,7 +136,8 @@ class Dashboard extends React.Component {
<span>
<Icon type="audit" />
<span>Policies</span>
</span>}
</span>
}
>
<Menu.Item key="policiesList">
<Link to="/entgra/policies">
@ -163,7 +168,8 @@ class Dashboard extends React.Component {
<span>
<Icon type="setting" />
<span>Configurations</span>
</span>}
</span>
}
>
<Menu.Item key="certificates">
<Link to="/entgra/certificates">
@ -171,33 +177,31 @@ class Dashboard extends React.Component {
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="trigger">
</Menu.Item>
<SubMenu className="profile"
<Menu.Item key="trigger"></Menu.Item>
<SubMenu
className="profile"
title={
<span className="submenu-title-wrapper">
<Icon type="user" />
{this.config.user}
</span> }>
</span>
}
>
<Logout />
</SubMenu>
</Menu>
</Header>
<Content style={{ marginTop: 10 }}>
<Switch>
<Redirect exact from="/entgra" to="/entgra/devices" />
{this.state.routes.map((route) => (
{this.state.routes.map(route => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>
</Content>
<Footer style={{textAlign: 'center'}}>
©2019 entgra.io
</Footer>
<Footer style={{ textAlign: 'center' }}>©2019 entgra.io</Footer>
</Layout>
</Layout>
</div>

View File

@ -16,15 +16,10 @@
* 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;
@ -42,7 +37,9 @@ class DeviceTypes extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Device Types</Breadcrumb.Item>
</Breadcrumb>
@ -50,13 +47,13 @@ class DeviceTypes extends React.Component {
<h3>Device Types</h3>
<Paragraph>All device types for device management.</Paragraph>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<DeviceTypesTable />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -1,13 +1,7 @@
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;
@ -25,9 +19,13 @@ class DeviceEnroll extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
<Link to="/entgra/devices">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>
<Link to="/entgra/devices">Devices</Link>
</Breadcrumb.Item>
<Breadcrumb.Item><Link to="/entgra/devices">Devices</Link></Breadcrumb.Item>
<Breadcrumb.Item>Enroll Device</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
@ -38,10 +36,9 @@ class DeviceEnroll extends React.Component {
<AddDevice />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,16 +16,10 @@
* 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;
@ -43,7 +37,9 @@ class Devices extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
<Link to="/entgra/devices">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Devices</Breadcrumb.Item>
</Breadcrumb>
@ -51,13 +47,13 @@ class Devices extends React.Component {
<h3>Devices</h3>
<Paragraph>All enrolled devices</Paragraph>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<DeviceTable />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,16 +16,10 @@
* 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;
@ -35,7 +29,6 @@ class Geo extends React.Component {
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
@ -44,7 +37,9 @@ class Geo extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Geo</Breadcrumb.Item>
</Breadcrumb>
@ -53,7 +48,14 @@ class Geo extends React.Component {
<Paragraph>Geo Location Service</Paragraph>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720, alignItems: "center"}}>
<div
style={{
background: '#f0f2f5',
padding: 24,
minHeight: 720,
alignItems: 'center',
}}
>
<GeoDashboard />
</div>
</div>

View File

@ -16,15 +16,10 @@
* 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;
@ -42,7 +37,9 @@ class Groups extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Groups</Breadcrumb.Item>
</Breadcrumb>

View File

@ -16,53 +16,51 @@
* under the License.
*/
import React from "react";
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
loading: false,
};
}
/*
This function call the logout api when the request is success
*/
handleSubmit = () => {
const thisForm = this;
const config = this.props.context;
thisForm.setState({
inValid: false
inValid: false,
});
axios.post(window.location.origin + config.serverConfig.logoutUri
).then(res => {
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";
window.location = window.location.origin + '/entgra/login';
}
}).catch(function (error) {
if (error.hasOwnProperty("response") && error.response.status === 400) {
})
.catch(function(error) {
if (error.hasOwnProperty('response') && error.response.status === 400) {
thisForm.setState({
inValid: true
inValid: true,
});
} else {
notification["error"]({
message: "There was a problem",
notification.error({
message: 'There was a problem',
duration: 0,
description:
"Error occurred while trying to logout.",
description: 'Error occurred while trying to logout.',
});
}
});
@ -71,7 +69,10 @@ class Logout extends React.Component {
render() {
return (
<Menu>
<Menu.Item key="1" onClick={this.handleSubmit}><Icon type="logout"/>Logout</Menu.Item>
<Menu.Item key="1" onClick={this.handleSubmit}>
<Icon type="logout" />
Logout
</Menu.Item>
</Menu>
);
}

View File

@ -16,15 +16,10 @@
* 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;
@ -42,7 +37,9 @@ class AddNewPolicy extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Policies</Breadcrumb.Item>
</Breadcrumb>
@ -54,9 +51,9 @@ class AddNewPolicy extends React.Component {
<AddPolicy />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,15 +16,10 @@
* 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;
@ -42,7 +37,9 @@ class Policies extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Policies</Breadcrumb.Item>
</Breadcrumb>
@ -50,13 +47,13 @@ class Policies extends React.Component {
<h3>Policies</h3>
<Paragraph>All policies for device management</Paragraph>
</div>
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
<PoliciesTable />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,136 +16,180 @@
* 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"]
}
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')]}]
{
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) =>
let itemStatus = this.durationItemArray.map(data => (
<Col key={data.name} span={6}>
<Link
to={{
// Path to respective report page
pathname: "/entgra/devicestatus",
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>
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) =>
let itemEnrollmentsVsUnenrollments = this.durationItemArray.map(data => (
<Col key={data.name} span={6}>
<Link
to={{
// Path to respective report page
pathname: "/entgra/enrollmentsvsunenrollments",
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>
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) =>
let itemEnrollmentType = this.durationItemArray.map(data => (
<Col key={data.name} span={6}>
<Link
to={{
// Path to respective report page
pathname: "/entgra/enrollmenttype",
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>
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>
<Row gutter={16}>{itemStatus}</Row>
</div>
<div style={{ borderRadius: 5 }}>
<Row gutter={16} >
{itemEnrollmentsVsUnenrollments}
</Row>
<Row gutter={16}>{itemEnrollmentsVsUnenrollments}</Row>
</div>
<div style={{ borderRadius: 5 }}>
<Row gutter={16} >
{itemEnrollmentType}
</Row>
<Row gutter={16}>{itemEnrollmentType}</Row>
</div>
</div>
)
);
}
}

View File

@ -16,17 +16,10 @@
* 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;
@ -36,7 +29,7 @@ class Reports extends React.Component {
this.routes = props.routes;
this.state = {
paramsObject: {},
}
};
}
// Get modified value from datepicker and set it to paramsObject
updateDurationValue = (modifiedFromDate, modifiedToDate) => {
@ -49,14 +42,14 @@ class Reports extends React.Component {
// Get modified value from filters and set it to paramsObject
updateFiltersValue = (modifiedValue, filterType) => {
let tempParamObj = this.state.paramsObject;
if(filterType=="Device Status"){
if (filterType == 'Device Status') {
tempParamObj.status = modifiedValue;
if(modifiedValue=="ALL" && tempParamObj.status){
if (modifiedValue == 'ALL' && tempParamObj.status) {
delete tempParamObj.status;
}
} else {
tempParamObj.ownership = modifiedValue;
if(modifiedValue=="ALL" && tempParamObj.ownership){
if (modifiedValue == 'ALL' && tempParamObj.ownership) {
delete tempParamObj.ownership;
}
}
@ -64,18 +57,14 @@ class Reports extends React.Component {
};
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>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Reports</Breadcrumb.Item>
</Breadcrumb>
@ -84,9 +73,9 @@ class Reports extends React.Component {
<ReportDurationItemList />
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,15 +16,10 @@
* 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;
@ -42,7 +37,9 @@ class Roles extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Roles</Breadcrumb.Item>
</Breadcrumb>

View File

@ -16,15 +16,10 @@
* 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;
@ -42,7 +37,9 @@ class Users extends React.Component {
<PageHeader style={{ paddingTop: 0 }}>
<Breadcrumb style={{ paddingBottom: 16 }}>
<Breadcrumb.Item>
<Link to="/entgra"><Icon type="home"/> Home</Link>
<Link to="/entgra">
<Icon type="home" /> Home
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Users</Breadcrumb.Item>
</Breadcrumb>
@ -52,9 +49,9 @@ class Users extends React.Component {
</div>
<UsersTable />
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
<div
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
></div>
</div>
);
}

View File

@ -16,11 +16,20 @@
* 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;
@ -30,53 +39,45 @@ class Login extends React.Component {
const config = this.props.context;
return (
<div>
<div className="background">
</div>
<div className="background"></div>
<div className="content">
<Row>
<Col xs={3} sm={3} md={10}>
</Col>
<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={
{
<Col style={{ textAlign: 'center' }}>
<img
style={{
marginTop: 36,
height: 60
}
}
src={config.theme.logo}/>
height: 60,
}}
src={config.theme.logo}
/>
</Col>
</Row>
<Title level={2}>Login</Title>
<WrappedNormalLoginForm />
</Col>
</Row>
<Row>
<Col span={4} offset={10}>
</Col>
<Col span={4} offset={10}></Col>
</Row>
</div>
</div>
);
}
}
class NormalLoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
inValid: false,
loading: false
loading: false,
};
}
handleSubmit = (e) => {
handleSubmit = e => {
const thisForm = this;
const config = this.props.context;
console.log(config);
@ -84,50 +85,53 @@ class NormalLoginForm extends React.Component {
e.preventDefault();
this.props.form.validateFields((err, values) => {
thisForm.setState({
inValid: false
inValid: false,
});
if (!err) {
thisForm.setState({
loading: true
loading: true,
});
const parameters = {
username: values.username,
password: values.password,
platform: "entgra"
platform: 'entgra',
};
const request = Object.keys(parameters).map(key => key + '=' + parameters[key]).join('&');
const request = Object.keys(parameters)
.map(key => key + '=' + parameters[key])
.join('&');
axios.post(window.location.origin+ config.serverConfig.loginUri, request
).then(res => {
axios
.post(window.location.origin + config.serverConfig.loginUri, request)
.then(res => {
if (res.status === 200) {
let redirectUrl = window.location.origin + "/entgra";
let redirectUrl = window.location.origin + '/entgra';
const searchParams = new URLSearchParams(window.location.search);
if (searchParams.has("redirect")) {
redirectUrl = searchParams.get("redirect");
if (searchParams.has('redirect')) {
redirectUrl = searchParams.get('redirect');
}
window.location = redirectUrl;
}
}).catch(function (error) {
})
.catch(function(error) {
if (error.response.status === 400) {
thisForm.setState({
inValid: true,
loading: false
loading: false,
});
}
});
}
});
};
render() {
const { getFieldDecorator } = this.props.form;
let errorMsg = "";
let errorMsg = '';
if (this.state.inValid) {
errorMsg = <Text type="danger">Invalid Login Details</Text>;
}
let loading = "";
let loading = '';
if (this.state.loading) {
loading = <Text type="secondary">Loading..</Text>;
}
@ -137,18 +141,25 @@ class NormalLoginForm extends React.Component {
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input name="username" style={{height: 32}}
<Input
name="username"
style={{ height: 32 }}
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username"/>
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"/>
<Input
name="password"
style={{ height: 32 }}
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
type="password"
placeholder="Password"
/>,
)}
</Form.Item>
{loading}
@ -157,12 +168,18 @@ class NormalLoginForm extends React.Component {
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(
<Checkbox>Remember me</Checkbox>
)}
})(<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">
<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>
@ -171,6 +188,8 @@ class NormalLoginForm extends React.Component {
}
}
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,22 +16,22 @@
* 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",
devtool: 'source-map',
output: {
publicPath: '/entgra/'
publicPath: '/entgra/',
},
watch: false,
resolve: {
alias: {
AppData: path.resolve(__dirname, 'source/src/app/common/'),
AppComponents: path.resolve(__dirname, 'source/src/app/components/')
AppComponents: path.resolve(__dirname, 'source/src/app/components/'),
},
extensions: ['.jsx', '.js', '.ttf', '.woff', '.woff2', '.svg']
extensions: ['.jsx', '.js', '.ttf', '.woff', '.woff2', '.svg'],
},
module: {
rules: [
@ -40,47 +40,47 @@ const config = {
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
loader: 'babel-loader',
},
],
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
loader: 'html-loader',
options: { minimize: true },
},
],
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader"
]
'css-loader',
'postcss-loader',
'sass-loader',
],
},
{
test: /\.scss$/,
use: [ 'style-loader', 'scss-loader' ]
use: ['style-loader', 'scss-loader'],
},
{
test: /\.less$/,
use: [
{
loader: "style-loader"
loader: 'style-loader',
},
{
loader: "css-loader",
loader: 'css-loader',
},
{
loader: "less-loader",
loader: 'less-loader',
options: {
modifyVars: {
'primary-color': configurations.theme.primaryColor,
@ -88,8 +88,8 @@ const config = {
},
javascriptEnabled: true,
},
}
]
},
],
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
@ -99,35 +99,35 @@ const config = {
test: /\.(png|jpe?g)/i,
use: [
{
loader: "url-loader",
loader: 'url-loader',
options: {
name: "./img/[name].[ext]",
limit: 10000
}
name: './img/[name].[ext]',
limit: 10000,
},
},
{
loader: "img-loader"
}
]
}
]
loader: 'img-loader',
},
],
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
template: './src/index.html',
filename: './index.html',
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
externals: {
'Config': JSON.stringify(require('./public/conf/config.json'))
}
Config: JSON.stringify(require('./public/conf/config.json')),
},
};
if (process.env.NODE_ENV === "development") {
if (process.env.NODE_ENV === 'development') {
config.watch = true;
}