mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
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:
commit
c34811f0e7
@ -82,6 +82,16 @@
|
|||||||
<arguments>install</arguments>
|
<arguments>install</arguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>lint</id>
|
||||||
|
<goals>
|
||||||
|
<goal>npm</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<arguments>run-script lint</arguments>
|
||||||
|
</configuration>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<id>prod</id>
|
<id>prod</id>
|
||||||
<goals>
|
<goals>
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"parser": "flow"
|
||||||
|
}
|
||||||
@ -16,14 +16,13 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = function (api) {
|
module.exports = function(api) {
|
||||||
api.cache(true);
|
api.cache(true);
|
||||||
const presets = [ "@babel/preset-env",
|
const presets = ['@babel/preset-env', '@babel/preset-react'];
|
||||||
"@babel/preset-react" ];
|
const plugins = ['@babel/plugin-proposal-class-properties'];
|
||||||
const plugins = ["@babel/plugin-proposal-class-properties"];
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
presets,
|
presets,
|
||||||
plugins
|
plugins,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
"acorn": "^6.2.0",
|
"acorn": "^6.2.0",
|
||||||
"antd": "^3.23.5",
|
"antd": "^3.23.5",
|
||||||
"axios": "^0.18.1",
|
"axios": "^0.18.1",
|
||||||
|
"babel-eslint": "^9.0.0",
|
||||||
"bizcharts": "^3.5.6",
|
"bizcharts": "^3.5.6",
|
||||||
"bootstrap": "^4.3.1",
|
"bootstrap": "^4.3.1",
|
||||||
"javascript-time-ago": "^2.0.1",
|
"javascript-time-ago": "^2.0.1",
|
||||||
@ -46,6 +47,12 @@
|
|||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"chai": "^4.1.2",
|
"chai": "^4.1.2",
|
||||||
"css-loader": "^0.28.11",
|
"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": "^4.17.1",
|
||||||
"express-pino-logger": "^4.0.0",
|
"express-pino-logger": "^4.0.0",
|
||||||
"file-loader": "^2.0.0",
|
"file-loader": "^2.0.0",
|
||||||
@ -64,6 +71,7 @@
|
|||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"pino-colada": "^1.4.5",
|
"pino-colada": "^1.4.5",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
|
"prettier": "1.18.1",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-intl": "^2.9.0",
|
"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_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 ",
|
"build_dev": "NODE_ENV=development webpack -d --watch ",
|
||||||
"server": "node-env-run server --exec nodemon | pino-colada",
|
"server": "node-env-run server --exec nodemon | pino-colada",
|
||||||
"dev2": "run-p server start"
|
"dev2": "run-p server start",
|
||||||
|
"lint": "eslint \"src/**/*.js\""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,153 +16,156 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import "antd/dist/antd.less";
|
import 'antd/dist/antd.less';
|
||||||
import RouteWithSubRoutes from "./components/RouteWithSubRoutes";
|
import RouteWithSubRoutes from './components/RouteWithSubRoutes';
|
||||||
import {
|
import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
|
||||||
BrowserRouter as Router,
|
import axios from 'axios';
|
||||||
Redirect, Switch,
|
import { Layout, Spin, Result, notification } from 'antd';
|
||||||
} from 'react-router-dom';
|
import ConfigContext from './context/ConfigContext';
|
||||||
import axios from "axios";
|
|
||||||
import {Layout, Spin, Result, message, notification} from "antd";
|
|
||||||
import ConfigContext from "./context/ConfigContext";
|
|
||||||
|
|
||||||
const {Content} = Layout;
|
const { Content } = Layout;
|
||||||
const loadingView = (
|
const loadingView = (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Content style={{
|
<Content
|
||||||
padding: '0 0',
|
style={{
|
||||||
paddingTop: 300,
|
padding: '0 0',
|
||||||
backgroundColor: '#fff',
|
paddingTop: 300,
|
||||||
textAlign: 'center'
|
backgroundColor: '#fff',
|
||||||
}}>
|
textAlign: 'center',
|
||||||
<Spin tip="Loading..."/>
|
}}
|
||||||
</Content>
|
>
|
||||||
</Layout>
|
<Spin tip="Loading..." />
|
||||||
|
</Content>
|
||||||
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|
||||||
const errorView = (
|
const errorView = (
|
||||||
<Result
|
<Result
|
||||||
style={{
|
style={{
|
||||||
paddingTop: 200
|
paddingTop: 200,
|
||||||
}}
|
}}
|
||||||
status="500"
|
status="500"
|
||||||
title="Error occurred while loading the configuration"
|
title="Error occurred while loading the configuration"
|
||||||
subTitle="Please refresh your browser window"
|
subTitle="Please refresh your browser window"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
error: false,
|
||||||
|
config: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
componentDidMount() {
|
||||||
super(props);
|
axios
|
||||||
this.state = {
|
.get(window.location.origin + '/entgra/public/conf/config.json')
|
||||||
loading: true,
|
.then(res => {
|
||||||
error: false,
|
const config = res.data;
|
||||||
config: {}
|
this.checkUserLoggedIn(config);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
error: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkUserLoggedIn = config => {
|
||||||
|
axios
|
||||||
|
.post(
|
||||||
|
window.location.origin + '/entgra-ui-request-handler/user',
|
||||||
|
'platform=entgra',
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
config.user = res.data.data;
|
||||||
|
const pageURL = window.location.pathname;
|
||||||
|
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
||||||
|
if (lastURLSegment === 'login') {
|
||||||
|
window.location.href = window.location.origin + '/entgra/';
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
config: config,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
this.getDeviceTypes(config);
|
||||||
|
})
|
||||||
componentDidMount() {
|
.catch(error => {
|
||||||
axios.get(
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
window.location.origin + "/entgra/public/conf/config.json",
|
const redirectUrl = encodeURI(window.location.href);
|
||||||
).then(res => {
|
const pageURL = window.location.pathname;
|
||||||
const config = res.data;
|
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
||||||
this.checkUserLoggedIn(config);
|
if (lastURLSegment !== 'login') {
|
||||||
}).catch((error) => {
|
window.location.href =
|
||||||
|
window.location.origin + `/entgra/login?redirect=${redirectUrl}`;
|
||||||
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
error: true
|
config: config,
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
checkUserLoggedIn = (config) => {
|
|
||||||
axios.post(
|
|
||||||
window.location.origin + "/entgra-ui-request-handler/user",
|
|
||||||
"platform=entgra"
|
|
||||||
).then(res => {
|
|
||||||
config.user = res.data.data;
|
|
||||||
const pageURL = window.location.pathname;
|
|
||||||
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
|
||||||
if (lastURLSegment === "login") {
|
|
||||||
window.location.href = window.location.origin + `/entgra/`;
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
config: config
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.getDeviceTypes(config);
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
const redirectUrl = encodeURI(window.location.href);
|
|
||||||
const pageURL = window.location.pathname;
|
|
||||||
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
|
||||||
if (lastURLSegment !== "login") {
|
|
||||||
window.location.href = window.location.origin + `/entgra/login?redirect=${redirectUrl}`;
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
config: config
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
error: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getDeviceTypes = (config) => {
|
|
||||||
axios.get(
|
|
||||||
window.location.origin + "/entgra-ui-request-handler/invoke/device-mgt/v1.0/device-types",
|
|
||||||
).then(res => {
|
|
||||||
config.deviceTypes = JSON.parse(res.data.data);
|
|
||||||
this.setState({
|
|
||||||
config: config,
|
|
||||||
loading: false
|
|
||||||
});
|
});
|
||||||
}).catch((error) => {
|
}
|
||||||
|
} else {
|
||||||
notification["error"]({
|
this.setState({
|
||||||
message: "There was a problem",
|
loading: false,
|
||||||
duration: 0,
|
error: true,
|
||||||
description:"Error occurred while trying to load device types.",
|
});
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getDeviceTypes = config => {
|
||||||
|
axios
|
||||||
|
.get(
|
||||||
|
window.location.origin +
|
||||||
|
'/entgra-ui-request-handler/invoke/device-mgt/v1.0/device-types',
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
config.deviceTypes = JSON.parse(res.data.data);
|
||||||
|
this.setState({
|
||||||
|
config: config,
|
||||||
|
loading: false,
|
||||||
});
|
});
|
||||||
};
|
})
|
||||||
|
.catch(error => {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load device types.',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {loading, error} = this.state;
|
const { loading, error } = this.state;
|
||||||
|
const applicationView = (
|
||||||
|
<Router>
|
||||||
|
<ConfigContext.Provider value={this.state.config}>
|
||||||
|
<div>
|
||||||
|
<Switch>
|
||||||
|
<Redirect exact from="/entgra" to="/entgra/devices" />
|
||||||
|
{this.props.routes.map(route => (
|
||||||
|
<RouteWithSubRoutes key={route.path} {...route} />
|
||||||
|
))}
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
</ConfigContext.Provider>
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
|
||||||
const abc = this.state.deviceTypes;
|
return (
|
||||||
const applicationView = (
|
<div>
|
||||||
<Router>
|
{loading && loadingView}
|
||||||
<ConfigContext.Provider value={this.state.config}>
|
{!loading && !error && applicationView}
|
||||||
<div>
|
{error && errorView}
|
||||||
<Switch>
|
</div>
|
||||||
<Redirect exact from="/entgra" to="/entgra/devices"/>
|
);
|
||||||
{this.props.routes.map((route) => (
|
}
|
||||||
<RouteWithSubRoutes key={route.path} {...route} />
|
|
||||||
))}
|
|
||||||
</Switch>
|
|
||||||
</div>
|
|
||||||
</ConfigContext.Provider>
|
|
||||||
</Router>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{loading && loadingView}
|
|
||||||
{!loading && !error && applicationView}
|
|
||||||
{error && errorView}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@ -16,217 +16,247 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {Icon, message, Modal, notification, Popconfirm, Select, Table, Tag, Tooltip, Typography} from "antd";
|
import {
|
||||||
import TimeAgo from 'javascript-time-ago'
|
Icon,
|
||||||
|
message,
|
||||||
|
notification,
|
||||||
|
Popconfirm,
|
||||||
|
Table,
|
||||||
|
Tooltip,
|
||||||
|
Typography,
|
||||||
|
} from 'antd';
|
||||||
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../../context/ConfigContext";
|
import { withConfigContext } from '../../../context/ConfigContext';
|
||||||
import Moment from "react-moment";
|
import Moment from 'react-moment';
|
||||||
|
|
||||||
const {Paragraph, Text} = Typography;
|
const { Paragraph, Text } = Typography;
|
||||||
|
|
||||||
let config = null;
|
let config = null;
|
||||||
|
|
||||||
class CertificateTable extends React.Component {
|
class CertificateTable extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
config = this.props.context;
|
||||||
TimeAgo.addLocale(en);
|
TimeAgo.addLocale(en);
|
||||||
this.state = {
|
this.state = {
|
||||||
data: [],
|
data: [],
|
||||||
pagination: {},
|
pagination: {},
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
// get current page
|
||||||
|
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (currentPage - 1), // calculate the offset
|
||||||
|
limit: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
const encodedExtraParams = Object.keys(extraParams)
|
||||||
|
.map(key => key + '=' + extraParams[key])
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
// send request to the invoker
|
||||||
|
axios
|
||||||
|
.get(
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
'/certificate-mgt/v1.0/admin/certificates' +
|
||||||
|
encodedExtraParams,
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
data: res.data.data.certificates,
|
||||||
}
|
pagination,
|
||||||
|
});
|
||||||
componentDidMount() {
|
}
|
||||||
this.fetch();
|
})
|
||||||
}
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
//fetch data from api
|
// todo display a popop with error
|
||||||
fetch = (params = {}) => {
|
message.error('You are not logged in');
|
||||||
this.setState({loading: true});
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
// get current page
|
} else {
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
const extraParams = {
|
duration: 0,
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
description: 'Error occurred while trying to load devices.',
|
||||||
limit: 10,
|
});
|
||||||
requireDeviceInfo: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
|
||||||
|
|
||||||
//send request to the invoker
|
|
||||||
axios.get(
|
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
'/certificate-mgt/v1.0/admin/certificates',
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
const pagination = {...this.state.pagination};
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
data: res.data.data.certificates,
|
|
||||||
pagination
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to load devices.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = {...this.state.pagination};
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetch({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
deleteCertificate = (serialNumber) =>{
|
|
||||||
axios.delete(
|
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
'/certificate-mgt/v1.0/admin/certificates/'+ serialNumber,
|
|
||||||
{headers: {'Content-Type': 'application/json'}}
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetch();
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully deleted the certificate.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to delete the certificate.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
columns = [
|
|
||||||
{
|
|
||||||
title: 'Serial Number',
|
|
||||||
dataIndex: 'serialNumber'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Username',
|
|
||||||
dataIndex: 'username'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Certificate Version',
|
|
||||||
dataIndex: 'certificateVersion'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Certificate Serial',
|
|
||||||
dataIndex: 'certificateserial'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Not Before',
|
|
||||||
dataIndex: 'notBefore',
|
|
||||||
render: notBefore => (
|
|
||||||
<Moment format="YYYY/MM/DD HH:mm" date={notBefore} />
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Not After',
|
|
||||||
dataIndex: 'notAfter',
|
|
||||||
render: notAfter => (
|
|
||||||
<Moment format="YYYY/MM/DD HH:mm" date={notAfter} />
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Subject',
|
|
||||||
dataIndex: 'subject',
|
|
||||||
render: subject => (
|
|
||||||
<Paragraph style={{marginBottom: 0}} ellipsis={{rows:1, expandable: true}}>{subject}</Paragraph>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Issuer',
|
|
||||||
dataIndex: 'issuer',
|
|
||||||
render: issuer => (
|
|
||||||
<Paragraph style={{marginBottom: 0}} ellipsis={{rows:1, expandable: true}}>{issuer}</Paragraph>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Actions',
|
|
||||||
key: 'actions',
|
|
||||||
dataIndex: 'serialNumber',
|
|
||||||
render: (serialNumber) => (
|
|
||||||
<Tooltip placement="bottom" title={"Remove User"}>
|
|
||||||
<Popconfirm
|
|
||||||
placement="top"
|
|
||||||
title={"Are you sure?"}
|
|
||||||
onConfirm={() => {this.deleteCertificate(serialNumber)}}
|
|
||||||
okText="Ok"
|
|
||||||
cancelText="Cancel">
|
|
||||||
<a><Text type="danger"><Icon type="delete"/></Text></a>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
];
|
|
||||||
|
|
||||||
render() {
|
this.setState({ loading: false });
|
||||||
const {data, pagination, loading} = this.state;
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
<div>
|
const pager = { ...this.state.pagination };
|
||||||
<div>
|
pager.current = pagination.current;
|
||||||
<Table
|
this.setState({
|
||||||
columns={this.columns}
|
pagination: pager,
|
||||||
rowKey={record => record.serialNumber}
|
});
|
||||||
dataSource={data}
|
this.fetch({
|
||||||
pagination={{
|
results: pagination.pageSize,
|
||||||
...pagination,
|
page: pagination.current,
|
||||||
size: "small",
|
sortField: sorter.field,
|
||||||
// position: "top",
|
sortOrder: sorter.order,
|
||||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
|
...filters,
|
||||||
// showQuickJumper: true
|
});
|
||||||
}}
|
};
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
deleteCertificate = serialNumber => {
|
||||||
/>
|
axios
|
||||||
</div>
|
.delete(
|
||||||
</div>
|
window.location.origin +
|
||||||
);
|
config.serverConfig.invoker.uri +
|
||||||
}
|
'/certificate-mgt/v1.0/admin/certificates/' +
|
||||||
|
serialNumber,
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.fetch();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully deleted the certificate.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
'Error occurred while trying to delete the certificate.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
columns = [
|
||||||
|
{
|
||||||
|
title: 'Serial Number',
|
||||||
|
dataIndex: 'serialNumber',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Username',
|
||||||
|
dataIndex: 'username',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Certificate Version',
|
||||||
|
dataIndex: 'certificateVersion',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Certificate Serial',
|
||||||
|
dataIndex: 'certificateserial',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Not Before',
|
||||||
|
dataIndex: 'notBefore',
|
||||||
|
render: notBefore => (
|
||||||
|
<Moment format="YYYY/MM/DD HH:mm" date={notBefore} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Not After',
|
||||||
|
dataIndex: 'notAfter',
|
||||||
|
render: notAfter => <Moment format="YYYY/MM/DD HH:mm" date={notAfter} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Subject',
|
||||||
|
dataIndex: 'subject',
|
||||||
|
render: subject => (
|
||||||
|
<Paragraph
|
||||||
|
style={{ marginBottom: 0 }}
|
||||||
|
ellipsis={{ rows: 1, expandable: true }}
|
||||||
|
>
|
||||||
|
{subject}
|
||||||
|
</Paragraph>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Issuer',
|
||||||
|
dataIndex: 'issuer',
|
||||||
|
render: issuer => (
|
||||||
|
<Paragraph
|
||||||
|
style={{ marginBottom: 0 }}
|
||||||
|
ellipsis={{ rows: 1, expandable: true }}
|
||||||
|
>
|
||||||
|
{issuer}
|
||||||
|
</Paragraph>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Actions',
|
||||||
|
key: 'actions',
|
||||||
|
dataIndex: 'serialNumber',
|
||||||
|
render: serialNumber => (
|
||||||
|
<Tooltip placement="bottom" title={'Remove User'}>
|
||||||
|
<Popconfirm
|
||||||
|
placement="top"
|
||||||
|
title={'Are you sure?'}
|
||||||
|
onConfirm={() => {
|
||||||
|
this.deleteCertificate(serialNumber);
|
||||||
|
}}
|
||||||
|
okText="Ok"
|
||||||
|
cancelText="Cancel"
|
||||||
|
>
|
||||||
|
<a>
|
||||||
|
<Text type="danger">
|
||||||
|
<Icon type="delete" />
|
||||||
|
</Text>
|
||||||
|
</a>
|
||||||
|
</Popconfirm>
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { data, pagination, loading } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<Table
|
||||||
|
columns={this.columns}
|
||||||
|
rowKey={record => record.serialNumber}
|
||||||
|
dataSource={data}
|
||||||
|
pagination={{
|
||||||
|
...pagination,
|
||||||
|
size: 'small',
|
||||||
|
// position: "top",
|
||||||
|
showTotal: (total, range) =>
|
||||||
|
`showing ${range[0]}-${range[1]} of ${total} devices`,
|
||||||
|
// showQuickJumper: true
|
||||||
|
}}
|
||||||
|
loading={loading}
|
||||||
|
onChange={this.handleTableChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(CertificateTable);
|
export default withConfigContext(CertificateTable);
|
||||||
|
|||||||
@ -16,129 +16,115 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {Card, Col, Icon, message, notification, Row, Typography} from "antd";
|
import { Card, Col, Icon, message, notification, Row } from 'antd';
|
||||||
import TimeAgo from 'javascript-time-ago'
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
let apiUrl;
|
let apiUrl;
|
||||||
|
|
||||||
class DeviceTypesTable extends React.Component {
|
class DeviceTypesTable extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
TimeAgo.addLocale(en);
|
||||||
TimeAgo.addLocale(en);
|
this.state = {
|
||||||
this.state = {
|
data: [],
|
||||||
data: [],
|
pagination: {},
|
||||||
pagination: {},
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetchUsers = (params = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/device-types';
|
||||||
|
|
||||||
|
// send request to the invokerss
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: []
|
data: JSON.parse(res.data.data),
|
||||||
};
|
pagination,
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load device types.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
this.setState({ loading: false });
|
||||||
this.fetchUsers();
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
//fetch data from api
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
fetchUsers = (params = {}) => {
|
const pager = { ...this.state.pagination };
|
||||||
const config = this.props.context;
|
pager.current = pagination.current;
|
||||||
this.setState({loading: true});
|
this.setState({
|
||||||
|
pagination: pager,
|
||||||
|
});
|
||||||
|
this.fetch({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// get current page
|
render() {
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
const { data } = this.state;
|
||||||
|
const { Meta } = Card;
|
||||||
const extraParams = {
|
const itemCard = data.map(data => (
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
<Col span={5} key={data.id}>
|
||||||
limit: 10,
|
<Card
|
||||||
};
|
size="default"
|
||||||
|
style={{ width: 200 }}
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
bordered={true}
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
actions={[
|
||||||
|
<Icon type="setting" key="setting" />,
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
<Icon type="edit" key="edit" />,
|
||||||
config.serverConfig.invoker.deviceMgt +
|
]}
|
||||||
"/device-types";
|
>
|
||||||
|
<Meta
|
||||||
//send request to the invokerss
|
avatar={<Icon type="desktop" key="device-types" />}
|
||||||
axios.get(apiUrl).then(res => {
|
title={data.name}
|
||||||
if (res.status === 200) {
|
/>
|
||||||
const pagination = {...this.state.pagination};
|
</Card>
|
||||||
this.setState({
|
</Col>
|
||||||
loading: false,
|
));
|
||||||
data: JSON.parse(res.data.data),
|
return (
|
||||||
pagination,
|
<div style={{ background: '#ECECEC', padding: '20px' }}>
|
||||||
});
|
<Row gutter={16}>{itemCard}</Row>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
}).catch((error) => {
|
}
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load device types.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = {...this.state.pagination};
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetch({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
|
||||||
const { Meta } = Card;
|
|
||||||
const itemCard = data.map((data) =>
|
|
||||||
<Col span={5} key={data.id}>
|
|
||||||
<Card
|
|
||||||
size="default"
|
|
||||||
style={{ width: 200 }}
|
|
||||||
bordered={true}
|
|
||||||
actions={[
|
|
||||||
<Icon type="setting" key="setting" />,
|
|
||||||
<Icon type="edit" key="edit" />,]}
|
|
||||||
>
|
|
||||||
<Meta
|
|
||||||
avatar={<Icon type="desktop" key="device-types"/>}
|
|
||||||
title={data.name}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<div style={{ background: '#ECECEC', padding: '20px' }}>
|
|
||||||
<Row gutter={16}>
|
|
||||||
{itemCard}
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(DeviceTypesTable);
|
export default withConfigContext(DeviceTypesTable);
|
||||||
|
|||||||
@ -1,66 +1,56 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Button, Form, Row, Col, Card, Steps, Input, message, Modal, notification, Typography} from "antd";
|
import { Form, Row, Col, Card, Steps } from 'antd';
|
||||||
import axios from "axios";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import DeviceType from './DeviceType';
|
||||||
import DeviceType from "./DeviceType";
|
import EnrollAgent from './EnrollAgent';
|
||||||
import EnrollAgent from "./EnrollAgent";
|
const { Step } = Steps;
|
||||||
const {Step} = Steps;
|
|
||||||
|
|
||||||
class AddDevice extends React.Component {
|
class AddDevice extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
constructor(props) {
|
super(props);
|
||||||
super(props);
|
this.config = this.props.context;
|
||||||
this.config = this.props.context;
|
this.state = {
|
||||||
this.state = {
|
isAddDeviceModalVisible: false,
|
||||||
isAddDeviceModalVisible: false,
|
current: 0,
|
||||||
current : 0,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
onClickType = () =>{
|
onClickType = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
current: 1,
|
current: 1,
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
openAddDeviceModal = () =>{
|
render() {
|
||||||
this.setState({
|
const { current } = this.state;
|
||||||
isAddDeviceModalVisible : true,
|
return (
|
||||||
})
|
<div>
|
||||||
};
|
<Row>
|
||||||
|
<Col span={16} offset={4}>
|
||||||
|
<Steps style={{ minHeight: 32 }} current={current}>
|
||||||
|
<Step key="DeviceType" title="Device Type" />
|
||||||
|
<Step key="EnrollAgent" title="Enroll Agent" />
|
||||||
|
<Step key="Result" title="Result" />
|
||||||
|
</Steps>
|
||||||
|
</Col>
|
||||||
|
<Col span={16} offset={4}>
|
||||||
|
<Card style={{ marginTop: 24 }}>
|
||||||
|
<div style={{ display: current === 0 ? 'unset' : 'none' }}>
|
||||||
|
<DeviceType onClickType={this.onClickType} />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: current === 1 ? 'unset' : 'none' }}>
|
||||||
|
<EnrollAgent />
|
||||||
|
</div>
|
||||||
|
|
||||||
render() {
|
<div style={{ display: current === 2 ? 'unset' : 'none' }}></div>
|
||||||
const {loading, current, isError, supportedOsVersions, errorText, forbiddenErrors} = this.state;
|
</Card>
|
||||||
const { getFieldDecorator } = this.props.form;
|
</Col>
|
||||||
return (
|
</Row>
|
||||||
<div>
|
</div>
|
||||||
<Row>
|
);
|
||||||
<Col span={16} offset={4}>
|
}
|
||||||
<Steps style={{minHeight: 32}} current={current}>
|
|
||||||
<Step key="DeviceType" title="Device Type"/>
|
|
||||||
<Step key="EnrollAgent" title="Enroll Agent"/>
|
|
||||||
<Step key="Result" title="Result"/>
|
|
||||||
</Steps>
|
|
||||||
</Col>
|
|
||||||
<Col span={16} offset={4}>
|
|
||||||
|
|
||||||
<Card style={{marginTop: 24}}>
|
|
||||||
<div style={{display: (current === 0 ? 'unset' : 'none')}}>
|
|
||||||
<DeviceType onClickType={this.onClickType}/>
|
|
||||||
</div>
|
|
||||||
<div style={{display: (current === 1 ? 'unset' : 'none')}}>
|
|
||||||
<EnrollAgent />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{display: (current === 2 ? 'unset' : 'none')}}>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create({name: 'add-device'})(AddDevice));
|
export default withConfigContext(
|
||||||
|
Form.create({ name: 'add-device' })(AddDevice),
|
||||||
|
);
|
||||||
|
|||||||
@ -16,109 +16,118 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {Button, Tooltip, Popconfirm, Divider} from "antd";
|
import { Button, Tooltip, Popconfirm, Divider } from 'antd';
|
||||||
|
|
||||||
class BulkActionBar extends React.Component {
|
class BulkActionBar extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
selectedMultiple: false,
|
||||||
|
selectedSingle: false,
|
||||||
|
canDelete: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
// This method checks whether NON-REMOVED devices are selected
|
||||||
super(props);
|
onDeleteDeviceCall = () => {
|
||||||
this.state = {
|
let tempDeleteState;
|
||||||
selectedMultiple: false,
|
for (let i = 0; i < this.props.selectedRows.length; i++) {
|
||||||
selectedSingle: false,
|
if (this.props.selectedRows[i].enrolmentInfo.status != 'REMOVED') {
|
||||||
canDelete: true,
|
tempDeleteState = false;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
tempDeleteState = true;
|
||||||
}
|
}
|
||||||
|
this.setState({ canDelete: tempDeleteState });
|
||||||
|
};
|
||||||
|
|
||||||
//This method checks whether NON-REMOVED devices are selected
|
onConfirmDelete = () => {
|
||||||
onDeleteDeviceCall = () => {
|
if (this.state.canDelete) {
|
||||||
let tempDeleteState;
|
this.props.deleteDevice();
|
||||||
for(let i=0; i < this.props.selectedRows.length; i++){
|
}
|
||||||
if(this.props.selectedRows[i].enrolmentInfo.status != "REMOVED"){
|
};
|
||||||
tempDeleteState = false;
|
|
||||||
break;
|
onConfirmDisenroll = () => {
|
||||||
|
this.props.disenrollDevice();
|
||||||
|
};
|
||||||
|
|
||||||
|
onDeviceGroupCall = () => {
|
||||||
|
this.props.getGroups();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const isSelected = this.props.selectedRows.length > 0;
|
||||||
|
const isSelectedSingle = this.props.selectedRows.length == 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: isSelected ? 'inline' : 'none', padding: '11px' }}>
|
||||||
|
<Tooltip
|
||||||
|
placement="bottom"
|
||||||
|
title={'Delete Device'}
|
||||||
|
autoAdjustOverflow={true}
|
||||||
|
>
|
||||||
|
<Popconfirm
|
||||||
|
placement="topLeft"
|
||||||
|
title={
|
||||||
|
this.state.canDelete
|
||||||
|
? 'Are you sure you want to delete?'
|
||||||
|
: 'You can only delete disenrolled devices'
|
||||||
}
|
}
|
||||||
tempDeleteState = true;
|
onConfirm={this.onConfirmDelete}
|
||||||
}
|
okText="Ok"
|
||||||
this.setState({canDelete:tempDeleteState})
|
cancelText="Cancel"
|
||||||
};
|
>
|
||||||
|
<Button
|
||||||
onConfirmDelete = () => {
|
type="link"
|
||||||
if (this.state.canDelete) {
|
shape="circle"
|
||||||
this.props.deleteDevice();
|
icon="delete"
|
||||||
}
|
size={'default'}
|
||||||
};
|
onClick={this.onDeleteDeviceCall}
|
||||||
|
disabled={!isSelected}
|
||||||
onConfirmDisenroll = () => {
|
style={{ margin: '2px' }}
|
||||||
this.props.disenrollDevice();
|
/>
|
||||||
};
|
</Popconfirm>
|
||||||
|
</Tooltip>
|
||||||
onDeviceGroupCall = () => {
|
<Divider type="vertical" />
|
||||||
this.props.getGroups();
|
<Tooltip placement="bottom" title={'Disenroll Device'}>
|
||||||
}
|
<Popconfirm
|
||||||
|
placement="topLeft"
|
||||||
render() {
|
title={'Are you sure?'}
|
||||||
const isSelected = this.props.selectedRows.length > 0;
|
onConfirm={this.onConfirmDisenroll}
|
||||||
const isSelectedSingle = this.props.selectedRows.length == 1;
|
okText="Ok"
|
||||||
|
disabled={!isSelectedSingle}
|
||||||
return (
|
cancelText="Cancel"
|
||||||
<div style={{display: isSelected ? "inline" : "none", padding: '11px'}}>
|
>
|
||||||
|
<Button
|
||||||
<Tooltip
|
type="link"
|
||||||
placement="bottom"
|
shape="circle"
|
||||||
title={"Delete Device"}
|
icon="close"
|
||||||
autoAdjustOverflow={true}>
|
size={'default'}
|
||||||
<Popconfirm
|
style={{
|
||||||
placement="topLeft"
|
display: isSelectedSingle ? 'inline' : 'none',
|
||||||
title={
|
margin: '2px',
|
||||||
this.state.canDelete ?
|
}}
|
||||||
"Are you sure you want to delete?" : "You can only delete disenrolled devices"}
|
/>
|
||||||
onConfirm={this.onConfirmDelete}
|
</Popconfirm>
|
||||||
okText="Ok"
|
</Tooltip>
|
||||||
cancelText="Cancel">
|
<Divider
|
||||||
|
type="vertical"
|
||||||
<Button
|
style={{ display: isSelectedSingle ? 'inline-block' : 'none' }}
|
||||||
type="link"
|
/>
|
||||||
shape="circle"
|
<Tooltip placement="bottom" title={'Add to group'}>
|
||||||
icon="delete"
|
<Button
|
||||||
size={'default'}
|
type="link"
|
||||||
onClick={this.onDeleteDeviceCall}
|
shape="circle"
|
||||||
disabled={isSelected ? false : true}
|
icon="deployment-unit"
|
||||||
style={{margin: "2px"}}/>
|
size={'default'}
|
||||||
</Popconfirm>
|
onClick={this.onDeviceGroupCall}
|
||||||
</Tooltip>
|
style={{ margin: '2px' }}
|
||||||
<Divider type="vertical"/>
|
/>
|
||||||
<Tooltip placement="bottom" title={"Disenroll Device"}>
|
</Tooltip>
|
||||||
<Popconfirm
|
</div>
|
||||||
placement="topLeft"
|
);
|
||||||
title={"Are you sure?"}
|
}
|
||||||
onConfirm={this.onConfirmDisenroll}
|
|
||||||
okText="Ok"
|
|
||||||
disabled={isSelectedSingle ? false : true}
|
|
||||||
cancelText="Cancel">
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="close"
|
|
||||||
size={'default'}
|
|
||||||
style={{display:isSelectedSingle ? "inline" : "none", margin: "2px"}}/>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" style={{display:isSelectedSingle ? "inline-block" : "none"}}/>
|
|
||||||
<Tooltip placement="bottom" title={"Add to group"}>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="deployment-unit"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.onDeviceGroupCall}
|
|
||||||
style={{margin: "2px"}}/>
|
|
||||||
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BulkActionBar;
|
export default BulkActionBar;
|
||||||
|
|||||||
@ -16,133 +16,126 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {Card, Col, Icon, message, notification, Row, Typography} from "antd";
|
import { Card, Col, Icon, message, notification, Row } from 'antd';
|
||||||
import TimeAgo from 'javascript-time-ago'
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
let apiUrl;
|
let apiUrl;
|
||||||
|
|
||||||
class DeviceType extends React.Component {
|
class DeviceType extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
TimeAgo.addLocale(en);
|
||||||
TimeAgo.addLocale(en);
|
this.state = {
|
||||||
this.state = {
|
data: [],
|
||||||
data: [],
|
pagination: {},
|
||||||
pagination: {},
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickCard = data => {
|
||||||
|
console.log(data);
|
||||||
|
this.props.onClickType();
|
||||||
|
};
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetchUsers = (params = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/device-types';
|
||||||
|
|
||||||
|
// send request to the invokerss
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: []
|
data: JSON.parse(res.data.data),
|
||||||
};
|
pagination,
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load device types.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
this.setState({ loading: false });
|
||||||
this.fetchUsers();
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
onClickCard = (data) =>{
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
console.log(data);
|
const pager = { ...this.state.pagination };
|
||||||
this.props.onClickType();
|
pager.current = pagination.current;
|
||||||
};
|
this.setState({
|
||||||
|
pagination: pager,
|
||||||
|
});
|
||||||
|
this.fetch({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
//fetch data from api
|
render() {
|
||||||
fetchUsers = (params = {}) => {
|
const { data } = this.state;
|
||||||
const config = this.props.context;
|
const { Meta } = Card;
|
||||||
this.setState({loading: true});
|
const itemCard = data.map(data => (
|
||||||
|
<Col span={5} key={data.id}>
|
||||||
// get current page
|
<Card
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
size="default"
|
||||||
|
style={{ width: 150 }}
|
||||||
const extraParams = {
|
bordered={true}
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
onClick={this.onClickCard}
|
||||||
limit: 10,
|
cover={
|
||||||
};
|
<Icon
|
||||||
|
type="android"
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
key="device-types"
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
style={{
|
||||||
|
color: '#ffffff',
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
backgroundColor: '#4b92db',
|
||||||
config.serverConfig.invoker.deviceMgt +
|
fontSize: '100px',
|
||||||
"/device-types";
|
padding: '20px',
|
||||||
|
}}
|
||||||
//send request to the invokerss
|
/>
|
||||||
axios.get(apiUrl).then(res => {
|
}
|
||||||
if (res.status === 200) {
|
>
|
||||||
const pagination = {...this.state.pagination};
|
<Meta title={data.name} />
|
||||||
this.setState({
|
</Card>
|
||||||
loading: false,
|
</Col>
|
||||||
data: JSON.parse(res.data.data),
|
));
|
||||||
pagination,
|
return (
|
||||||
});
|
<div>
|
||||||
}
|
<Row gutter={16}>{itemCard}</Row>
|
||||||
|
</div>
|
||||||
}).catch((error) => {
|
);
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
}
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load device types.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = {...this.state.pagination};
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetch({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
|
||||||
const { Meta } = Card;
|
|
||||||
const itemCard = data.map((data) =>
|
|
||||||
<Col span={5} key={data.id}>
|
|
||||||
<Card
|
|
||||||
size="default"
|
|
||||||
style={{ width: 150 }}
|
|
||||||
bordered={true}
|
|
||||||
onClick={this.onClickCard}
|
|
||||||
cover={<Icon type="android" key="device-types" style={{color:'#ffffff',
|
|
||||||
backgroundColor:'#4b92db', fontSize: '100px', padding:'20px'}}/>}
|
|
||||||
>
|
|
||||||
<Meta
|
|
||||||
title={data.name}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row gutter={16}>
|
|
||||||
{itemCard}
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(DeviceType);
|
export default withConfigContext(DeviceType);
|
||||||
|
|||||||
@ -16,471 +16,523 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {Icon, message, Modal, notification, Select, Table, Tag, Tooltip, Typography} from "antd";
|
import {
|
||||||
import TimeAgo from 'javascript-time-ago'
|
Icon,
|
||||||
|
message,
|
||||||
|
Modal,
|
||||||
|
notification,
|
||||||
|
Select,
|
||||||
|
Table,
|
||||||
|
Tag,
|
||||||
|
Tooltip,
|
||||||
|
} from 'antd';
|
||||||
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
import BulkActionBar from "./BulkActionBar";
|
import BulkActionBar from './BulkActionBar';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
let config = null;
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: 'Device',
|
title: 'Device',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Type',
|
title: 'Type',
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
key: 'type',
|
key: 'type',
|
||||||
render: type => {
|
// eslint-disable-next-line react/display-name
|
||||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
render: type => {
|
||||||
let icon = defaultPlatformIcons.default.icon;
|
const defaultPlatformIcons = config.defaultPlatformIcons;
|
||||||
let color = defaultPlatformIcons.default.color;
|
let icon = defaultPlatformIcons.default.icon;
|
||||||
let theme = defaultPlatformIcons.default.theme;
|
let color = defaultPlatformIcons.default.color;
|
||||||
|
let theme = defaultPlatformIcons.default.theme;
|
||||||
|
|
||||||
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
||||||
icon = defaultPlatformIcons[type].icon;
|
icon = defaultPlatformIcons[type].icon;
|
||||||
color = defaultPlatformIcons[type].color;
|
color = defaultPlatformIcons[type].color;
|
||||||
theme = defaultPlatformIcons[type].theme;
|
theme = defaultPlatformIcons[type].theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
|
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
|
||||||
<Icon type={icon} theme={theme}/>
|
<Icon type={icon} theme={theme} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Owner',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
{
|
||||||
key: 'owner',
|
title: 'Owner',
|
||||||
render: enrolmentInfo => enrolmentInfo.owner
|
dataIndex: 'enrolmentInfo',
|
||||||
// todo add filtering options
|
key: 'owner',
|
||||||
|
render: enrolmentInfo => enrolmentInfo.owner,
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ownership',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'ownership',
|
||||||
|
render: enrolmentInfo => enrolmentInfo.ownership,
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Status',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'status',
|
||||||
|
// eslint-disable-next-line react/display-name
|
||||||
|
render: enrolmentInfo => {
|
||||||
|
const status = enrolmentInfo.status.toLowerCase();
|
||||||
|
let color = '#f9ca24';
|
||||||
|
switch (status) {
|
||||||
|
case 'active':
|
||||||
|
color = '#badc58';
|
||||||
|
break;
|
||||||
|
case 'created':
|
||||||
|
color = '#6ab04c';
|
||||||
|
break;
|
||||||
|
case 'removed':
|
||||||
|
color = '#ff7979';
|
||||||
|
break;
|
||||||
|
case 'inactive':
|
||||||
|
color = '#f9ca24';
|
||||||
|
break;
|
||||||
|
case 'blocked':
|
||||||
|
color = '#636e72';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return <Tag color={color}>{status}</Tag>;
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Ownership',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
{
|
||||||
key: 'ownership',
|
title: 'Last Updated',
|
||||||
render: enrolmentInfo => enrolmentInfo.ownership
|
dataIndex: 'enrolmentInfo',
|
||||||
// todo add filtering options
|
key: 'dateOfLastUpdate',
|
||||||
|
// eslint-disable-next-line react/display-name
|
||||||
|
render: data => {
|
||||||
|
const { dateOfLastUpdate } = data;
|
||||||
|
const timeAgoString = getTimeAgo(dateOfLastUpdate);
|
||||||
|
return (
|
||||||
|
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
|
||||||
|
{timeAgoString}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Status',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'status',
|
|
||||||
render: (enrolmentInfo) => {
|
|
||||||
const status = enrolmentInfo.status.toLowerCase();
|
|
||||||
let color = "#f9ca24";
|
|
||||||
switch (status) {
|
|
||||||
case "active":
|
|
||||||
color = "#badc58";
|
|
||||||
break;
|
|
||||||
case "created":
|
|
||||||
color = "#6ab04c";
|
|
||||||
break;
|
|
||||||
case "removed":
|
|
||||||
color = "#ff7979";
|
|
||||||
break;
|
|
||||||
case "inactive":
|
|
||||||
color = "#f9ca24";
|
|
||||||
break;
|
|
||||||
case "blocked":
|
|
||||||
color = "#636e72";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return <Tag color={color}>{status}</Tag>;
|
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Last Updated',
|
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'dateOfLastUpdate',
|
|
||||||
render: (data) => {
|
|
||||||
const {dateOfLastUpdate} = data;
|
|
||||||
const timeAgoString = getTimeAgo(dateOfLastUpdate);
|
|
||||||
return <Tooltip title={new Date(dateOfLastUpdate).toString()}>{timeAgoString}</Tooltip>;
|
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const getTimeAgo = (time) => {
|
const getTimeAgo = time => {
|
||||||
const timeAgo = new TimeAgo('en-US');
|
const timeAgo = new TimeAgo('en-US');
|
||||||
return timeAgo.format(time);
|
return timeAgo.format(time);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class DeviceTable extends React.Component {
|
class DeviceTable extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
config = this.props.context;
|
||||||
TimeAgo.addLocale(en);
|
TimeAgo.addLocale(en);
|
||||||
this.state = {
|
this.state = {
|
||||||
data: [],
|
data: [],
|
||||||
pagination: {},
|
pagination: {},
|
||||||
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
deviceGroups: [],
|
||||||
|
groupModalVisible: false,
|
||||||
|
selectedGroupId: [],
|
||||||
|
selectedRowKeys: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
// get current page
|
||||||
|
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (currentPage - 1), // calculate the offset
|
||||||
|
limit: 10,
|
||||||
|
requireDeviceInfo: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const encodedExtraParams = Object.keys(extraParams)
|
||||||
|
.map(key => key + '=' + extraParams[key])
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
// send request to the invoker
|
||||||
|
axios
|
||||||
|
.get(
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/devices?' +
|
||||||
|
encodedExtraParams,
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: [],
|
data: res.data.data.devices,
|
||||||
deviceGroups: [],
|
pagination,
|
||||||
groupModalVisible: false,
|
});
|
||||||
selectedGroupId: [],
|
}
|
||||||
selectedRowKeys:[]
|
})
|
||||||
};
|
.catch(error => {
|
||||||
}
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
componentDidMount() {
|
message.error('You are not logged in');
|
||||||
this.fetch();
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
}
|
} else {
|
||||||
|
notification.error({
|
||||||
//fetch data from api
|
message: 'There was a problem',
|
||||||
fetch = (params = {}) => {
|
duration: 0,
|
||||||
const config = this.props.context;
|
description: 'Error occurred while trying to load devices.',
|
||||||
this.setState({loading: true});
|
});
|
||||||
// get current page
|
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
|
||||||
|
|
||||||
const extraParams = {
|
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
|
||||||
limit: 10,
|
|
||||||
requireDeviceInfo: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
|
||||||
|
|
||||||
//send request to the invoker
|
|
||||||
axios.get(
|
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/devices?" + encodedExtraParams,
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
const pagination = {...this.state.pagination};
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
data: res.data.data.devices,
|
|
||||||
pagination
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to load devices.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
deleteDevice = () => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({loading: true});
|
|
||||||
|
|
||||||
const deviceData = this.state.selectedRows.map(obj => obj.deviceIdentifier);
|
|
||||||
|
|
||||||
//send request to the invoker
|
|
||||||
axios.put(
|
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/admin/devices/permanent-delete",
|
|
||||||
deviceData,
|
|
||||||
{headers: {'Content-Type': 'application/json'}}
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetch();
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to delete devices.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
disenrollDevice = () => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({loading: true});
|
|
||||||
|
|
||||||
const deviceData = this.state.selectedRows[0];
|
|
||||||
|
|
||||||
//send request to the invoker
|
|
||||||
axios.delete(
|
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/devices/type/" + deviceData.type + "/id/" + deviceData.deviceIdentifier,
|
|
||||||
{headers: {'Content-Type': 'application/json'}}
|
|
||||||
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetch();
|
|
||||||
this.setState({
|
|
||||||
selectedRowKeys:[]
|
|
||||||
})
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully dis-enrolled the device.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to dis-enroll devices.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
addDevicesToGroup = (groupId) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({loading: true});
|
|
||||||
|
|
||||||
let apiUrl;
|
|
||||||
let deviceData;
|
|
||||||
if (this.state.selectedRows.length === 1) {
|
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/groups/device/assign";
|
|
||||||
deviceData = {
|
|
||||||
deviceIdentifier: {
|
|
||||||
id: this.state.selectedRows[0].deviceIdentifier,
|
|
||||||
type: this.state.selectedRows[0].type
|
|
||||||
},
|
|
||||||
deviceGroupIds: groupId
|
|
||||||
}
|
|
||||||
} else if (!groupId[0]){
|
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/groups/id/" + groupId + "/devices/add";
|
|
||||||
deviceData = this.state.selectedRows.map(obj => ({id: obj.deviceIdentifier, type: obj.type}));
|
|
||||||
} else{
|
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/groups/id/" + groupId[0] + "/devices/add";
|
|
||||||
deviceData = this.state.selectedRows.map(obj => ({id: obj.deviceIdentifier, type: obj.type}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//send request to the invoker
|
this.setState({ loading: false });
|
||||||
axios.post(
|
});
|
||||||
apiUrl,
|
};
|
||||||
deviceData,
|
|
||||||
{headers: {'Content-Type': 'application/json'}}
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
loading: false
|
|
||||||
});
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully added to the device group.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while adding to the device group.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
deleteDevice = () => {
|
||||||
});
|
const config = this.props.context;
|
||||||
};
|
this.setState({ loading: true });
|
||||||
|
|
||||||
getGroups = () => {
|
const deviceData = this.state.selectedRows.map(obj => obj.deviceIdentifier);
|
||||||
this.setState({
|
|
||||||
groupModalVisible: true
|
|
||||||
});
|
|
||||||
//send request to the invoker
|
|
||||||
axios.get(
|
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/groups"
|
|
||||||
).then(res => {
|
|
||||||
this.setState({deviceGroups: res.data.data.deviceGroups})
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while retrieving device groups.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
// send request to the invoker
|
||||||
});
|
axios
|
||||||
};
|
.put(
|
||||||
|
window.location.origin +
|
||||||
handleOk = e => {
|
config.serverConfig.invoker.uri +
|
||||||
if(this.state.selectedGroupId){
|
config.serverConfig.invoker.deviceMgt +
|
||||||
this.addDevicesToGroup(this.state.selectedGroupId);
|
'/admin/devices/permanent-delete',
|
||||||
this.setState({
|
deviceData,
|
||||||
groupModalVisible: false
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
});
|
)
|
||||||
}else{
|
.then(res => {
|
||||||
notification["error"]({
|
if (res.status === 200) {
|
||||||
message: "There was a problem",
|
this.fetch();
|
||||||
duration: 0,
|
}
|
||||||
description:
|
})
|
||||||
"Please select a group.",
|
.catch(error => {
|
||||||
});
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to delete devices.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
this.setState({ loading: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
handleCancel = e => {
|
disenrollDevice = () => {
|
||||||
this.setState({
|
const config = this.props.context;
|
||||||
groupModalVisible: false,
|
this.setState({ loading: true });
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onGroupSelectChange = (value) => {
|
const deviceData = this.state.selectedRows[0];
|
||||||
this.setState({selectedGroupId: value});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
// send request to the invoker
|
||||||
const pager = {...this.state.pagination};
|
axios
|
||||||
pager.current = pagination.current;
|
.delete(
|
||||||
this.setState({
|
window.location.origin +
|
||||||
pagination: pager,
|
config.serverConfig.invoker.uri +
|
||||||
});
|
config.serverConfig.invoker.deviceMgt +
|
||||||
this.fetch({
|
'/devices/type/' +
|
||||||
results: pagination.pageSize,
|
deviceData.type +
|
||||||
page: pagination.current,
|
'/id/' +
|
||||||
sortField: sorter.field,
|
deviceData.deviceIdentifier,
|
||||||
sortOrder: sorter.order,
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
...filters,
|
)
|
||||||
});
|
.then(res => {
|
||||||
};
|
if (res.status === 200) {
|
||||||
|
this.fetch();
|
||||||
onSelectChange = (selectedRowKeys, selectedRows) => {
|
this.setState({
|
||||||
this.setState({
|
selectedRowKeys: [],
|
||||||
selectedRowKeys,
|
});
|
||||||
selectedRows: selectedRows
|
notification.success({
|
||||||
});
|
message: 'Done',
|
||||||
};
|
duration: 4,
|
||||||
|
description: 'Successfully dis-enrolled the device.',
|
||||||
render() {
|
});
|
||||||
const {data, pagination, loading, selectedRows, selectedRowKeys} = this.state;
|
}
|
||||||
const isSelectedSingle = this.state.selectedRows.length == 1;
|
})
|
||||||
|
.catch(error => {
|
||||||
let selectedText;
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
if(isSelectedSingle){
|
// todo display a popop with error
|
||||||
selectedText = "You have selected 1 device"
|
message.error('You are not logged in');
|
||||||
}else{
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
selectedText = "You have selected " + this.state.selectedRows.length + " devices"
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to dis-enroll devices.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const rowSelection = {
|
this.setState({ loading: false });
|
||||||
selectedRowKeys,
|
});
|
||||||
selectedRows,
|
};
|
||||||
onChange: this.onSelectChange,
|
|
||||||
};
|
|
||||||
|
|
||||||
let item = this.state.deviceGroups.map((data) =>
|
addDevicesToGroup = groupId => {
|
||||||
<Select.Option
|
const config = this.props.context;
|
||||||
value={data.id}
|
this.setState({ loading: true });
|
||||||
key={data.id}>
|
|
||||||
{data.name}
|
|
||||||
</Select.Option>);
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<BulkActionBar
|
|
||||||
deleteDevice={this.deleteDevice}
|
|
||||||
getGroups={this.getGroups}
|
|
||||||
disenrollDevice={this.disenrollDevice}
|
|
||||||
selectedRows={this.state.selectedRows}/>
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
|
|
||||||
dataSource={data}
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: "small",
|
|
||||||
// position: "top",
|
|
||||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
|
|
||||||
// showQuickJumper: true
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Modal
|
let apiUrl;
|
||||||
title="Grouping Devices"
|
let deviceData;
|
||||||
width="350px"
|
if (this.state.selectedRows.length === 1) {
|
||||||
visible={this.state.groupModalVisible}
|
apiUrl =
|
||||||
onOk={this.handleOk}
|
window.location.origin +
|
||||||
onCancel={this.handleCancel}
|
config.serverConfig.invoker.uri +
|
||||||
>
|
config.serverConfig.invoker.deviceMgt +
|
||||||
<p>{selectedText}</p>
|
'/groups/device/assign';
|
||||||
<Select
|
deviceData = {
|
||||||
mode={isSelectedSingle ? "multiple" : "default"}
|
deviceIdentifier: {
|
||||||
showSearch
|
id: this.state.selectedRows[0].deviceIdentifier,
|
||||||
style={{display:"block"}}
|
type: this.state.selectedRows[0].type,
|
||||||
placeholder="Select Group"
|
},
|
||||||
optionFilterProp="children"
|
deviceGroupIds: groupId,
|
||||||
onChange={this.onGroupSelectChange}
|
};
|
||||||
>
|
} else if (!groupId[0]) {
|
||||||
{item}
|
apiUrl =
|
||||||
</Select>
|
window.location.origin +
|
||||||
</Modal>
|
config.serverConfig.invoker.uri +
|
||||||
</div>
|
config.serverConfig.invoker.deviceMgt +
|
||||||
);
|
'/groups/id/' +
|
||||||
|
groupId +
|
||||||
|
'/devices/add';
|
||||||
|
deviceData = this.state.selectedRows.map(obj => ({
|
||||||
|
id: obj.deviceIdentifier,
|
||||||
|
type: obj.type,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/groups/id/' +
|
||||||
|
groupId[0] +
|
||||||
|
'/devices/add';
|
||||||
|
deviceData = this.state.selectedRows.map(obj => ({
|
||||||
|
id: obj.deviceIdentifier,
|
||||||
|
type: obj.type,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send request to the invoker
|
||||||
|
axios
|
||||||
|
.post(apiUrl, deviceData, {
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully added to the device group.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while adding to the device group.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ loading: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getGroups = () => {
|
||||||
|
this.setState({
|
||||||
|
groupModalVisible: true,
|
||||||
|
});
|
||||||
|
// send request to the invoker
|
||||||
|
axios
|
||||||
|
.get(
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/groups',
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
this.setState({ deviceGroups: res.data.data.deviceGroups });
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while retrieving device groups.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ loading: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleOk = e => {
|
||||||
|
if (this.state.selectedGroupId) {
|
||||||
|
this.addDevicesToGroup(this.state.selectedGroupId);
|
||||||
|
this.setState({
|
||||||
|
groupModalVisible: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Please select a group.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCancel = e => {
|
||||||
|
this.setState({
|
||||||
|
groupModalVisible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onGroupSelectChange = value => {
|
||||||
|
this.setState({ selectedGroupId: value });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
const pager = { ...this.state.pagination };
|
||||||
|
pager.current = pagination.current;
|
||||||
|
this.setState({
|
||||||
|
pagination: pager,
|
||||||
|
});
|
||||||
|
this.fetch({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onSelectChange = (selectedRowKeys, selectedRows) => {
|
||||||
|
this.setState({
|
||||||
|
selectedRowKeys,
|
||||||
|
selectedRows: selectedRows,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
pagination,
|
||||||
|
loading,
|
||||||
|
selectedRows,
|
||||||
|
selectedRowKeys,
|
||||||
|
} = this.state;
|
||||||
|
const isSelectedSingle = this.state.selectedRows.length == 1;
|
||||||
|
|
||||||
|
let selectedText;
|
||||||
|
if (isSelectedSingle) {
|
||||||
|
selectedText = 'You have selected 1 device';
|
||||||
|
} else {
|
||||||
|
selectedText =
|
||||||
|
'You have selected ' + this.state.selectedRows.length + ' devices';
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowSelection = {
|
||||||
|
selectedRowKeys,
|
||||||
|
selectedRows,
|
||||||
|
onChange: this.onSelectChange,
|
||||||
|
};
|
||||||
|
|
||||||
|
let item = this.state.deviceGroups.map(data => (
|
||||||
|
<Select.Option value={data.id} key={data.id}>
|
||||||
|
{data.name}
|
||||||
|
</Select.Option>
|
||||||
|
));
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<BulkActionBar
|
||||||
|
deleteDevice={this.deleteDevice}
|
||||||
|
getGroups={this.getGroups}
|
||||||
|
disenrollDevice={this.disenrollDevice}
|
||||||
|
selectedRows={this.state.selectedRows}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
rowKey={record =>
|
||||||
|
record.deviceIdentifier +
|
||||||
|
record.enrolmentInfo.owner +
|
||||||
|
record.enrolmentInfo.ownership
|
||||||
|
}
|
||||||
|
dataSource={data}
|
||||||
|
pagination={{
|
||||||
|
...pagination,
|
||||||
|
size: 'small',
|
||||||
|
// position: "top",
|
||||||
|
showTotal: (total, range) =>
|
||||||
|
`showing ${range[0]}-${range[1]} of ${total} devices`,
|
||||||
|
// showQuickJumper: true
|
||||||
|
}}
|
||||||
|
loading={loading}
|
||||||
|
onChange={this.handleTableChange}
|
||||||
|
rowSelection={rowSelection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title="Grouping Devices"
|
||||||
|
width="350px"
|
||||||
|
visible={this.state.groupModalVisible}
|
||||||
|
onOk={this.handleOk}
|
||||||
|
onCancel={this.handleCancel}
|
||||||
|
>
|
||||||
|
<p>{selectedText}</p>
|
||||||
|
<Select
|
||||||
|
mode={isSelectedSingle ? 'multiple' : 'default'}
|
||||||
|
showSearch
|
||||||
|
style={{ display: 'block' }}
|
||||||
|
placeholder="Select Group"
|
||||||
|
optionFilterProp="children"
|
||||||
|
onChange={this.onGroupSelectChange}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</Select>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(DeviceTable);
|
export default withConfigContext(DeviceTable);
|
||||||
|
|||||||
@ -1,87 +1,97 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Collapse, Button, Divider, message, notification , Select} from 'antd';
|
import { Button, Divider, message, notification } from 'antd';
|
||||||
import TimeAgo from "javascript-time-ago/modules/JavascriptTimeAgo";
|
import TimeAgo from 'javascript-time-ago/modules/JavascriptTimeAgo';
|
||||||
import en from "javascript-time-ago/locale/en";
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
class EnrollAgent extends React.Component {
|
class EnrollAgent extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.config = this.props.context;
|
this.config = this.props.context;
|
||||||
TimeAgo.addLocale(en);
|
TimeAgo.addLocale(en);
|
||||||
this.state = {
|
this.state = {
|
||||||
data: [],
|
data: [],
|
||||||
pagination: {},
|
pagination: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: [],
|
selectedRows: [],
|
||||||
visibleSelector: {display : 'none'}
|
visibleSelector: { display: 'none' },
|
||||||
};
|
|
||||||
}
|
|
||||||
componentDidMount() {
|
|
||||||
this.getConfigData();
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
this.getConfigData();
|
||||||
|
}
|
||||||
|
|
||||||
onGetEnrollmentQR = () =>{
|
onGetEnrollmentQR = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
visibleSelector: {display : 'block'}
|
visibleSelector: { display: 'block' },
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
getConfigData = () =>{
|
getConfigData = () => {
|
||||||
axios.get(
|
axios
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
.get(
|
||||||
"/device-mgt/android/v1.0/configuration"
|
window.location.origin +
|
||||||
).then(res => {
|
this.config.serverConfig.invoker.uri +
|
||||||
let data = res.data.data;
|
'/device-mgt/android/v1.0/configuration',
|
||||||
}).catch((error) => {
|
)
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
.catch(error => {
|
||||||
//todo display a popop with error
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
message.error('You are not logged in');
|
// todo display a popop with error
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
message.error('You are not logged in');
|
||||||
} else {
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
notification["error"]({
|
} else {
|
||||||
message: "There was a problem",
|
notification.error({
|
||||||
duration: 0,
|
message: 'There was a problem',
|
||||||
description:
|
duration: 0,
|
||||||
"Error occurred while retrieving device groups.",
|
description: 'Error occurred while retrieving device groups.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
});
|
render() {
|
||||||
};
|
return (
|
||||||
|
<div>
|
||||||
|
<Divider orientation="left">Step 01 - Get your Android Agent.</Divider>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
The Android agent can be downloaded by using following QR. The
|
||||||
|
generated QR code can be scanned, and the agent APK downloaded from
|
||||||
|
the link, and transferred to the device and then installed.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div style={{ margin: '30px' }}>
|
||||||
|
<Button type="primary" size={'default'}>
|
||||||
|
Get Android Agent
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Divider orientation="left">
|
||||||
|
Step 02 - Enroll the Android Agent.
|
||||||
|
</Divider>
|
||||||
|
|
||||||
render() {
|
<div>
|
||||||
return (
|
<p>
|
||||||
<div>
|
{' '}
|
||||||
<Divider orientation="left">Step 01 - Get your Android Agent.</Divider>
|
Your device can be enrolled with Entgra IoTS automatically via QR
|
||||||
<div>
|
code. To enroll first download agent as mentioned in Step 1 then
|
||||||
<p>The Android agent can be downloaded by using following QR.
|
proceed with the ENROLL WITH QR option from the device setup
|
||||||
The generated QR code can be scanned, and the agent APK downloaded from the link,
|
activity. Thereafter select the ownership configuration and scan the
|
||||||
and transferred to the device and then installed.</p>
|
generated QR to complete the process.
|
||||||
</div>
|
</p>
|
||||||
<div style={{ margin:'30px'}}>
|
</div>
|
||||||
<Button type="primary" size={"default"}>
|
<div style={{ margin: '30px' }}>
|
||||||
Get Android Agent
|
<Button
|
||||||
</Button>
|
type="primary"
|
||||||
</div>
|
size={'default'}
|
||||||
<Divider orientation="left">Step 02 - Enroll the Android Agent.</Divider>
|
onClick={this.onGetEnrollmentQR}
|
||||||
|
>
|
||||||
<div>
|
Enroll Using QR
|
||||||
<p> Your device can be enrolled with Entgra IoTS automatically via QR code.
|
</Button>
|
||||||
To enroll first download agent as mentioned in Step 1 then proceed with the ENROLL WITH
|
</div>
|
||||||
QR option from the device setup activity. Thereafter select the ownership configuration
|
</div>
|
||||||
and scan the generated QR to complete the process.</p>
|
);
|
||||||
</div>
|
}
|
||||||
<div style={{ margin:'30px'}}>
|
|
||||||
<Button type="primary" size={"default"} onClick={this.onGetEnrollmentQR}>
|
|
||||||
Enroll Using QR
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(EnrollAgent);
|
export default withConfigContext(EnrollAgent);
|
||||||
|
|||||||
@ -16,232 +16,252 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {Icon, message, notification, Table, Tag, Tooltip, Typography} from "antd";
|
import { Icon, message, notification, Table, Tag, Tooltip } from 'antd';
|
||||||
import TimeAgo from 'javascript-time-ago'
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
let config = null;
|
||||||
let apiUrl;
|
let apiUrl;
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: 'Device',
|
title: 'Device',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Type',
|
title: 'Type',
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
key: 'type',
|
key: 'type',
|
||||||
render: type => {
|
// eslint-disable-next-line react/display-name
|
||||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
render: type => {
|
||||||
let icon = defaultPlatformIcons.default.icon;
|
const defaultPlatformIcons = config.defaultPlatformIcons;
|
||||||
let color = defaultPlatformIcons.default.color;
|
let icon = defaultPlatformIcons.default.icon;
|
||||||
let theme = defaultPlatformIcons.default.theme;
|
let color = defaultPlatformIcons.default.color;
|
||||||
|
let theme = defaultPlatformIcons.default.theme;
|
||||||
|
|
||||||
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
||||||
icon = defaultPlatformIcons[type].icon;
|
icon = defaultPlatformIcons[type].icon;
|
||||||
color = defaultPlatformIcons[type].color;
|
color = defaultPlatformIcons[type].color;
|
||||||
theme = defaultPlatformIcons[type].theme;
|
theme = defaultPlatformIcons[type].theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
|
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
|
||||||
<Icon type={icon} theme={theme}/>
|
<Icon type={icon} theme={theme} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Owner',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
{
|
||||||
key: 'owner',
|
title: 'Owner',
|
||||||
render: enrolmentInfo => enrolmentInfo.owner
|
dataIndex: 'enrolmentInfo',
|
||||||
// todo add filtering options
|
key: 'owner',
|
||||||
|
render: enrolmentInfo => enrolmentInfo.owner,
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ownership',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'ownership',
|
||||||
|
render: enrolmentInfo => enrolmentInfo.ownership,
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Status',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'status',
|
||||||
|
// eslint-disable-next-line react/display-name
|
||||||
|
render: enrolmentInfo => {
|
||||||
|
const status = enrolmentInfo.status.toLowerCase();
|
||||||
|
let color = '#f9ca24';
|
||||||
|
switch (status) {
|
||||||
|
case 'active':
|
||||||
|
color = '#badc58';
|
||||||
|
break;
|
||||||
|
case 'created':
|
||||||
|
color = '#6ab04c';
|
||||||
|
break;
|
||||||
|
case 'removed':
|
||||||
|
color = '#ff7979';
|
||||||
|
break;
|
||||||
|
case 'inactive':
|
||||||
|
color = '#f9ca24';
|
||||||
|
break;
|
||||||
|
case 'blocked':
|
||||||
|
color = '#636e72';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return <Tag color={color}>{status}</Tag>;
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Ownership',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
{
|
||||||
key: 'ownership',
|
title: 'Last Updated',
|
||||||
render: enrolmentInfo => enrolmentInfo.ownership
|
dataIndex: 'enrolmentInfo',
|
||||||
// todo add filtering options
|
key: 'dateOfLastUpdate',
|
||||||
|
// eslint-disable-next-line react/display-name
|
||||||
|
render: data => {
|
||||||
|
const { dateOfLastUpdate } = data;
|
||||||
|
const timeAgoString = getTimeAgo(dateOfLastUpdate);
|
||||||
|
return (
|
||||||
|
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
|
||||||
|
{timeAgoString}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Status',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'status',
|
|
||||||
render: (enrolmentInfo) => {
|
|
||||||
const status = enrolmentInfo.status.toLowerCase();
|
|
||||||
let color = "#f9ca24";
|
|
||||||
switch (status) {
|
|
||||||
case "active":
|
|
||||||
color = "#badc58";
|
|
||||||
break;
|
|
||||||
case "created":
|
|
||||||
color = "#6ab04c";
|
|
||||||
break;
|
|
||||||
case "removed":
|
|
||||||
color = "#ff7979";
|
|
||||||
break;
|
|
||||||
case "inactive":
|
|
||||||
color = "#f9ca24";
|
|
||||||
break;
|
|
||||||
case "blocked":
|
|
||||||
color = "#636e72";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return <Tag color={color}>{status}</Tag>;
|
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Last Updated',
|
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'dateOfLastUpdate',
|
|
||||||
render: (data) => {
|
|
||||||
const {dateOfLastUpdate} = data;
|
|
||||||
const timeAgoString = getTimeAgo(dateOfLastUpdate);
|
|
||||||
return <Tooltip title={new Date(dateOfLastUpdate).toString()}>{timeAgoString}</Tooltip>;
|
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const getTimeAgo = (time) => {
|
const getTimeAgo = time => {
|
||||||
const timeAgo = new TimeAgo('en-US');
|
const timeAgo = new TimeAgo('en-US');
|
||||||
return timeAgo.format(time);
|
return timeAgo.format(time);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReportDeviceTable extends React.Component {
|
class ReportDeviceTable extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
config = this.props.context;
|
||||||
TimeAgo.addLocale(en);
|
TimeAgo.addLocale(en);
|
||||||
this.state = {
|
this.state = {
|
||||||
data: [],
|
data: [],
|
||||||
pagination: {},
|
pagination: {},
|
||||||
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
paramsObj: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rowSelection = {
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
this.setState({
|
||||||
|
selectedRows: selectedRows,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rerender component when parameters change
|
||||||
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||||
|
if (prevProps.paramsObject !== this.props.paramsObject) {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
// get current page
|
||||||
|
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||||
|
|
||||||
|
this.props.paramsObject.offset = 10 * (currentPage - 1); // calculate the offset
|
||||||
|
this.props.paramsObject.limit = 10;
|
||||||
|
|
||||||
|
const encodedExtraParams = Object.keys(this.props.paramsObject)
|
||||||
|
.map(key => key + '=' + this.props.paramsObject[key])
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.props.paramsObject.from == null &&
|
||||||
|
this.props.paramsObject.to == null
|
||||||
|
) {
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/devices?' +
|
||||||
|
encodedExtraParams;
|
||||||
|
} else {
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/reports/devices?' +
|
||||||
|
encodedExtraParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send request to the invokerss
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: [],
|
data: res.data.data.devices,
|
||||||
paramsObj:{}
|
pagination,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
rowSelection = {
|
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
|
||||||
this.setState({
|
|
||||||
selectedRows: selectedRows
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
.catch(error => {
|
||||||
componentDidMount() {
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
this.fetch();
|
// todo display a popop with error
|
||||||
}
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
//Rerender component when parameters change
|
} else {
|
||||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
notification.error({
|
||||||
if(prevProps.paramsObject !== this.props.paramsObject){
|
message: 'There was a problem',
|
||||||
this.fetch();
|
duration: 0,
|
||||||
}
|
description: 'Error occurred while trying to load devices.',
|
||||||
}
|
});
|
||||||
|
|
||||||
//fetch data from api
|
|
||||||
fetch = (params = {}) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({loading: true});
|
|
||||||
// get current page
|
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
|
||||||
|
|
||||||
this.props.paramsObject.offset = 10 * (currentPage -1); //calculate the offset
|
|
||||||
this.props.paramsObject.limit = 10;
|
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(this.props.paramsObject)
|
|
||||||
.map(key => key + '=' + this.props.paramsObject[key]).join('&');
|
|
||||||
|
|
||||||
if(this.props.paramsObject.from==null && this.props.paramsObject.to==null){
|
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/devices?" + encodedExtraParams;
|
|
||||||
|
|
||||||
}else{
|
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/reports/devices?" + encodedExtraParams;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//send request to the invokerss
|
this.setState({ loading: false });
|
||||||
axios.get(apiUrl).then(res => {
|
});
|
||||||
if (res.status === 200) {
|
};
|
||||||
const pagination = {...this.state.pagination};
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
data: res.data.data.devices,
|
|
||||||
pagination,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch((error) => {
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
const pager = { ...this.state.pagination };
|
||||||
//todo display a popop with error
|
pager.current = pagination.current;
|
||||||
message.error('You are not logged in');
|
this.setState({
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
pagination: pager,
|
||||||
} else {
|
});
|
||||||
notification["error"]({
|
this.fetch({
|
||||||
message: "There was a problem",
|
results: pagination.pageSize,
|
||||||
duration: 0,
|
page: pagination.current,
|
||||||
description:"Error occurred while trying to load devices.",
|
sortField: sorter.field,
|
||||||
});
|
sortOrder: sorter.order,
|
||||||
}
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
this.setState({loading: false});
|
render() {
|
||||||
});
|
const { data, pagination, loading } = this.state;
|
||||||
};
|
return (
|
||||||
|
<div>
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
<Table
|
||||||
const pager = {...this.state.pagination};
|
columns={columns}
|
||||||
pager.current = pagination.current;
|
rowKey={record =>
|
||||||
this.setState({
|
record.deviceIdentifier +
|
||||||
pagination: pager,
|
record.enrolmentInfo.owner +
|
||||||
});
|
record.enrolmentInfo.ownership
|
||||||
this.fetch({
|
}
|
||||||
results: pagination.pageSize,
|
dataSource={data}
|
||||||
page: pagination.current,
|
pagination={{
|
||||||
sortField: sorter.field,
|
...pagination,
|
||||||
sortOrder: sorter.order,
|
size: 'small',
|
||||||
...filters,
|
// position: "top",
|
||||||
});
|
showTotal: (total, range) =>
|
||||||
};
|
`showing ${range[0]}-${range[1]} of ${total} devices`,
|
||||||
|
// showQuickJumper: true
|
||||||
render() {
|
}}
|
||||||
|
loading={loading}
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
onChange={this.handleTableChange}
|
||||||
return (
|
rowSelection={this.rowSelection}
|
||||||
<div>
|
/>
|
||||||
<Table
|
</div>
|
||||||
columns={columns}
|
);
|
||||||
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
|
}
|
||||||
dataSource={data}
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: "small",
|
|
||||||
// position: "top",
|
|
||||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
|
|
||||||
// showQuickJumper: true
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={this.rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(ReportDeviceTable);
|
export default withConfigContext(ReportDeviceTable);
|
||||||
|
|||||||
@ -16,66 +16,64 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {Component, Fragment} from "react";
|
import React, { Component, Fragment } from 'react';
|
||||||
import {
|
import {
|
||||||
Map,
|
Map,
|
||||||
TileLayer,
|
TileLayer,
|
||||||
Marker,
|
Marker,
|
||||||
Polyline, Popup, Tooltip
|
Polyline,
|
||||||
} from "react-leaflet";
|
Popup,
|
||||||
import {withConfigContext} from "../../../context/ConfigContext";
|
Tooltip,
|
||||||
|
} from 'react-leaflet';
|
||||||
|
import { withConfigContext } from '../../../context/ConfigContext';
|
||||||
|
|
||||||
class GeoCustomMap extends Component {
|
class GeoCustomMap extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
/**
|
||||||
super(props);
|
* Polyline draw for historical locations
|
||||||
}
|
* @param locationData - location data object
|
||||||
|
* @returns content
|
||||||
|
*/
|
||||||
|
polylineMarker = locationData => {
|
||||||
|
const polyMarkers = locationData.map(locationPoint => {
|
||||||
|
return [locationPoint.latitude, locationPoint.longitude];
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
return (
|
||||||
* Polyline draw for historical locations
|
<div style={{ display: 'none' }}>
|
||||||
* @param locationData - location data object
|
{
|
||||||
* @returns content
|
<Polyline color="green" positions={polyMarkers}>
|
||||||
*/
|
<Popup>on the way</Popup>
|
||||||
polylineMarker = (locationData) => {
|
</Polyline>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const polyMarkers = locationData
|
render() {
|
||||||
.map(locationPoint => {
|
const locationData = this.props.locationData;
|
||||||
return [locationPoint.latitude, locationPoint.longitude]
|
const config = this.props.context;
|
||||||
});
|
const attribution = config.geoMap.attribution;
|
||||||
|
const url = config.geoMap.url;
|
||||||
return (
|
const startingPoint = [locationData[0].latitude, locationData[0].longitude];
|
||||||
<div style={{display: "none"}}>{
|
const zoom = config.geoMap.defaultZoomLevel;
|
||||||
<Polyline color="green" positions={polyMarkers}>
|
return (
|
||||||
<Popup>on the way</Popup>
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5, padding: 5 }}>
|
||||||
</Polyline>
|
<Map center={startingPoint} zoom={zoom}>
|
||||||
}</div>
|
<TileLayer url={url} attribution={attribution} />
|
||||||
);
|
<Fragment>
|
||||||
};
|
{this.polylineMarker(locationData)}
|
||||||
|
<Marker position={startingPoint}>
|
||||||
render() {
|
<Tooltip>Starting Location</Tooltip>
|
||||||
const locationData = this.props.locationData;
|
</Marker>
|
||||||
const config = this.props.context;
|
</Fragment>
|
||||||
const attribution = config.geoMap.attribution;
|
</Map>
|
||||||
const url = config.geoMap.url;
|
</div>
|
||||||
const startingPoint = [locationData[0].latitude, locationData[0].longitude];
|
);
|
||||||
const zoom = config.geoMap.defaultZoomLevel;
|
}
|
||||||
return (
|
|
||||||
<div style={{backgroundColor: "#ffffff", borderRadius: 5, padding: 5}}>
|
|
||||||
<Map center={startingPoint} zoom={zoom}>
|
|
||||||
<TileLayer
|
|
||||||
url={url}
|
|
||||||
attribution={attribution}
|
|
||||||
/>
|
|
||||||
<Fragment>
|
|
||||||
{this.polylineMarker(locationData)}
|
|
||||||
<Marker position={startingPoint}>
|
|
||||||
<Tooltip>Starting Location</Tooltip>
|
|
||||||
</Marker>
|
|
||||||
</Fragment>
|
|
||||||
</Map>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(GeoCustomMap);
|
export default withConfigContext(GeoCustomMap);
|
||||||
|
|||||||
@ -16,266 +16,300 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import moment from "moment";
|
import moment from 'moment';
|
||||||
import {Button, Select, message, notification, Tag, Tooltip, Empty, DatePicker} from "antd";
|
import {
|
||||||
import axios from "axios";
|
Button,
|
||||||
import {withConfigContext} from "../../../context/ConfigContext";
|
Select,
|
||||||
import GeoCustomMap from "../geo-custom-map/GeoCustomMap";
|
message,
|
||||||
import "./GeoDashboard.css";
|
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 {
|
class GeoDashboard extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
constructor(props) {
|
super(props);
|
||||||
super(props);
|
let start = moment(
|
||||||
let start = moment(
|
new Date(
|
||||||
new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), 0, 0, 0, 0)
|
new Date().getFullYear(),
|
||||||
);
|
new Date().getMonth(),
|
||||||
let end = moment(start)
|
new Date().getDate(),
|
||||||
.add(1, "days")
|
0,
|
||||||
.subtract(1, "seconds");
|
0,
|
||||||
this.state = {
|
0,
|
||||||
deviceData: [],
|
0,
|
||||||
selectedDevice: '',
|
),
|
||||||
locationData: [],
|
);
|
||||||
loading: false,
|
let end = moment(start)
|
||||||
start: start,
|
.add(1, 'days')
|
||||||
end: end,
|
.subtract(1, 'seconds');
|
||||||
buttonTooltip: "Fetch Locations",
|
this.state = {
|
||||||
};
|
deviceData: [],
|
||||||
}
|
selectedDevice: '',
|
||||||
|
locationData: [],
|
||||||
componentDidMount() {
|
loading: false,
|
||||||
this.fetchDevices();
|
start: start,
|
||||||
// this.fetchCurrentLocation();
|
end: end,
|
||||||
}
|
buttonTooltip: 'Fetch Locations',
|
||||||
|
|
||||||
/**
|
|
||||||
* Call back on apply button in the date time picker
|
|
||||||
* @param startDate - start date
|
|
||||||
* @param endDate - end date
|
|
||||||
*/
|
|
||||||
applyCallback = (dates, dateStrings) => {
|
|
||||||
console.log("Apply Callback");
|
|
||||||
this.setState({
|
|
||||||
start: dateStrings[0],
|
|
||||||
end: dateStrings[1]
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
componentDidMount() {
|
||||||
* Api call handle on fetch location date button
|
this.fetchDevices();
|
||||||
*/
|
// this.fetchCurrentLocation();
|
||||||
handleApiCall = () => {
|
}
|
||||||
|
|
||||||
if (this.state.selectedDevice && this.state.start && this.state.end) {
|
/**
|
||||||
const toInMills = moment(this.state.end);
|
* Call back on apply button in the date time picker
|
||||||
const fromInMills = moment(this.state.start);
|
* @param startDate - start date
|
||||||
const deviceType = this.state.selectedDevice.type;
|
* @param endDate - end date
|
||||||
const deviceId = this.state.selectedDevice.deviceIdentifier;
|
*/
|
||||||
const config = this.props.context;
|
applyCallback = (dates, dateStrings) => {
|
||||||
this.setState({loading: true});
|
console.log('Apply Callback');
|
||||||
|
this.setState({
|
||||||
|
start: dateStrings[0],
|
||||||
|
end: dateStrings[1],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
axios.get(window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt
|
/**
|
||||||
+ "/devices/" + deviceType + "/" + deviceId + "/location-history?" + "from=" + fromInMills + "&to=" +
|
* Api call handle on fetch location date button
|
||||||
toInMills,).then(res => {
|
*/
|
||||||
if (res.status === 200) {
|
handleApiCall = () => {
|
||||||
const locationData = JSON.parse(res.data.data);
|
if (this.state.selectedDevice && this.state.start && this.state.end) {
|
||||||
this.setState({
|
const toInMills = moment(this.state.end);
|
||||||
loading: false,
|
const fromInMills = moment(this.state.start);
|
||||||
locationData,
|
const deviceType = this.state.selectedDevice.type;
|
||||||
});
|
const deviceId = this.state.selectedDevice.deviceIdentifier;
|
||||||
}
|
const config = this.props.context;
|
||||||
}).catch((error) => {
|
this.setState({ loading: true });
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to fetch locations......",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
axios
|
||||||
console.log(error);
|
.get(
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/devices/' +
|
||||||
|
deviceType +
|
||||||
|
'/' +
|
||||||
|
deviceId +
|
||||||
|
'/location-history?' +
|
||||||
|
'from=' +
|
||||||
|
fromInMills +
|
||||||
|
'&to=' +
|
||||||
|
toInMills,
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const locationData = JSON.parse(res.data.data);
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
locationData,
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
notification["error"]({
|
})
|
||||||
message: "There was a problem",
|
.catch(error => {
|
||||||
duration: 0,
|
if (
|
||||||
description:
|
error.hasOwnProperty('response') &&
|
||||||
"Please provide a date range and a device.",
|
error.response.status === 401
|
||||||
});
|
) {
|
||||||
}
|
message.error('You are not logged in');
|
||||||
};
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
'Error occurred while trying to fetch locations......',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
this.setState({ loading: false });
|
||||||
* Device dropdown list handler
|
console.log(error);
|
||||||
* @param e - selected device data
|
|
||||||
*/
|
|
||||||
handleDeviceList = (e) => {
|
|
||||||
let selectedDevice = this.state.deviceData[e];
|
|
||||||
this.setState({selectedDevice})
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* render fetch location button
|
|
||||||
*/
|
|
||||||
fetchLocationButton = () => {
|
|
||||||
let flag;
|
|
||||||
let toolTip = "";
|
|
||||||
if (this.state.selectedDevice === "") {
|
|
||||||
flag = true;
|
|
||||||
toolTip = "Please select a Device";
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Tooltip placement="rightBottom" title={toolTip}>
|
|
||||||
<Button disabled={flag}
|
|
||||||
onClick={this.handleApiCall}>
|
|
||||||
Fetch Locations
|
|
||||||
</Button>
|
|
||||||
</Tooltip>);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fetches device data to populate the dropdown list
|
|
||||||
*/
|
|
||||||
fetchDevices = () => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({loading: true});
|
|
||||||
|
|
||||||
axios.get(
|
|
||||||
window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/devices?excludeStatus=REMOVED",).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
deviceData: res.data.data.devices,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to load devices.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
});
|
||||||
};
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Please provide a date range and a device.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Geo Dashboard controller
|
* Device dropdown list handler
|
||||||
*/
|
* @param e - selected device data
|
||||||
controllerBar = () => {
|
*/
|
||||||
|
handleDeviceList = e => {
|
||||||
|
let selectedDevice = this.state.deviceData[e];
|
||||||
|
this.setState({ selectedDevice });
|
||||||
|
};
|
||||||
|
|
||||||
const {RangePicker} = DatePicker;
|
/**
|
||||||
let now = new Date();
|
* render fetch location button
|
||||||
let start = moment(
|
*/
|
||||||
new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0)
|
fetchLocationButton = () => {
|
||||||
);
|
let flag;
|
||||||
let end = moment(start)
|
let toolTip = '';
|
||||||
.add(1, "days")
|
if (this.state.selectedDevice === '') {
|
||||||
.subtract(1, "seconds");
|
flag = true;
|
||||||
let ranges = {
|
toolTip = 'Please select a Device';
|
||||||
"Today Only": [moment(start), moment(end)],
|
}
|
||||||
"Yesterday Only": [
|
return (
|
||||||
moment(start).subtract(1, "days"),
|
<Tooltip placement="rightBottom" title={toolTip}>
|
||||||
moment(end).subtract(1, "days")
|
<Button disabled={flag} onClick={this.handleApiCall}>
|
||||||
],
|
Fetch Locations
|
||||||
"3 Days": [moment(start).subtract(3, "days"), moment(end)],
|
</Button>
|
||||||
"5 Days": [moment(start).subtract(5, "days"), moment(end)],
|
</Tooltip>
|
||||||
"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;
|
/**
|
||||||
|
* fetches device data to populate the dropdown list
|
||||||
|
*/
|
||||||
|
fetchDevices = () => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
return (
|
axios
|
||||||
<div className="controllerDiv">
|
.get(
|
||||||
<RangePicker
|
window.location.origin +
|
||||||
ranges={ranges}
|
config.serverConfig.invoker.uri +
|
||||||
style={{marginRight: 20}}
|
config.serverConfig.invoker.deviceMgt +
|
||||||
showTime
|
'/devices?excludeStatus=REMOVED',
|
||||||
format="YYYY-MM-DD HH:mm:ss"
|
)
|
||||||
defaultValue={[this.state.start, this.state.end]}
|
.then(res => {
|
||||||
onChange={this.applyCallback}
|
if (res.status === 200) {
|
||||||
|
this.setState({
|
||||||
/>
|
loading: false,
|
||||||
|
deviceData: res.data.data.devices,
|
||||||
<Select
|
});
|
||||||
showSearch
|
}
|
||||||
style={{width: 220, marginRight: 20}}
|
})
|
||||||
placeholder="Select a Device"
|
.catch(error => {
|
||||||
optionFilterProp="children"
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
onChange={this.handleDeviceList}
|
message.error('You are not logged in');
|
||||||
filterOption={(input, option) =>
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
} else {
|
||||||
}
|
notification.error({
|
||||||
>
|
message: 'There was a problem',
|
||||||
{deviceData.map((device, index) =>
|
duration: 0,
|
||||||
<Select.Option key={index} value={index}>
|
description: 'Error occurred while trying to load devices.',
|
||||||
{device.name + " "}{this.statusTag(device)}
|
});
|
||||||
</Select.Option>)}
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
{this.fetchLocationButton()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates color based tags on device status
|
|
||||||
* @param device - device object
|
|
||||||
*/
|
|
||||||
statusTag = (device) => {
|
|
||||||
|
|
||||||
const status = device.enrolmentInfo.status.toLowerCase();
|
|
||||||
let color = "#f9ca24";
|
|
||||||
switch (status) {
|
|
||||||
case "active":
|
|
||||||
color = "#badc58";
|
|
||||||
break;
|
|
||||||
case "created":
|
|
||||||
color = "#6ab04c";
|
|
||||||
break;
|
|
||||||
case "inactive":
|
|
||||||
color = "#f9ca24";
|
|
||||||
break;
|
|
||||||
case "blocked":
|
|
||||||
color = "#636e72";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Tag color={color}>{status}</Tag>
|
this.setState({ loading: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geo Dashboard controller
|
||||||
|
*/
|
||||||
|
controllerBar = () => {
|
||||||
|
const { RangePicker } = DatePicker;
|
||||||
|
let now = new Date();
|
||||||
|
let start = moment(
|
||||||
|
new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0),
|
||||||
|
);
|
||||||
|
let end = moment(start)
|
||||||
|
.add(1, 'days')
|
||||||
|
.subtract(1, 'seconds');
|
||||||
|
let ranges = {
|
||||||
|
'Today Only': [moment(start), moment(end)],
|
||||||
|
'Yesterday Only': [
|
||||||
|
moment(start).subtract(1, 'days'),
|
||||||
|
moment(end).subtract(1, 'days'),
|
||||||
|
],
|
||||||
|
'3 Days': [moment(start).subtract(3, 'days'), moment(end)],
|
||||||
|
'5 Days': [moment(start).subtract(5, 'days'), moment(end)],
|
||||||
|
'1 Week': [moment(start).subtract(7, 'days'), moment(end)],
|
||||||
|
'2 Weeks': [moment(start).subtract(14, 'days'), moment(end)],
|
||||||
|
'1 Month': [moment(start).subtract(1, 'months'), moment(end)],
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
let { deviceData } = this.state;
|
||||||
const locationData = [...this.state.locationData];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="controllerDiv">
|
||||||
{this.controllerBar()}
|
<RangePicker
|
||||||
{(locationData.length > 0) ?
|
ranges={ranges}
|
||||||
<GeoCustomMap locationData={locationData}/>
|
style={{ marginRight: 20 }}
|
||||||
:
|
showTime
|
||||||
<Empty/>
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
}
|
defaultValue={[this.state.start, this.state.end]}
|
||||||
</div>
|
onChange={this.applyCallback}
|
||||||
);
|
/>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
showSearch
|
||||||
|
style={{ width: 220, marginRight: 20 }}
|
||||||
|
placeholder="Select a Device"
|
||||||
|
optionFilterProp="children"
|
||||||
|
onChange={this.handleDeviceList}
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >=
|
||||||
|
0
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{deviceData.map((device, index) => (
|
||||||
|
<Select.Option key={index} value={index}>
|
||||||
|
{device.name + ' '}
|
||||||
|
{this.statusTag(device)}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
{this.fetchLocationButton()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates color based tags on device status
|
||||||
|
* @param device - device object
|
||||||
|
*/
|
||||||
|
statusTag = device => {
|
||||||
|
const status = device.enrolmentInfo.status.toLowerCase();
|
||||||
|
let color = '#f9ca24';
|
||||||
|
switch (status) {
|
||||||
|
case 'active':
|
||||||
|
color = '#badc58';
|
||||||
|
break;
|
||||||
|
case 'created':
|
||||||
|
color = '#6ab04c';
|
||||||
|
break;
|
||||||
|
case 'inactive':
|
||||||
|
color = '#f9ca24';
|
||||||
|
break;
|
||||||
|
case 'blocked':
|
||||||
|
color = '#636e72';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return <Tag color={color}>{status}</Tag>;
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const locationData = [...this.state.locationData];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container">
|
||||||
|
{this.controllerBar()}
|
||||||
|
{locationData.length > 0 ? (
|
||||||
|
<GeoCustomMap locationData={locationData} />
|
||||||
|
) : (
|
||||||
|
<Empty />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(GeoDashboard);
|
export default withConfigContext(GeoDashboard);
|
||||||
|
|||||||
@ -16,160 +16,159 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {Button, Form, Input, message, Modal, notification, Typography} from "antd";
|
import { Button, Form, Input, message, Modal, notification } from 'antd';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
let config = null;
|
|
||||||
|
|
||||||
class AddGroup extends React.Component {
|
class AddGroup extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
addModalVisible: false,
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
onConfirmAdGroup = () => {
|
||||||
super(props);
|
const config = this.props.context;
|
||||||
config = this.props.context;
|
|
||||||
this.state = {
|
const groupData = {
|
||||||
addModalVisible: false,
|
name: this.state.name,
|
||||||
name:'',
|
description: this.state.description,
|
||||||
description:'',
|
};
|
||||||
|
|
||||||
|
// send request to the invoker
|
||||||
|
axios
|
||||||
|
.post(
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/groups',
|
||||||
|
groupData,
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 201) {
|
||||||
|
this.props.fetchGroups();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully added the group.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.catch(error => {
|
||||||
onConfirmAdGroup = () => {
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
const config = this.props.context;
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
const groupData = {
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
name: this.state.name,
|
} else {
|
||||||
description: this.state.description
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to add group.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
//send request to the invoker
|
openAddModal = () => {
|
||||||
axios.post(
|
this.setState({
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
addModalVisible: true,
|
||||||
config.serverConfig.invoker.deviceMgt +
|
});
|
||||||
"/groups",
|
};
|
||||||
groupData,
|
|
||||||
{headers: {'Content-Type': 'application/json'}}
|
handleAddOk = e => {
|
||||||
).then(res => {
|
this.props.form.validateFields(err => {
|
||||||
if (res.status === 201) {
|
if (!err) {
|
||||||
this.props.fetchGroups();
|
this.onConfirmAdGroup();
|
||||||
notification["success"]({
|
this.setState({
|
||||||
message: "Done",
|
addModalVisible: false,
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully added the group.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to add group.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
openAddModal = () => {
|
handleAddCancel = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
addModalVisible:true
|
addModalVisible: false,
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleAddOk = e => {
|
onChangeName = e => {
|
||||||
this.props.form.validateFields(err => {
|
this.setState({
|
||||||
if (!err) {
|
name: e.currentTarget.value,
|
||||||
this.onConfirmAdGroup();
|
});
|
||||||
this.setState({
|
};
|
||||||
addModalVisible: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleAddCancel = e => {
|
onChangeDescription = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
addModalVisible: false,
|
description: e.currentTarget.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onChangeName = (e) => {
|
render() {
|
||||||
this.setState({
|
const { getFieldDecorator } = this.props.form;
|
||||||
name:e.currentTarget.value
|
return (
|
||||||
})
|
<div>
|
||||||
};
|
<div>
|
||||||
|
<Button
|
||||||
onChangeDescription = (e) => {
|
type="primary"
|
||||||
this.setState({
|
icon="plus"
|
||||||
description:e.currentTarget.value
|
size={'default'}
|
||||||
})
|
onClick={this.openAddModal}
|
||||||
};
|
>
|
||||||
|
Add Group
|
||||||
render() {
|
</Button>
|
||||||
const { getFieldDecorator } = this.props.form;
|
</div>
|
||||||
return(
|
<div>
|
||||||
<div>
|
<Modal
|
||||||
<div>
|
title="ADD NEW GROUP"
|
||||||
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal}>
|
width="40%"
|
||||||
Add Group
|
visible={this.state.addModalVisible}
|
||||||
</Button>
|
onOk={this.handleAddOk}
|
||||||
</div>
|
onCancel={this.handleAddCancel}
|
||||||
<div>
|
footer={[
|
||||||
<Modal
|
<Button key="cancel" onClick={this.handleAddCancel}>
|
||||||
title="ADD NEW GROUP"
|
Cancel
|
||||||
width="40%"
|
</Button>,
|
||||||
visible={this.state.addModalVisible}
|
<Button key="submit" type="primary" onClick={this.handleAddOk}>
|
||||||
onOk={this.handleAddOk}
|
Submit
|
||||||
onCancel={this.handleAddCancel}
|
</Button>,
|
||||||
footer={[
|
]}
|
||||||
<Button key="cancel" onClick={this.handleAddCancel}>
|
>
|
||||||
Cancel
|
<div style={{ alignItems: 'center' }}>
|
||||||
</Button>,
|
<p>Create new device group on IoT Server.</p>
|
||||||
<Button key="submit" type="primary" onClick={this.handleAddOk}>
|
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
||||||
Submit
|
<Form.Item label="Name" style={{ display: 'block' }}>
|
||||||
</Button>,
|
{getFieldDecorator('name', {
|
||||||
]}
|
rules: [
|
||||||
>
|
{
|
||||||
<div style={{alignItems:"center"}}>
|
required: true,
|
||||||
<p>Create new device group on IoT Server.</p>
|
message: 'Please input group name',
|
||||||
<Form
|
},
|
||||||
labelCol={{ span: 5 }}
|
],
|
||||||
wrapperCol={{ span: 18 }}
|
})(<Input onChange={this.onChangeName} />)}
|
||||||
>
|
</Form.Item>
|
||||||
<Form.Item label="Name" style={{display:"block"}}>
|
<Form.Item label="Description" style={{ display: 'block' }}>
|
||||||
{getFieldDecorator('name', {
|
{getFieldDecorator('description', {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: 'Please input group name',
|
message: 'Please input group description',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})(<Input onChange={this.onChangeName}/>)}
|
})(<Input onChange={this.onChangeDescription} />)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Description" style={{display:"block"}}>
|
</Form>
|
||||||
{getFieldDecorator('description', {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please input group description',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input onChange={this.onChangeDescription}/>)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
</Modal>
|
||||||
}
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create({name: 'add-group'})(AddGroup));
|
export default withConfigContext(Form.create({ name: 'add-group' })(AddGroup));
|
||||||
|
|||||||
@ -16,364 +16,380 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Divider,
|
Divider,
|
||||||
Form,
|
Form,
|
||||||
Icon,
|
Icon,
|
||||||
Input,
|
Input,
|
||||||
message,
|
message,
|
||||||
Modal,
|
Modal,
|
||||||
notification,
|
notification,
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
Select,
|
Select,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography
|
Typography,
|
||||||
} from "antd";
|
} from 'antd';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
|
||||||
const {Text} = Typography;
|
const { Text } = Typography;
|
||||||
let config = null;
|
|
||||||
|
|
||||||
class GroupActions extends React.Component {
|
class GroupActions extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
editModalVisible: false,
|
||||||
|
shareModalVisible: false,
|
||||||
|
name: this.props.data.name,
|
||||||
|
description: this.props.data.description,
|
||||||
|
groupDataObject: {},
|
||||||
|
rolesData: [],
|
||||||
|
shareRolesData: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
onConfirmDeleteGroup = () => {
|
||||||
super(props);
|
const config = this.props.context;
|
||||||
config = this.props.context;
|
|
||||||
this.state = {
|
// send request to the invoker
|
||||||
editModalVisible: false,
|
axios
|
||||||
shareModalVisible: false,
|
.delete(
|
||||||
name:this.props.data.name,
|
window.location.origin +
|
||||||
description:this.props.data.description,
|
config.serverConfig.invoker.uri +
|
||||||
groupDataObject:{},
|
config.serverConfig.invoker.deviceMgt +
|
||||||
rolesData:[],
|
'/groups/id/' +
|
||||||
shareRolesData:[]
|
this.props.data.id,
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchGroups();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully deleted the group.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to delete group.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onConfirmDeleteGroup = () => {
|
onConfirmUpdateGroup = data => {
|
||||||
const config = this.props.context;
|
const config = this.props.context;
|
||||||
|
|
||||||
//send request to the invoker
|
// send request to the invoker
|
||||||
axios.delete(
|
axios
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
.put(
|
||||||
config.serverConfig.invoker.deviceMgt +
|
window.location.origin +
|
||||||
"/groups/id/" + this.props.data.id,
|
config.serverConfig.invoker.uri +
|
||||||
{headers: {'Content-Type': 'application/json'}}
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/groups/id/' +
|
||||||
|
this.props.data.id,
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchGroups();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully updated the group.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to update group.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
).then(res => {
|
fetchUserRoles = (params = {}) => {
|
||||||
if (res.status === 200) {
|
const config = this.props.context;
|
||||||
this.props.fetchGroups();
|
|
||||||
notification["success"]({
|
const apiUrl =
|
||||||
message: "Done",
|
window.location.origin +
|
||||||
duration: 4,
|
config.serverConfig.invoker.uri +
|
||||||
description:
|
config.serverConfig.invoker.deviceMgt +
|
||||||
"Successfully deleted the group.",
|
'/roles';
|
||||||
});
|
|
||||||
}
|
// send request to the invokerss
|
||||||
}).catch((error) => {
|
axios
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
.get(apiUrl)
|
||||||
//todo display a popop with error
|
.then(res => {
|
||||||
message.error('You are not logged in');
|
if (res.status === 200) {
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
this.setState({
|
||||||
} else {
|
rolesData: res.data.data.roles,
|
||||||
notification["error"]({
|
});
|
||||||
message: "There was a problem",
|
}
|
||||||
duration: 0,
|
})
|
||||||
description:
|
.catch(error => {
|
||||||
"Error occurred while trying to delete group.",
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
});
|
// todo display a popop with error
|
||||||
}
|
message.error('You are not logged in');
|
||||||
});
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load roles.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onConfirmShareGroup = data => {
|
||||||
|
const config = this.props.context;
|
||||||
|
|
||||||
|
// send request to the invoker
|
||||||
|
axios
|
||||||
|
.post(
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/groups/id/' +
|
||||||
|
this.props.data.id +
|
||||||
|
'/share',
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchGroups();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully shared the group.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to share group.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
openEditModal = () => {
|
||||||
|
this.setState({
|
||||||
|
editModalVisible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
openShareModal = () => {
|
||||||
|
this.fetchUserRoles();
|
||||||
|
this.setState({
|
||||||
|
shareModalVisible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleEditOk = e => {
|
||||||
|
const groupDataObject = {
|
||||||
|
name: this.state.name,
|
||||||
|
description: this.state.description,
|
||||||
|
id: this.props.data.id,
|
||||||
|
owner: this.props.data.owner,
|
||||||
|
groupProperties: this.props.data.groupProperties,
|
||||||
};
|
};
|
||||||
|
|
||||||
onConfirmUpdateGroup = (data) => {
|
this.setState({ groupDataObject });
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
//send request to the invoker
|
this.props.form.validateFields(err => {
|
||||||
axios.put(
|
if (!err) {
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
this.onConfirmUpdateGroup(this.state.groupDataObject);
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/groups/id/" + this.props.data.id,
|
|
||||||
data
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchGroups();
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully updated the group.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to update group.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchUserRoles = (params = {}) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/roles";
|
|
||||||
|
|
||||||
//send request to the invokerss
|
|
||||||
axios.get(apiUrl).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
rolesData: res.data.data.roles,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load roles.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmShareGroup = (data) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
//send request to the invoker
|
|
||||||
axios.post(
|
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/groups/id/" + this.props.data.id + "/share",
|
|
||||||
data
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchGroups();
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully shared the group.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to share group.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
openEditModal = () => {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
editModalVisible:true
|
editModalVisible: false,
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
openShareModal = () => {
|
|
||||||
this.fetchUserRoles();
|
|
||||||
this.setState({
|
|
||||||
shareModalVisible:true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEditOk = e => {
|
|
||||||
this.state.groupDataObject = {
|
|
||||||
name:this.state.name,
|
|
||||||
description:this.state.description,
|
|
||||||
id:this.props.data.id,
|
|
||||||
owner:this.props.data.owner,
|
|
||||||
groupProperties:this.props.data.groupProperties
|
|
||||||
};
|
|
||||||
this.props.form.validateFields(err => {
|
|
||||||
if (!err) {
|
|
||||||
this.onConfirmUpdateGroup(this.state.groupDataObject);
|
|
||||||
this.setState({
|
|
||||||
editModalVisible: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
handleEditCancel = e => {
|
handleEditCancel = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
editModalVisible: false,
|
editModalVisible: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleShareOk = e => {
|
handleShareOk = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
shareModalVisible: false,
|
shareModalVisible: false,
|
||||||
});
|
});
|
||||||
this.onConfirmShareGroup(this.state.shareRolesData);
|
this.onConfirmShareGroup(this.state.shareRolesData);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleShareCancel = e => {
|
handleShareCancel = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
shareModalVisible: false,
|
shareModalVisible: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onChangeName = (e) => {
|
onChangeName = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
name:e.currentTarget.value
|
name: e.currentTarget.value,
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onChangeDescription = (e) => {
|
onChangeDescription = e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
description:e.currentTarget.value
|
description: e.currentTarget.value,
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleRolesDropdownChange = (value) => {
|
handleRolesDropdownChange = value => {
|
||||||
this.setState({
|
this.setState({
|
||||||
shareRolesData:value
|
shareRolesData: value,
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const isAdminGroups = this.props.data.id==1 || this.props.data.id==2;
|
const isAdminGroups = this.props.data.id == 1 || this.props.data.id == 2;
|
||||||
const { Option } = Select;
|
const { getFieldDecorator } = this.props.form;
|
||||||
const { getFieldDecorator } = this.props.form;
|
let item = this.state.rolesData.map(data => (
|
||||||
let item = this.state.rolesData.map((data) =>
|
<Select.Option value={data} key={data}>
|
||||||
<Select.Option
|
{data}
|
||||||
value={data}
|
</Select.Option>
|
||||||
key={data}>
|
));
|
||||||
{data}
|
return (
|
||||||
</Select.Option>);
|
<div>
|
||||||
return(
|
<div style={{ display: isAdminGroups ? 'none' : 'inline' }}>
|
||||||
<div>
|
<Tooltip placement="top" title={'Share Group'}>
|
||||||
<div style={{display:isAdminGroups ? "none" : "inline"}}>
|
<a>
|
||||||
<Tooltip placement="top" title={"Share Group"}>
|
<Icon type="share-alt" onClick={this.openShareModal} />
|
||||||
<a><Icon type="share-alt" onClick={this.openShareModal}/></a>
|
</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Divider type="vertical" />
|
<Divider type="vertical" />
|
||||||
<Tooltip placement="top" title={"Edit Group"}>
|
<Tooltip placement="top" title={'Edit Group'}>
|
||||||
<a><Icon type="edit" onClick={this.openEditModal}/></a>
|
<a>
|
||||||
</Tooltip>
|
<Icon type="edit" onClick={this.openEditModal} />
|
||||||
<Divider type="vertical" />
|
</a>
|
||||||
<Tooltip placement="bottom" title={"Delete Group"}>
|
</Tooltip>
|
||||||
<Popconfirm
|
<Divider type="vertical" />
|
||||||
placement="top"
|
<Tooltip placement="bottom" title={'Delete Group'}>
|
||||||
title={"Are you sure?"}
|
<Popconfirm
|
||||||
onConfirm={this.onConfirmDeleteGroup}
|
placement="top"
|
||||||
okText="Ok"
|
title={'Are you sure?'}
|
||||||
cancelText="Cancel">
|
onConfirm={this.onConfirmDeleteGroup}
|
||||||
<a><Text type="danger"><Icon type="delete"/></Text></a>
|
okText="Ok"
|
||||||
</Popconfirm>
|
cancelText="Cancel"
|
||||||
</Tooltip>
|
>
|
||||||
</div>
|
<a>
|
||||||
<div>
|
<Text type="danger">
|
||||||
<Modal
|
<Icon type="delete" />
|
||||||
title="Update Group"
|
</Text>
|
||||||
width="40%"
|
</a>
|
||||||
visible={this.state.editModalVisible}
|
</Popconfirm>
|
||||||
onOk={this.handleEditOk}
|
</Tooltip>
|
||||||
onCancel={this.handleEditCancel}
|
</div>
|
||||||
footer={[
|
<div>
|
||||||
<Button key="cancel" onClick={this.handleEditCancel}>
|
<Modal
|
||||||
Cancel
|
title="Update Group"
|
||||||
</Button>,
|
width="40%"
|
||||||
<Button key="submit" type="primary" onClick={this.handleEditOk}>
|
visible={this.state.editModalVisible}
|
||||||
Submit
|
onOk={this.handleEditOk}
|
||||||
</Button>,
|
onCancel={this.handleEditCancel}
|
||||||
]}
|
footer={[
|
||||||
>
|
<Button key="cancel" onClick={this.handleEditCancel}>
|
||||||
<div style={{alignItems:"center"}}>
|
Cancel
|
||||||
<p>Enter new name and description for the group</p>
|
</Button>,
|
||||||
<Form
|
<Button key="submit" type="primary" onClick={this.handleEditOk}>
|
||||||
labelCol={{ span: 5 }}
|
Submit
|
||||||
wrapperCol={{ span: 18 }}
|
</Button>,
|
||||||
>
|
]}
|
||||||
<Form.Item label="Name" style={{display:"block"}}>
|
>
|
||||||
{getFieldDecorator(
|
<div style={{ alignItems: 'center' }}>
|
||||||
'name',
|
<p>Enter new name and description for the group</p>
|
||||||
{
|
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
||||||
initialValue: this.props.data.name,
|
<Form.Item label="Name" style={{ display: 'block' }}>
|
||||||
rules: [
|
{getFieldDecorator('name', {
|
||||||
{
|
initialValue: this.props.data.name,
|
||||||
required: true,
|
rules: [
|
||||||
message: 'Please input group name',
|
{
|
||||||
},
|
required: true,
|
||||||
],
|
message: 'Please input group name',
|
||||||
})(<Input
|
},
|
||||||
onChange={this.onChangeName}/>)}
|
],
|
||||||
</Form.Item>
|
})(<Input onChange={this.onChangeName} />)}
|
||||||
<Form.Item label="Description" style={{display:"block"}}>
|
</Form.Item>
|
||||||
{getFieldDecorator(
|
<Form.Item label="Description" style={{ display: 'block' }}>
|
||||||
'description',
|
{getFieldDecorator('description', {
|
||||||
{
|
initialValue: this.props.data.description,
|
||||||
initialValue: this.props.data.description,
|
rules: [
|
||||||
rules: [
|
{
|
||||||
{
|
required: true,
|
||||||
required: true,
|
message: 'Please input group description',
|
||||||
message: 'Please input group description',
|
},
|
||||||
},
|
],
|
||||||
],
|
})(<Input onChange={this.onChangeDescription} />)}
|
||||||
})(<Input
|
</Form.Item>
|
||||||
onChange={this.onChangeDescription}/>)}
|
</Form>
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="Share Group"
|
|
||||||
width="500px"
|
|
||||||
visible={this.state.shareModalVisible}
|
|
||||||
onOk={this.handleShareOk}
|
|
||||||
onCancel={this.handleShareCancel}
|
|
||||||
footer={[
|
|
||||||
<Button key="new-role" onClick={this.handleShareCancel}>
|
|
||||||
New Role
|
|
||||||
</Button>,
|
|
||||||
<Button key="new-role-selection" onClick={this.handleShareCancel}>
|
|
||||||
New Role from Selection
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.handleShareOk}>
|
|
||||||
Share
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<p>Select user role(s)</p>
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
defaultValue={"admin"}
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
onChange={this.handleRolesDropdownChange}>
|
|
||||||
{item}
|
|
||||||
</Select>,
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
</Modal>
|
||||||
}
|
</div>
|
||||||
|
<div>
|
||||||
|
<Modal
|
||||||
|
title="Share Group"
|
||||||
|
width="500px"
|
||||||
|
visible={this.state.shareModalVisible}
|
||||||
|
onOk={this.handleShareOk}
|
||||||
|
onCancel={this.handleShareCancel}
|
||||||
|
footer={[
|
||||||
|
<Button key="new-role" onClick={this.handleShareCancel}>
|
||||||
|
New Role
|
||||||
|
</Button>,
|
||||||
|
<Button key="new-role-selection" onClick={this.handleShareCancel}>
|
||||||
|
New Role from Selection
|
||||||
|
</Button>,
|
||||||
|
<Button key="submit" type="primary" onClick={this.handleShareOk}>
|
||||||
|
Share
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<p>Select user role(s)</p>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
defaultValue={'admin'}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
onChange={this.handleRolesDropdownChange}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</Select>
|
||||||
|
,
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create({name: 'group-actions'})(GroupActions));
|
export default withConfigContext(
|
||||||
|
Form.create({ name: 'group-actions' })(GroupActions),
|
||||||
|
);
|
||||||
|
|||||||
@ -16,193 +16,191 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {message, notification, Table, Typography} from "antd";
|
import { message, notification, Table } from 'antd';
|
||||||
import TimeAgo from 'javascript-time-ago'
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
import GroupActions from "./GroupActions";
|
import GroupActions from './GroupActions';
|
||||||
import AddGroup from "./AddGroup";
|
import AddGroup from './AddGroup';
|
||||||
import Filter from "../Utils/Filter/Filter";
|
import Filter from '../Utils/Filter/Filter';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
const searchFields = [
|
const searchFields = [
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
placeholder: 'Name'
|
placeholder: 'Name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
placeholder: 'Owner'
|
placeholder: 'Owner',
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let config = null;
|
|
||||||
let apiUrl;
|
let apiUrl;
|
||||||
|
|
||||||
const getTimeAgo = (time) => {
|
|
||||||
const timeAgo = new TimeAgo('en-US');
|
|
||||||
return timeAgo.format(time);
|
|
||||||
};
|
|
||||||
|
|
||||||
class GroupsTable extends React.Component {
|
class GroupsTable extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
TimeAgo.addLocale(en);
|
||||||
TimeAgo.addLocale(en);
|
this.state = {
|
||||||
this.state = {
|
data: [],
|
||||||
data: [],
|
pagination: {},
|
||||||
pagination: {},
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
columns = [
|
||||||
|
{
|
||||||
|
title: 'Group Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Owner',
|
||||||
|
dataIndex: 'owner',
|
||||||
|
key: 'owner',
|
||||||
|
// render: enrolmentInfo => enrolmentInfo.owner
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Description',
|
||||||
|
dataIndex: 'description',
|
||||||
|
key: 'description',
|
||||||
|
// render: enrolmentInfo => enrolmentInfo.ownership
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'action',
|
||||||
|
render: (id, row) => (
|
||||||
|
<span>
|
||||||
|
<GroupActions data={row} fetchGroups={this.fetchGroups} />
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
rowSelection = {
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
this.setState({
|
||||||
|
selectedRows: selectedRows,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchGroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetchGroups = (params = {}, filters = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
// get current page
|
||||||
|
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (currentPage - 1), // calculate the offset
|
||||||
|
limit: 10,
|
||||||
|
...filters,
|
||||||
|
};
|
||||||
|
|
||||||
|
const encodedExtraParams = Object.keys(extraParams)
|
||||||
|
.map(key => key + '=' + extraParams[key])
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/admin/groups?' +
|
||||||
|
encodedExtraParams;
|
||||||
|
|
||||||
|
// send request to the invokerss
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: []
|
data: res.data.data,
|
||||||
};
|
pagination,
|
||||||
}
|
});
|
||||||
|
}
|
||||||
columns = [
|
})
|
||||||
{
|
.catch(error => {
|
||||||
title: 'Group Name',
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
dataIndex: 'name',
|
// todo display a popop with error
|
||||||
width: 100,
|
message.error('You are not logged in');
|
||||||
},
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
{
|
} else {
|
||||||
title: 'Owner',
|
notification.error({
|
||||||
dataIndex: 'owner',
|
message: 'There was a problem',
|
||||||
key: 'owner',
|
duration: 0,
|
||||||
// render: enrolmentInfo => enrolmentInfo.owner
|
description: 'Error occurred while trying to load device groups.',
|
||||||
// todo add filtering options
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Description',
|
|
||||||
dataIndex: 'description',
|
|
||||||
key: 'description',
|
|
||||||
// render: enrolmentInfo => enrolmentInfo.ownership
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Action',
|
|
||||||
dataIndex: 'id',
|
|
||||||
key: 'action',
|
|
||||||
render: (id, row) => (
|
|
||||||
<span>
|
|
||||||
<GroupActions data={row} fetchGroups={this.fetchGroups}/>
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
rowSelection = {
|
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
|
||||||
this.setState({
|
|
||||||
selectedRows: selectedRows
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
this.setState({ loading: false });
|
||||||
this.fetchGroups();
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
//fetch data from api
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
fetchGroups = (params = {}, filters = {}) => {
|
const pager = { ...this.state.pagination };
|
||||||
const config = this.props.context;
|
pager.current = pagination.current;
|
||||||
this.setState({loading: true});
|
this.setState({
|
||||||
|
pagination: pager,
|
||||||
|
});
|
||||||
|
this.fetchGroups({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// get current page
|
render() {
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
const { data, pagination, loading } = this.state;
|
||||||
|
|
||||||
const extraParams = {
|
return (
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
<div>
|
||||||
limit: 10,
|
<div style={{ background: '#f0f2f5' }}>
|
||||||
...filters
|
<AddGroup
|
||||||
};
|
fetchGroups={this.fetchGroups}
|
||||||
|
style={{ marginBottom: '10px' }}
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
/>
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
</div>
|
||||||
|
<div style={{ textAlign: 'right' }}>
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
<Filter fields={searchFields} callback={this.fetchGroups} />
|
||||||
config.serverConfig.invoker.deviceMgt +
|
</div>
|
||||||
"/admin/groups?" + encodedExtraParams;
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
|
<Table
|
||||||
//send request to the invokerss
|
columns={this.columns}
|
||||||
axios.get(apiUrl).then(res => {
|
rowKey={record => record.id}
|
||||||
if (res.status === 200) {
|
dataSource={data.deviceGroups}
|
||||||
const pagination = {...this.state.pagination};
|
pagination={{
|
||||||
this.setState({
|
...pagination,
|
||||||
loading: false,
|
size: 'small',
|
||||||
data: res.data.data,
|
total: data.count,
|
||||||
pagination,
|
pageSize: 10,
|
||||||
});
|
showTotal: (total, range) =>
|
||||||
}
|
`showing ${range[0]}-${range[1]} of ${total} groups`,
|
||||||
|
}}
|
||||||
}).catch((error) => {
|
loading={loading}
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
onChange={this.handleTableChange}
|
||||||
//todo display a popop with error
|
rowSelection={this.rowSelection}
|
||||||
message.error('You are not logged in');
|
/>
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
</div>
|
||||||
} else {
|
</div>
|
||||||
notification["error"]({
|
);
|
||||||
message: "There was a problem",
|
}
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load device groups.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = {...this.state.pagination};
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetchGroups({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div style={{background: '#f0f2f5'}}>
|
|
||||||
<AddGroup fetchGroups={this.fetchGroups} style={{marginBottom:"10px"}}/>
|
|
||||||
</div>
|
|
||||||
<div style={{textAlign: 'right'}}>
|
|
||||||
<Filter fields={searchFields} callback={this.fetchGroups}/>
|
|
||||||
</div>
|
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
|
||||||
<Table
|
|
||||||
columns={this.columns}
|
|
||||||
rowKey={record => (record.id)}
|
|
||||||
dataSource={data.deviceGroups}
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: "small",
|
|
||||||
total: data.count,
|
|
||||||
pageSize: 10,
|
|
||||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={this.rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(GroupsTable);
|
export default withConfigContext(GroupsTable);
|
||||||
|
|||||||
@ -1,104 +1,86 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Button, Form, Row, Col, Card, Steps, Input, message, Modal, notification, Typography} from "antd";
|
import { Button, Form, Row, Col, Card, Steps } from 'antd';
|
||||||
import axios from "axios";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import SelectPlatform from './SelectPlatform';
|
||||||
import DeviceType from "../Devices/DeviceType";
|
import ConfigureProfile from './ConfigureProfile';
|
||||||
import SelectPlatform from "./SelectPlatform";
|
const { Step } = Steps;
|
||||||
import ConfigureProfile from "./ConfigureProfile";
|
|
||||||
const {Step} = Steps;
|
|
||||||
|
|
||||||
class AddPolicy extends React.Component {
|
class AddPolicy extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
constructor(props) {
|
super(props);
|
||||||
super(props);
|
this.config = this.props.context;
|
||||||
this.config = this.props.context;
|
this.state = {
|
||||||
this.state = {
|
isAddDeviceModalVisible: false,
|
||||||
isAddDeviceModalVisible: false,
|
current: 0,
|
||||||
current : 0,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
onClickType = () =>{
|
onClickType = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
current: 1,
|
current: 1,
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
next() {
|
next() {
|
||||||
const current = this.state.current + 1;
|
const current = this.state.current + 1;
|
||||||
this.setState({ current });
|
this.setState({ current });
|
||||||
}
|
}
|
||||||
|
|
||||||
prev() {
|
|
||||||
const current = this.state.current - 1;
|
|
||||||
this.setState({ current });
|
|
||||||
}
|
|
||||||
|
|
||||||
openAddDeviceModal = () =>{
|
|
||||||
this.setState({
|
|
||||||
isAddDeviceModalVisible : true,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {loading, current, isError, supportedOsVersions, errorText, forbiddenErrors} = this.state;
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col span={20} offset={2}>
|
|
||||||
<Steps style={{minHeight: 32}} current={current}>
|
|
||||||
<Step key="Platform" title="Select a Platform"/>
|
|
||||||
<Step key="ProfileConfigure" title="Configure profile"/>
|
|
||||||
<Step key="PolicyType" title="Select policy type"/>
|
|
||||||
<Step key="AssignGroups" title="Assign to groups"/>
|
|
||||||
<Step key="Publish" title="Publish to devices"/>
|
|
||||||
<Step key="Result" title="Result"/>
|
|
||||||
</Steps>
|
|
||||||
</Col>
|
|
||||||
<Col span={16} offset={4}>
|
|
||||||
<Card style={{marginTop: 24}}>
|
|
||||||
<div style={{display: (current === 0 ? 'unset' : 'none')}}>
|
|
||||||
<SelectPlatform onClickType={this.onClickType}/>
|
|
||||||
</div>
|
|
||||||
<div style={{display: (current === 1 ? 'unset' : 'none')}}>
|
|
||||||
<ConfigureProfile/>
|
|
||||||
</div>
|
|
||||||
<div style={{display: (current === 2 ? 'unset' : 'none')}}>
|
|
||||||
</div>
|
|
||||||
<div style={{display: (current === 3 ? 'unset' : 'none')}}>
|
|
||||||
</div>
|
|
||||||
<div style={{display: (current === 4 ? 'unset' : 'none')}}>
|
|
||||||
</div>
|
|
||||||
<div style={{display: (current === 5 ? 'unset' : 'none')}}>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
<Col span={16} offset={4}>
|
|
||||||
<div style={{marginTop: 24}}>
|
|
||||||
{current > 0 && (
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={() => this.prev()}>
|
|
||||||
Previous
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{current < 5 && current > 0 && (
|
|
||||||
<Button type="primary" onClick={() => this.next()}>
|
|
||||||
Next
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{current === 5 && (
|
|
||||||
<Button type="primary">
|
|
||||||
Done
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
|
prev() {
|
||||||
|
const current = this.state.current - 1;
|
||||||
|
this.setState({ current });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { current } = this.state;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Row>
|
||||||
|
<Col span={20} offset={2}>
|
||||||
|
<Steps style={{ minHeight: 32 }} current={current}>
|
||||||
|
<Step key="Platform" title="Select a Platform" />
|
||||||
|
<Step key="ProfileConfigure" title="Configure profile" />
|
||||||
|
<Step key="PolicyType" title="Select policy type" />
|
||||||
|
<Step key="AssignGroups" title="Assign to groups" />
|
||||||
|
<Step key="Publish" title="Publish to devices" />
|
||||||
|
<Step key="Result" title="Result" />
|
||||||
|
</Steps>
|
||||||
|
</Col>
|
||||||
|
<Col span={16} offset={4}>
|
||||||
|
<Card style={{ marginTop: 24 }}>
|
||||||
|
<div style={{ display: current === 0 ? 'unset' : 'none' }}>
|
||||||
|
<SelectPlatform onClickType={this.onClickType} />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: current === 1 ? 'unset' : 'none' }}>
|
||||||
|
<ConfigureProfile />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: current === 2 ? 'unset' : 'none' }}></div>
|
||||||
|
<div style={{ display: current === 3 ? 'unset' : 'none' }}></div>
|
||||||
|
<div style={{ display: current === 4 ? 'unset' : 'none' }}></div>
|
||||||
|
<div style={{ display: current === 5 ? 'unset' : 'none' }}></div>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span={16} offset={4}>
|
||||||
|
<div style={{ marginTop: 24 }}>
|
||||||
|
{current > 0 && (
|
||||||
|
<Button style={{ marginRight: 8 }} onClick={() => this.prev()}>
|
||||||
|
Previous
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{current < 5 && current > 0 && (
|
||||||
|
<Button type="primary" onClick={() => this.next()}>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{current === 5 && <Button type="primary">Done</Button>}
|
||||||
</div>
|
</div>
|
||||||
);
|
</Col>
|
||||||
}
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create({name: 'add-policy'})(AddPolicy));
|
export default withConfigContext(
|
||||||
|
Form.create({ name: 'add-policy' })(AddPolicy),
|
||||||
|
);
|
||||||
|
|||||||
@ -1,268 +1,270 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Tabs, Row, Col, Switch, Menu,Input, Typography, Form, Checkbox, Select,
|
import {
|
||||||
Tooltip, Icon, Collapse, Alert, Upload, Button,Radio} from "antd";
|
Tabs,
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
Row,
|
||||||
import "../../pages/Dashboard/Policies/policies.css";
|
Col,
|
||||||
import jsonResponse from "./configuration";
|
Switch,
|
||||||
const { Title, Text, Paragraph } = Typography;
|
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 { TabPane } = Tabs;
|
||||||
const {Option} = Select;
|
const { Option } = Select;
|
||||||
const {Panel} = Collapse;
|
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
const policyConfigurationsList = jsonResponse.PolicyConfigurations;
|
const policyConfigurationsList = jsonResponse.PolicyConfigurations;
|
||||||
|
|
||||||
class ConfigureProfile extends React.Component {
|
class ConfigureProfile extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.config = this.props.context;
|
this.config = this.props.context;
|
||||||
this.policies = policyConfigurationsList.androidPolicy.Policy;
|
this.policies = policyConfigurationsList.androidPolicy.Policy;
|
||||||
this.state = {
|
this.state = {
|
||||||
isDisplayMain: "none",
|
isDisplayMain: 'none',
|
||||||
activeKeys: []
|
activeKeys: [],
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {}
|
||||||
|
|
||||||
|
onChange = e => {
|
||||||
|
console.log(`checked = ${e.target.id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
onChecked = (e, i) => {
|
||||||
|
if (e) {
|
||||||
|
this.setState({
|
||||||
|
isDisplayMain: 'block',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
isDisplayMain: 'none',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onChange = (e) =>{
|
onClickSwitch = e => {};
|
||||||
console.log(`checked = ${e.target.id}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
onChecked = (e,i) =>{
|
getPanelItems = panel => {
|
||||||
if(e){
|
const { getFieldDecorator } = this.props.form;
|
||||||
this.setState({
|
return panel.map((item, k) => {
|
||||||
isDisplayMain: "block",
|
switch (item._type) {
|
||||||
});
|
case 'select':
|
||||||
}else{
|
return (
|
||||||
this.setState({
|
<Form.Item
|
||||||
isDisplayMain: "none",
|
key={k}
|
||||||
});
|
label={
|
||||||
|
<span>
|
||||||
|
{item.Label}
|
||||||
|
<Tooltip title={item.tooltip} placement="right">
|
||||||
|
<Icon type="question-circle-o" />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
style={{ display: 'block' }}
|
||||||
|
>
|
||||||
|
{getFieldDecorator(`${item._id}`, {
|
||||||
|
initialValue: `${item.Optional.Option[0]}`,
|
||||||
|
})(
|
||||||
|
<Select>
|
||||||
|
{item.Optional.Option.map(option => {
|
||||||
|
return <Option key={option}>{option}</Option>;
|
||||||
|
})}
|
||||||
|
</Select>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
case 'input':
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
key={k}
|
||||||
|
label={
|
||||||
|
<span>
|
||||||
|
{item.Label}
|
||||||
|
<Tooltip title={item.tooltip} placement="right">
|
||||||
|
<Icon type="question-circle-o" />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
style={{ display: 'block' }}
|
||||||
|
>
|
||||||
|
{getFieldDecorator(`${item._id}`, {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
pattern: new RegExp(`${item.Optional.rules.regex}`),
|
||||||
|
message: `${item.Optional.rules.validationMsg}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})(<Input placeholder={item.Optional.Placeholder} />)}
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
case 'checkbox':
|
||||||
|
return (
|
||||||
|
<Form.Item key={k}>
|
||||||
|
{getFieldDecorator(`${item._id}`, {
|
||||||
|
valuePropName: 'checked',
|
||||||
|
initialValue: `${item.Optional.checked}`,
|
||||||
|
})(
|
||||||
|
<Checkbox
|
||||||
|
// checked={item.Optional.checked}
|
||||||
|
onChange={this.onChange}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{item.Label}
|
||||||
|
<Tooltip title={item.tooltip} placement="right">
|
||||||
|
<Icon type="question-circle-o" />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
</Checkbox>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
case 'textArea':
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
key={k}
|
||||||
|
label={
|
||||||
|
<span>
|
||||||
|
{item.Label}
|
||||||
|
<Tooltip title={item.tooltip} placement="right">
|
||||||
|
<Icon type="question-circle-o" />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
style={{ display: 'block' }}
|
||||||
|
>
|
||||||
|
{getFieldDecorator(`${item._id}`, {})(
|
||||||
|
<TextArea
|
||||||
|
placeholder={item.Optional.Placeholder}
|
||||||
|
rows={item.Optional.Row}
|
||||||
|
/>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
case 'radioGroup':
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
key={k}
|
||||||
|
label={
|
||||||
|
<span>
|
||||||
|
{item.Label}
|
||||||
|
<Tooltip title={item.tooltip} placement="right">
|
||||||
|
<Icon type="question-circle-o" />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
style={{ display: 'block' }}
|
||||||
|
>
|
||||||
|
{getFieldDecorator(`${item._id}`, {})(
|
||||||
|
<Radio.Group>
|
||||||
|
{item.Optional.Radio.map(option => {
|
||||||
|
return (
|
||||||
|
<Radio key={option} value={option}>
|
||||||
|
{option}
|
||||||
|
</Radio>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Radio.Group>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
case 'title':
|
||||||
|
return (
|
||||||
|
<Title key={k} level={4}>
|
||||||
|
{item.Label}{' '}
|
||||||
|
</Title>
|
||||||
|
);
|
||||||
|
case 'paragraph':
|
||||||
|
return (
|
||||||
|
<Paragraph key={k} style={{ marginTop: 20 }}>
|
||||||
|
{item.Label}{' '}
|
||||||
|
</Paragraph>
|
||||||
|
);
|
||||||
|
case 'alert':
|
||||||
|
return (
|
||||||
|
<Alert key={k} description={item.Label} type="warning" showIcon />
|
||||||
|
);
|
||||||
|
case 'upload':
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
key={k}
|
||||||
|
label={
|
||||||
|
<span>
|
||||||
|
{item.Label}
|
||||||
|
<Tooltip title={item.tooltip} placement="right">
|
||||||
|
<Icon type="question-circle-o" />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{getFieldDecorator('upload', {})(
|
||||||
|
<Upload>
|
||||||
|
<Button>
|
||||||
|
<Icon type="upload" /> Click to upload
|
||||||
|
</Button>
|
||||||
|
</Upload>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
render() {
|
||||||
|
return (
|
||||||
};
|
<div>
|
||||||
|
<Tabs tabPosition={'left'} size={'large'}>
|
||||||
onClickSwitch = (e) =>{
|
{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) => {
|
||||||
getPanelItems = (panel)=>{
|
return (
|
||||||
const { getFieldDecorator } = this.props.form;
|
<div key={j}>
|
||||||
return (
|
<div>
|
||||||
panel.map((item,k)=>{
|
<Row>
|
||||||
switch(item._type){
|
<Col offset={0} span={14}>
|
||||||
case "select":
|
<Title level={4}>{panel.title} </Title>
|
||||||
return(
|
</Col>
|
||||||
<Form.Item key={k}
|
<Col offset={8} span={1}>
|
||||||
label={
|
<Switch
|
||||||
<span>
|
checkedChildren="ON"
|
||||||
{item.Label}
|
unCheckedChildren="OFF"
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
id={i}
|
||||||
<Icon type="question-circle-o" />
|
onClick={this.onClickSwitch}
|
||||||
</Tooltip>
|
onChange={this.onChecked}
|
||||||
</span>
|
|
||||||
}
|
|
||||||
style={{display: "block"}}>
|
|
||||||
{getFieldDecorator(`${item._id}`, {
|
|
||||||
initialValue: `${item.Optional.Option[0]}`
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
{item.Optional.Option.map((option)=>{
|
|
||||||
return(
|
|
||||||
<Option key={option}>{option}</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case "input":
|
|
||||||
return(
|
|
||||||
<Form.Item key={k}
|
|
||||||
label={
|
|
||||||
<span>
|
|
||||||
{item.Label}
|
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
style={{display: "block"}}>
|
|
||||||
{getFieldDecorator(`${item._id}`, {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
pattern: new RegExp(`${item.Optional.rules.regex}`),
|
|
||||||
message: `${item.Optional.rules.validationMsg}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(
|
|
||||||
<Input placeholder={item.Optional.Placeholder}/>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case "checkbox":
|
|
||||||
return(
|
|
||||||
<Form.Item key={k}>
|
|
||||||
{getFieldDecorator(`${item._id}`, {
|
|
||||||
valuePropName: 'checked',
|
|
||||||
initialValue: `${item.Optional.checked}`,
|
|
||||||
})(
|
|
||||||
<Checkbox
|
|
||||||
// checked={item.Optional.checked}
|
|
||||||
onChange={this.onChange}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
{item.Label}
|
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
</Checkbox>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case "textArea":
|
|
||||||
return(
|
|
||||||
<Form.Item key={k}
|
|
||||||
label={
|
|
||||||
<span>
|
|
||||||
{item.Label}
|
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
style={{display: "block"}}>
|
|
||||||
{getFieldDecorator(`${item._id}`, {
|
|
||||||
|
|
||||||
})(
|
|
||||||
<TextArea placeholder={item.Optional.Placeholder}
|
|
||||||
rows={item.Optional.Row} />
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case "radioGroup":
|
|
||||||
return(
|
|
||||||
<Form.Item key={k}
|
|
||||||
label={
|
|
||||||
<span>
|
|
||||||
{item.Label}
|
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
style={{display: "block"}}>
|
|
||||||
{getFieldDecorator(`${item._id}`, {
|
|
||||||
})(
|
|
||||||
<Radio.Group>
|
|
||||||
{item.Optional.Radio.map((option)=>{
|
|
||||||
return(
|
|
||||||
<Radio value={option}>{option}</Radio>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Radio.Group>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case "title":
|
|
||||||
return(
|
|
||||||
<Title key={k} level={4}>{item.Label} </Title>
|
|
||||||
);
|
|
||||||
case "paragraph":
|
|
||||||
return(
|
|
||||||
<Paragraph key={k} style={{marginTop:20}}>{item.Label} </Paragraph>
|
|
||||||
);
|
|
||||||
case "alert":
|
|
||||||
return(
|
|
||||||
<Alert
|
|
||||||
key={k}
|
|
||||||
description={item.Label}
|
|
||||||
type="warning"
|
|
||||||
showIcon
|
|
||||||
/>
|
/>
|
||||||
);
|
</Col>
|
||||||
case "upload":
|
</Row>
|
||||||
return(
|
<Row>{panel.description}</Row>
|
||||||
<Form.Item key={k}
|
</div>
|
||||||
label={
|
<div style={{ display: `${this.state.isDisplayMain}` }}>
|
||||||
<span>
|
<Form>{this.getPanelItems(panel.PanelItem)}</Form>
|
||||||
{item.Label}
|
</div>
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
</div>
|
||||||
<Icon type="question-circle-o" />
|
);
|
||||||
</Tooltip>
|
})}
|
||||||
</span>
|
</TabPane>
|
||||||
}
|
);
|
||||||
>
|
})}
|
||||||
{getFieldDecorator('upload', {
|
</Tabs>
|
||||||
|
</div>
|
||||||
})(
|
);
|
||||||
|
}
|
||||||
<Upload>
|
|
||||||
<Button>
|
|
||||||
<Icon type="upload" /> Click to upload
|
|
||||||
</Button>
|
|
||||||
</Upload>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Tabs tabPosition={"left"} size={"large"}>
|
|
||||||
{ this.policies.map((element, i) =>{
|
|
||||||
return(
|
|
||||||
|
|
||||||
<TabPane tab={element.Name} key={i} >
|
|
||||||
{/*<div style={{ height: 800, overflowY: "scroll"}}>*/}
|
|
||||||
{ Object.values(element.Panel).map((panel, j)=>{
|
|
||||||
return(
|
|
||||||
<div key={j} >
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col offset={0} span={14}>
|
|
||||||
<Title level={4}>{panel.title} </Title>
|
|
||||||
</Col>
|
|
||||||
<Col offset={8} span={1}>
|
|
||||||
<Switch
|
|
||||||
checkedChildren="ON"
|
|
||||||
unCheckedChildren="OFF"
|
|
||||||
id={i}
|
|
||||||
onClick={this.onClickSwitch}
|
|
||||||
onChange={this.onChecked}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>{panel.description}</Row>
|
|
||||||
</div>
|
|
||||||
<div style={{display: `${this.state.isDisplayMain}`}}>
|
|
||||||
<Form >
|
|
||||||
{this.getPanelItems(panel.PanelItem)}
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</TabPane>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(ConfigureProfile));
|
export default withConfigContext(Form.create()(ConfigureProfile));
|
||||||
|
|||||||
@ -16,165 +16,162 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {message, notification, Table, Typography} from "antd";
|
import { message, notification, Table } from 'antd';
|
||||||
import TimeAgo from 'javascript-time-ago'
|
import TimeAgo from 'javascript-time-ago';
|
||||||
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
let apiUrl;
|
let apiUrl;
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: 'Policy Name',
|
title: 'Policy Name',
|
||||||
dataIndex: 'policyName',
|
dataIndex: 'policyName',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Description',
|
title: 'Description',
|
||||||
dataIndex: 'description',
|
dataIndex: 'description',
|
||||||
key: 'description',
|
key: 'description',
|
||||||
// render: enrolmentInfo => enrolmentInfo.owner
|
// render: enrolmentInfo => enrolmentInfo.owner
|
||||||
// todo add filtering options
|
// todo add filtering options
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Compilance',
|
title: 'Compilance',
|
||||||
dataIndex: 'compliance',
|
dataIndex: 'compliance',
|
||||||
key: 'compliance',
|
key: 'compliance',
|
||||||
// render: enrolmentInfo => enrolmentInfo.ownership
|
// render: enrolmentInfo => enrolmentInfo.ownership
|
||||||
// todo add filtering options
|
// todo add filtering options
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Policy Type',
|
title: 'Policy Type',
|
||||||
dataIndex: 'policyType',
|
dataIndex: 'policyType',
|
||||||
key: 'policyType',
|
key: 'policyType',
|
||||||
// render: enrolmentInfo => enrolmentInfo.ownership
|
// render: enrolmentInfo => enrolmentInfo.ownership
|
||||||
// todo add filtering options
|
// todo add filtering options
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const getTimeAgo = (time) => {
|
|
||||||
const timeAgo = new TimeAgo('en-US');
|
|
||||||
return timeAgo.format(time);
|
|
||||||
};
|
|
||||||
|
|
||||||
class PoliciesTable extends React.Component {
|
class PoliciesTable extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
TimeAgo.addLocale(en);
|
||||||
TimeAgo.addLocale(en);
|
this.state = {
|
||||||
this.state = {
|
data: [],
|
||||||
data: [],
|
pagination: {},
|
||||||
pagination: {},
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rowSelection = {
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
this.setState({
|
||||||
|
selectedRows: selectedRows,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchGroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetchGroups = (params = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
// get current page
|
||||||
|
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (currentPage - 1), // calculate the offset
|
||||||
|
limit: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
const encodedExtraParams = Object.keys(extraParams)
|
||||||
|
.map(key => key + '=' + extraParams[key])
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/policies?' +
|
||||||
|
encodedExtraParams;
|
||||||
|
|
||||||
|
// send request to the invokerss
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: []
|
data: res.data.data.policies,
|
||||||
};
|
pagination,
|
||||||
}
|
});
|
||||||
|
}
|
||||||
rowSelection = {
|
})
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
.catch(error => {
|
||||||
this.setState({
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
selectedRows: selectedRows
|
// todo display a popop with error
|
||||||
})
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load policies.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
this.setState({ loading: false });
|
||||||
this.fetchGroups();
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
//fetch data from api
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
fetchGroups = (params = {}) => {
|
const pager = { ...this.state.pagination };
|
||||||
const config = this.props.context;
|
pager.current = pagination.current;
|
||||||
this.setState({loading: true});
|
this.setState({
|
||||||
|
pagination: pager,
|
||||||
|
});
|
||||||
|
this.fetch({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// get current page
|
render() {
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
const { data, pagination, loading } = this.state;
|
||||||
|
return (
|
||||||
const extraParams = {
|
<div>
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
<Table
|
||||||
limit: 10,
|
columns={columns}
|
||||||
};
|
rowKey={record => record.id}
|
||||||
|
dataSource={data}
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
pagination={{
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
...pagination,
|
||||||
|
size: 'small',
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
// position: "top",
|
||||||
config.serverConfig.invoker.deviceMgt +
|
showTotal: (total, range) =>
|
||||||
"/policies?" + encodedExtraParams;
|
`showing ${range[0]}-${range[1]} of ${total} groups`,
|
||||||
|
// showQuickJumper: true
|
||||||
//send request to the invokerss
|
}}
|
||||||
axios.get(apiUrl).then(res => {
|
loading={loading}
|
||||||
if (res.status === 200) {
|
onChange={this.handleTableChange}
|
||||||
const pagination = {...this.state.pagination};
|
rowSelection={this.rowSelection}
|
||||||
this.setState({
|
/>
|
||||||
loading: false,
|
</div>
|
||||||
data: res.data.data.policies,
|
);
|
||||||
pagination,
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load policies.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = {...this.state.pagination};
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetch({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
rowKey={record => (record.id)}
|
|
||||||
dataSource={data}
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: "small",
|
|
||||||
// position: "top",
|
|
||||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
|
|
||||||
// showQuickJumper: true
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={this.rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(PoliciesTable);
|
export default withConfigContext(PoliciesTable);
|
||||||
|
|||||||
@ -16,133 +16,126 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {Card, Col, Icon, message, notification, Row, Typography} from "antd";
|
import { Card, Col, Icon, message, notification, Row } from 'antd';
|
||||||
import TimeAgo from 'javascript-time-ago'
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
let apiUrl;
|
let apiUrl;
|
||||||
|
|
||||||
class SelectPlatform extends React.Component {
|
class SelectPlatform extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
TimeAgo.addLocale(en);
|
||||||
TimeAgo.addLocale(en);
|
this.state = {
|
||||||
this.state = {
|
data: [],
|
||||||
data: [],
|
pagination: {},
|
||||||
pagination: {},
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickCard = data => {
|
||||||
|
console.log(data);
|
||||||
|
this.props.onClickType();
|
||||||
|
};
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetchUsers = (params = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/device-types';
|
||||||
|
|
||||||
|
// send request to the invokerss
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: []
|
data: JSON.parse(res.data.data),
|
||||||
};
|
pagination,
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load device types.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
this.setState({ loading: false });
|
||||||
this.fetchUsers();
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
onClickCard = (data) =>{
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
console.log(data);
|
const pager = { ...this.state.pagination };
|
||||||
this.props.onClickType();
|
pager.current = pagination.current;
|
||||||
};
|
this.setState({
|
||||||
|
pagination: pager,
|
||||||
|
});
|
||||||
|
this.fetch({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
//fetch data from api
|
render() {
|
||||||
fetchUsers = (params = {}) => {
|
const { data } = this.state;
|
||||||
const config = this.props.context;
|
const { Meta } = Card;
|
||||||
this.setState({loading: true});
|
const itemCard = data.map(data => (
|
||||||
|
<Col span={5} key={data.id}>
|
||||||
// get current page
|
<Card
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
size="default"
|
||||||
|
style={{ width: 150 }}
|
||||||
const extraParams = {
|
bordered={true}
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
onClick={this.onClickCard}
|
||||||
limit: 10,
|
cover={
|
||||||
};
|
<Icon
|
||||||
|
type="android"
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
key="device-types"
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
style={{
|
||||||
|
color: '#ffffff',
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
backgroundColor: '#4b92db',
|
||||||
config.serverConfig.invoker.deviceMgt +
|
fontSize: '100px',
|
||||||
"/device-types";
|
padding: '20px',
|
||||||
|
}}
|
||||||
//send request to the invokerss
|
/>
|
||||||
axios.get(apiUrl).then(res => {
|
}
|
||||||
if (res.status === 200) {
|
>
|
||||||
const pagination = {...this.state.pagination};
|
<Meta title={data.name} />
|
||||||
this.setState({
|
</Card>
|
||||||
loading: false,
|
</Col>
|
||||||
data: JSON.parse(res.data.data),
|
));
|
||||||
pagination,
|
return (
|
||||||
});
|
<div>
|
||||||
}
|
<Row gutter={16}>{itemCard}</Row>
|
||||||
|
</div>
|
||||||
}).catch((error) => {
|
);
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
}
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load device types.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = {...this.state.pagination};
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetch({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
|
||||||
const { Meta } = Card;
|
|
||||||
const itemCard = data.map((data) =>
|
|
||||||
<Col span={5} key={data.id}>
|
|
||||||
<Card
|
|
||||||
size="default"
|
|
||||||
style={{ width: 150 }}
|
|
||||||
bordered={true}
|
|
||||||
onClick={this.onClickCard}
|
|
||||||
cover={<Icon type="android" key="device-types" style={{color:'#ffffff',
|
|
||||||
backgroundColor:'#4b92db', fontSize: '100px', padding:'20px'}}/>}
|
|
||||||
>
|
|
||||||
<Meta
|
|
||||||
title={data.name}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row gutter={16}>
|
|
||||||
{itemCard}
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(SelectPlatform);
|
export default withConfigContext(SelectPlatform);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -16,50 +16,47 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import { DatePicker } from 'antd';
|
import { DatePicker } from 'antd';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
class DateRangePicker extends React.Component {
|
class DateRangePicker extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props){
|
// Send updated date range to Reports.js when duration change
|
||||||
super(props);
|
onChange = (dates, dateStrings) => {
|
||||||
}
|
this.props.updateDurationValue(dateStrings[0], dateStrings[1]);
|
||||||
|
};
|
||||||
|
|
||||||
//Send updated date range to Reports.js when duration change
|
render() {
|
||||||
onChange = (dates, dateStrings) => {
|
const { RangePicker } = DatePicker;
|
||||||
this.props.updateDurationValue(dateStrings[0],dateStrings[1]);
|
return (
|
||||||
}
|
<RangePicker
|
||||||
|
ranges={{
|
||||||
render(){
|
Today: [moment(), moment()],
|
||||||
const { RangePicker } = DatePicker;
|
Yesterday: [
|
||||||
return(
|
moment().subtract(1, 'days'),
|
||||||
<RangePicker
|
moment().subtract(1, 'days'),
|
||||||
ranges={{
|
],
|
||||||
'Today': [
|
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
|
||||||
moment(),
|
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
|
||||||
moment()],
|
'This Month': [moment().startOf('month'), moment().endOf('month')],
|
||||||
'Yesterday': [
|
'Last Month': [
|
||||||
moment().subtract(1, 'days'),
|
moment()
|
||||||
moment().subtract(1, 'days')],
|
.subtract(1, 'month')
|
||||||
'Last 7 Days': [
|
.startOf('month'),
|
||||||
moment().subtract(6, 'days'),
|
moment()
|
||||||
moment()],
|
.subtract(1, 'month')
|
||||||
'Last 30 Days': [
|
.endOf('month'),
|
||||||
moment().subtract(29, 'days'),
|
],
|
||||||
moment()],
|
}}
|
||||||
'This Month': [
|
format="YYYY-MM-DD"
|
||||||
moment().startOf('month'),
|
onChange={this.onChange}
|
||||||
moment().endOf('month')],
|
/>
|
||||||
'Last Month': [
|
);
|
||||||
moment().subtract(1, 'month').startOf('month'),
|
}
|
||||||
moment().subtract(1, 'month').endOf('month')]
|
|
||||||
}}
|
|
||||||
format="YYYY-MM-DD"
|
|
||||||
onChange={this.onChange}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DateRangePicker;
|
export default DateRangePicker;
|
||||||
|
|||||||
@ -16,52 +16,53 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import { Select } from 'antd';
|
import { Select } from 'antd';
|
||||||
|
|
||||||
class Filter extends React.Component {
|
class Filter extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
selectedItem: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props){
|
// Send updated filter value to Reports.js
|
||||||
super(props);
|
onChange = value => {
|
||||||
const { Option } = Select;
|
this.setState({ selectedItem: value }, () => {
|
||||||
this.state = {
|
if (this.props.dropDownName == 'Device Status') {
|
||||||
selectedItem:null
|
this.props.updateFiltersValue(this.state.selectedItem, 'Device Status');
|
||||||
|
} else {
|
||||||
|
this.props.updateFiltersValue(
|
||||||
|
this.state.selectedItem,
|
||||||
|
'Device Ownership',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// Dynamically generate dropdown items from dropDownItems array
|
||||||
|
let item = this.props.dropDownItems.map(data => (
|
||||||
|
<Select.Option value={data} key={data}>
|
||||||
|
{data}
|
||||||
|
</Select.Option>
|
||||||
|
));
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
showSearch
|
||||||
|
style={{ width: 200 }}
|
||||||
|
placeholder={this.props.dropDownName}
|
||||||
|
optionFilterProp="children"
|
||||||
|
onChange={this.onChange}
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
}
|
}
|
||||||
}
|
>
|
||||||
|
{item}
|
||||||
//Send updated filter value to Reports.js
|
</Select>
|
||||||
onChange = value => {
|
);
|
||||||
this.setState({selectedItem:value},() => {
|
}
|
||||||
if(this.props.dropDownName=="Device Status"){
|
|
||||||
this.props.updateFiltersValue(this.state.selectedItem,"Device Status");
|
|
||||||
}else{
|
|
||||||
this.props.updateFiltersValue(this.state.selectedItem, "Device Ownership");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render(){
|
|
||||||
//Dynamically generate dropdown items from dropDownItems array
|
|
||||||
let item = this.props.dropDownItems.map((data) =>
|
|
||||||
<Select.Option
|
|
||||||
value={data}
|
|
||||||
key={data}>
|
|
||||||
{data}
|
|
||||||
</Select.Option>);
|
|
||||||
return(
|
|
||||||
<Select
|
|
||||||
showSearch
|
|
||||||
style={{ width: 200 }}
|
|
||||||
placeholder={this.props.dropDownName}
|
|
||||||
optionFilterProp="children"
|
|
||||||
onChange={this.onChange}
|
|
||||||
filterOption={(input, option) =>
|
|
||||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
||||||
}>
|
|
||||||
{item}
|
|
||||||
</Select>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Filter;
|
export default Filter;
|
||||||
|
|||||||
@ -16,110 +16,112 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Breadcrumb, Icon, Select, Button, Card } from 'antd';
|
||||||
PageHeader,
|
|
||||||
Typography,
|
|
||||||
Breadcrumb,
|
|
||||||
Icon,
|
|
||||||
Tag,
|
|
||||||
Radio, Select, Button, Card,
|
|
||||||
Row, Col, message, notification
|
|
||||||
} from "antd";
|
|
||||||
|
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from 'react-router-dom';
|
||||||
import PoliciesTable from "../../../components/Policies/PoliciesTable";
|
import ReportDeviceTable from '../../../components/Devices/ReportDevicesTable';
|
||||||
import DevicesTable from "../../../components/Devices/DevicesTable";
|
import PieChart from '../../../components/Reports/Widgets/PieChart';
|
||||||
import DateRangePicker from "../../../components/Reports/DateRangePicker";
|
import { withConfigContext } from '../../../context/ConfigContext';
|
||||||
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;
|
const { Option } = Select;
|
||||||
let config = null;
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceStatusReport extends React.Component {
|
class DeviceStatusReport extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
config = this.props.context;
|
const { reportData } = this.props.location;
|
||||||
const { reportData } = this.props.location;
|
this.state = {
|
||||||
this.state = {
|
selectedTags: ['Enrolled'],
|
||||||
selectedTags: ['Enrolled'],
|
paramsObject: {
|
||||||
paramsObject:{
|
from: reportData.duration[0],
|
||||||
from:reportData.duration[0],
|
to: reportData.duration[1],
|
||||||
to:reportData.duration[1]
|
},
|
||||||
},
|
statsObject: {},
|
||||||
statsObject:{},
|
statArray: [
|
||||||
statArray:[{item:"ACTIVE",count:0},{item:"INACTIVE",count:0},{item:"REMOVED",count:0}]
|
{ item: 'ACTIVE', count: 0 },
|
||||||
};
|
{ item: 'INACTIVE', count: 0 },
|
||||||
}
|
{ item: 'REMOVED', count: 0 },
|
||||||
|
],
|
||||||
onClickPieChart = (value) => {
|
|
||||||
console.log(value.data.point.item);
|
|
||||||
const chartValue = value.data.point.item;
|
|
||||||
let tempParamObj = this.state.paramsObject;
|
|
||||||
|
|
||||||
tempParamObj.status = chartValue;
|
|
||||||
|
|
||||||
|
|
||||||
this.setState({paramsObject:tempParamObj});
|
|
||||||
console.log(this.state.paramsObject)
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
onClickPieChart = value => {
|
||||||
const { statArray } = this.state;
|
console.log(value.data.point.item);
|
||||||
const { reportData } = this.props.location;
|
const chartValue = value.data.point.item;
|
||||||
|
let tempParamObj = this.state.paramsObject;
|
||||||
|
|
||||||
const params = {...this.state.paramsObject};
|
tempParamObj.status = chartValue;
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap" style={{marginBottom: '10px'}}>
|
|
||||||
<h3>Summary of enrollments</h3>
|
|
||||||
<div style={{marginBottom: '10px'}}>
|
|
||||||
<Select defaultValue="android" style={{ width: 120 , marginRight:10}}>
|
|
||||||
<Option value="android">Android</Option>
|
|
||||||
<Option value="ios">IOS</Option>
|
|
||||||
<Option value="windows">Windows</Option>
|
|
||||||
</Select>
|
|
||||||
<Button onClick={this.onSubmitReport} style={{marginLeft:10}} type="primary">Generate Report</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
this.setState({ paramsObject: tempParamObj });
|
||||||
<Card
|
console.log(this.state.paramsObject);
|
||||||
bordered={true}
|
};
|
||||||
hoverable={true}
|
|
||||||
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
|
|
||||||
|
|
||||||
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData}/>
|
render() {
|
||||||
</Card>
|
const { reportData } = this.props.location;
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
const params = { ...this.state.paramsObject };
|
||||||
<ReportDeviceTable paramsObject={params}/>
|
return (
|
||||||
</div>
|
<div>
|
||||||
</PageHeader>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
|
<Breadcrumb.Item>
|
||||||
</div>
|
<Link to="/entgra">
|
||||||
|
<Icon type="home" /> Home
|
||||||
|
</Link>
|
||||||
|
</Breadcrumb.Item>
|
||||||
|
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||||
|
</Breadcrumb>
|
||||||
|
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||||
|
<h3>Summary of enrollments</h3>
|
||||||
|
<div style={{ marginBottom: '10px' }}>
|
||||||
|
<Select
|
||||||
|
defaultValue="android"
|
||||||
|
style={{ width: 120, marginRight: 10 }}
|
||||||
|
>
|
||||||
|
<Option value="android">Android</Option>
|
||||||
|
<Option value="ios">IOS</Option>
|
||||||
|
<Option value="windows">Windows</Option>
|
||||||
|
</Select>
|
||||||
|
<Button
|
||||||
|
onClick={this.onSubmitReport}
|
||||||
|
style={{ marginLeft: 10 }}
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
Generate Report
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
|
||||||
|
<div>
|
||||||
|
<Card
|
||||||
|
bordered={true}
|
||||||
|
hoverable={true}
|
||||||
|
style={{
|
||||||
|
borderRadius: 5,
|
||||||
|
marginBottom: 10,
|
||||||
|
height: window.innerHeight * 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PieChart
|
||||||
|
onClickPieChart={this.onClickPieChart}
|
||||||
|
reportData={reportData}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
|
<ReportDeviceTable paramsObject={params} />
|
||||||
|
</div>
|
||||||
|
</PageHeader>
|
||||||
|
<div
|
||||||
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(DeviceStatusReport);
|
export default withConfigContext(DeviceStatusReport);
|
||||||
|
|||||||
@ -16,118 +16,88 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Breadcrumb, Icon, Card } from 'antd';
|
||||||
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 { 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 {
|
class EnrollmentTypeReport extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
config = this.props.context;
|
const { reportData } = this.props.location;
|
||||||
const { reportData } = this.props.location;
|
this.state = {
|
||||||
this.state = {
|
paramsObject: {
|
||||||
paramsObject:{
|
from: reportData.duration[0],
|
||||||
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) => {
|
console.log(reportData.duration);
|
||||||
const chartValue = value.data.point.item;
|
}
|
||||||
let tempParamObj = this.state.paramsObject;
|
|
||||||
|
|
||||||
console.log(chartValue)
|
onClickPieChart = value => {
|
||||||
|
const chartValue = value.data.point.item;
|
||||||
|
let tempParamObj = this.state.paramsObject;
|
||||||
|
|
||||||
tempParamObj.ownership = chartValue;
|
console.log(chartValue);
|
||||||
|
|
||||||
this.setState({paramsObject:tempParamObj});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
tempParamObj.ownership = chartValue;
|
||||||
const { reportData } = this.props.location;
|
|
||||||
|
|
||||||
const params = {...this.state.paramsObject};
|
this.setState({ paramsObject: tempParamObj });
|
||||||
return (
|
};
|
||||||
<div>
|
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap" style={{marginBottom: '10px'}}>
|
|
||||||
<h3>Summary of enrollments</h3>
|
|
||||||
|
|
||||||
</div>
|
render() {
|
||||||
|
const { reportData } = this.props.location;
|
||||||
|
|
||||||
<div>
|
const params = { ...this.state.paramsObject };
|
||||||
<Card
|
return (
|
||||||
bordered={true}
|
<div>
|
||||||
hoverable={true}
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
|
<Breadcrumb.Item>
|
||||||
|
<Link to="/entgra">
|
||||||
|
<Icon type="home" /> Home
|
||||||
|
</Link>
|
||||||
|
</Breadcrumb.Item>
|
||||||
|
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||||
|
</Breadcrumb>
|
||||||
|
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||||
|
<h3>Summary of enrollments</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Card
|
||||||
|
bordered={true}
|
||||||
|
hoverable={true}
|
||||||
|
style={{
|
||||||
|
borderRadius: 5,
|
||||||
|
marginBottom: 10,
|
||||||
|
height: window.innerHeight * 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PieChart
|
||||||
|
onClickPieChart={this.onClickPieChart}
|
||||||
|
reportData={reportData}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData}/>
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
|
<ReportDeviceTable paramsObject={params} />
|
||||||
</Card>
|
</div>
|
||||||
|
</PageHeader>
|
||||||
</div>
|
<div
|
||||||
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
></div>
|
||||||
<ReportDeviceTable paramsObject={params}/>
|
</div>
|
||||||
</div>
|
);
|
||||||
</PageHeader>
|
}
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(EnrollmentTypeReport);
|
export default withConfigContext(EnrollmentTypeReport);
|
||||||
|
|||||||
@ -16,157 +16,111 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Breadcrumb, Icon, Card } from 'antd';
|
||||||
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 { 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 {
|
class EnrollmentsVsUnenrollmentsReport extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
config = this.props.context;
|
const { reportData } = this.props.location;
|
||||||
const { reportData } = this.props.location;
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
paramsObject:{
|
paramsObject: {
|
||||||
from:reportData? reportData.duration[0]: "2019-01-01",
|
from: reportData ? reportData.duration[0] : '2019-01-01',
|
||||||
to:reportData? reportData.duration[1]: "2019-01-01"
|
to: reportData ? reportData.duration[1] : '2019-01-01',
|
||||||
},
|
},
|
||||||
redirect: false
|
redirect: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.redirectToHome();
|
this.redirectToHome();
|
||||||
console.log(this.state.paramsObject);
|
console.log(this.state.paramsObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectToHome = () => {
|
||||||
|
return <Redirect to="/entgra" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
onClickPieChart = value => {
|
||||||
|
const chartValue = value.data.point.item;
|
||||||
|
let tempParamObj = this.state.paramsObject;
|
||||||
|
|
||||||
|
console.log(chartValue);
|
||||||
|
|
||||||
|
if (chartValue === 'Enrollments') {
|
||||||
|
tempParamObj.status = 'ACTIVE&status=INACTIVE';
|
||||||
|
} else {
|
||||||
|
tempParamObj.status = 'REMOVED';
|
||||||
}
|
}
|
||||||
|
|
||||||
setParam = (tempParamObj, type, value) => {
|
this.setState({ paramsObject: tempParamObj });
|
||||||
if(type==="status"){
|
};
|
||||||
tempParamObj.status = value;
|
|
||||||
if(tempParamObj.status) {
|
render() {
|
||||||
delete tempParamObj.status;
|
const { reportData } = this.props.location;
|
||||||
}
|
|
||||||
} else if(type=="ownership"){
|
console.log('======');
|
||||||
tempParamObj.ownership = value;
|
console.log(reportData);
|
||||||
if(value=="ALL" && tempParamObj.ownership) {
|
console.log('======');
|
||||||
delete tempParamObj.ownership;
|
|
||||||
}
|
let reportDataClone = {
|
||||||
}
|
params: ['ACTIVE'],
|
||||||
|
duration: ['2020-01-01', '2020-01-01'],
|
||||||
};
|
};
|
||||||
|
|
||||||
redirectToHome = () => {
|
const params = { ...this.state.paramsObject };
|
||||||
return <Redirect to="/entgra" />
|
return (
|
||||||
};
|
<div>
|
||||||
|
<div>
|
||||||
|
{!reportData ? (
|
||||||
|
<Redirect to="/entgra/reports" />
|
||||||
|
) : (
|
||||||
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
|
<Breadcrumb.Item>
|
||||||
|
<Link to="/entgra">
|
||||||
|
<Icon type="home" /> Home
|
||||||
|
</Link>
|
||||||
|
</Breadcrumb.Item>
|
||||||
|
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||||
|
</Breadcrumb>
|
||||||
|
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||||
|
<h3>Summary of enrollments</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
setRedirect = (reportData) => {
|
<div>
|
||||||
if(!reportData){
|
<Card
|
||||||
this.setState({
|
bordered={true}
|
||||||
redirect: true
|
hoverable={true}
|
||||||
})
|
style={{
|
||||||
}
|
borderRadius: 5,
|
||||||
};
|
marginBottom: 10,
|
||||||
|
height: window.innerHeight * 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PieChart
|
||||||
|
onClickPieChart={this.onClickPieChart}
|
||||||
|
reportData={reportData ? reportData : reportDataClone}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
renderRedirect = () => {
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
if (this.state.redirect) {
|
<ReportDeviceTable paramsObject={params} />
|
||||||
return <Redirect to='/entgra' />
|
</div>
|
||||||
}
|
</PageHeader>
|
||||||
}
|
)}
|
||||||
|
</div>
|
||||||
onClickPieChart = (value) => {
|
</div>
|
||||||
const chartValue = value.data.point.item;
|
);
|
||||||
let tempParamObj = this.state.paramsObject;
|
}
|
||||||
|
|
||||||
console.log(chartValue)
|
|
||||||
|
|
||||||
// tempParamObj.status = chartValue;
|
|
||||||
|
|
||||||
if(chartValue==="Enrollments"){
|
|
||||||
tempParamObj.status = "ACTIVE&status=INACTIVE"
|
|
||||||
}else{
|
|
||||||
tempParamObj.status = "REMOVED"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.setState({paramsObject:tempParamObj});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { reportData } = this.props.location;
|
|
||||||
|
|
||||||
console.log("======")
|
|
||||||
console.log(reportData)
|
|
||||||
console.log("======")
|
|
||||||
|
|
||||||
let reportDataClone = {
|
|
||||||
params: ["ACTIVE"],
|
|
||||||
duration: ["2020-01-01","2020-01-01"]
|
|
||||||
};
|
|
||||||
|
|
||||||
const params = {...this.state.paramsObject};
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<div>{!reportData ? (
|
|
||||||
<Redirect to='/entgra/reports' />
|
|
||||||
) : (
|
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap" style={{marginBottom: '10px'}}>
|
|
||||||
<h3>Summary of enrollments</h3>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Card
|
|
||||||
bordered={true}
|
|
||||||
hoverable={true}
|
|
||||||
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
|
|
||||||
|
|
||||||
|
|
||||||
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData? reportData : reportDataClone}/>
|
|
||||||
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
|
||||||
<ReportDeviceTable paramsObject={params}/>
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
|
|
||||||
)}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(EnrollmentsVsUnenrollmentsReport);
|
export default withConfigContext(EnrollmentsVsUnenrollmentsReport);
|
||||||
|
|||||||
@ -1,63 +1,47 @@
|
|||||||
import React from "react";
|
import React from 'react';
|
||||||
|
|
||||||
import {Card, Col, Icon} from "antd";
|
import { Card, Col } from 'antd';
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
|
|
||||||
class CountWidget extends React.Component {
|
class CountWidget extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.routes = props.routes;
|
||||||
|
this.state = {
|
||||||
|
statArray: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
componentDidMount() {
|
||||||
super(props);
|
this.setState({ statArray: this.props.statArray });
|
||||||
this.routes = props.routes;
|
console.log('$$$$');
|
||||||
this.state = {
|
console.log(this.props.statArray);
|
||||||
statArray:[]
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
render() {
|
||||||
this.setState({statArray:this.props.statArray})
|
const { statArray } = this.state;
|
||||||
console.log("$$$$")
|
|
||||||
console.log(this.props.statArray)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let card = statArray.map(data => (
|
||||||
|
<Col key={data.item} span={6}>
|
||||||
|
<Card
|
||||||
|
key={data.item}
|
||||||
|
bordered={true}
|
||||||
|
hoverable={true}
|
||||||
|
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||||
|
>
|
||||||
|
<div align="center">
|
||||||
|
<h2>
|
||||||
|
<b>{data.item}</b>
|
||||||
|
</h2>
|
||||||
|
<h1>{data.count}</h1>
|
||||||
|
{/* <p>{data.duration}</p>*/}
|
||||||
|
{/* <ReportFilterModal/>*/}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
));
|
||||||
|
|
||||||
render() {
|
return <div>{card}</div>;
|
||||||
const countObj = [
|
}
|
||||||
{item:"All",count:100},
|
|
||||||
{item:"Enrolled",count:80},
|
|
||||||
{item:"Unenrolled",count:20}];
|
|
||||||
|
|
||||||
const { statArray } = this.state;
|
|
||||||
|
|
||||||
let card = statArray.map((data) =>
|
|
||||||
// <Card
|
|
||||||
// bordered={true}
|
|
||||||
// hoverable={true}
|
|
||||||
// key={data.item}
|
|
||||||
// style={{borderRadius: 5, marginBottom: 5, width:"100%"}}>
|
|
||||||
//
|
|
||||||
// <h3>{data.item} Devices: {data.count}</h3>
|
|
||||||
//
|
|
||||||
// </Card>
|
|
||||||
<Col key={data.item} span={6}>
|
|
||||||
<Card key={data.item} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
|
|
||||||
|
|
||||||
<div align='center'>
|
|
||||||
<h2><b>{data.item}</b></h2>
|
|
||||||
<h1>{data.count}</h1>
|
|
||||||
{/*<p>{data.duration}</p>*/}
|
|
||||||
{/*<ReportFilterModal/>*/}
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
)
|
|
||||||
|
|
||||||
return(
|
|
||||||
<div>
|
|
||||||
{card}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CountWidget;
|
export default CountWidget;
|
||||||
|
|||||||
@ -1,322 +1,342 @@
|
|||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
G2,
|
Chart,
|
||||||
Chart,
|
Geom,
|
||||||
Geom,
|
Axis,
|
||||||
Axis,
|
Tooltip,
|
||||||
Tooltip,
|
Coord,
|
||||||
Coord,
|
Label,
|
||||||
Label,
|
Legend,
|
||||||
Legend,
|
Guide,
|
||||||
View,
|
} from 'bizcharts';
|
||||||
Guide,
|
import DataSet from '@antv/data-set';
|
||||||
Shape,
|
import axios from 'axios';
|
||||||
Facet,
|
import { message, notification } from 'antd';
|
||||||
Util
|
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;
|
let config = null;
|
||||||
|
|
||||||
class PieChart extends React.Component {
|
class PieChart extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
config = this.props.context;
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
statArray: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
componentDidMount() {
|
||||||
super(props);
|
const { reportData } = this.props;
|
||||||
config = this.props.context;
|
let params = {
|
||||||
this.state = {
|
status: reportData.params[0],
|
||||||
loading:true,
|
from: reportData.duration[0],
|
||||||
statArray:[]
|
to: reportData.duration[1],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const urlSet = {
|
||||||
|
paramsList: reportData.params,
|
||||||
|
duration: reportData.duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(urlSet);
|
||||||
|
|
||||||
|
if (reportData.params[0] === 'Enrollments') {
|
||||||
|
this.getEnrollmentsVsUnenrollmentsCount(params, urlSet);
|
||||||
|
} else if (reportData.params[0] === 'BYOD') {
|
||||||
|
this.getEnrollmentTypeCount(params, urlSet);
|
||||||
|
} else {
|
||||||
|
this.getCount(params, urlSet);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
clicked = () => {
|
||||||
let { statArray } = this.state;
|
console.log('Clicked...!!');
|
||||||
const { reportData } = this.props;
|
};
|
||||||
let params = {
|
|
||||||
status: reportData.params[0],
|
|
||||||
from: reportData.duration[0],
|
|
||||||
to: reportData.duration[1]
|
|
||||||
};
|
|
||||||
|
|
||||||
const urlSet = {
|
onChartChange = data => {
|
||||||
paramsList:reportData.params,
|
this.props.onClickPieChart(data);
|
||||||
duration:reportData.duration
|
};
|
||||||
};
|
|
||||||
|
|
||||||
console.log(urlSet)
|
statArray = [];
|
||||||
|
|
||||||
if(reportData.params[0]==="Enrollments"){
|
// Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||||
this.getEnrollmentsVsUnenrollmentsCount(params, urlSet)
|
getCount = (params, urlSet) => {
|
||||||
}else if(reportData.params[0]==="BYOD"){
|
this.setState({ loading: true });
|
||||||
this.getEnrollmentTypeCount(params, urlSet);
|
|
||||||
}else{
|
let { statArray } = this.state;
|
||||||
this.getCount(params, urlSet);
|
|
||||||
|
console.log(urlSet);
|
||||||
|
|
||||||
|
const urlArray = [];
|
||||||
|
|
||||||
|
urlSet.paramsList.map(data => {
|
||||||
|
const paramsObj = {
|
||||||
|
status: data,
|
||||||
|
from: urlSet.duration[0],
|
||||||
|
to: urlSet.duration[1],
|
||||||
|
};
|
||||||
|
// console.log(paramsObj)
|
||||||
|
const encodedExtraParams = Object.keys(paramsObj)
|
||||||
|
.map(key => key + '=' + paramsObj[key])
|
||||||
|
.join('&');
|
||||||
|
const apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/reports/devices/count?' +
|
||||||
|
encodedExtraParams;
|
||||||
|
|
||||||
|
urlArray.push(axios.get(apiUrl, data));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(urlArray);
|
||||||
|
|
||||||
|
axios
|
||||||
|
.all(urlArray)
|
||||||
|
.then(res => {
|
||||||
|
res.map(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
let countData = {
|
||||||
|
item: response.config[0],
|
||||||
|
// eslint-disable-next-line radix
|
||||||
|
count: parseInt(response.data.data),
|
||||||
|
};
|
||||||
|
statArray.push(countData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setState({ statArray });
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popup with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to get device count.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
};
|
||||||
|
|
||||||
clicked = () => {
|
// Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||||
console.log("Clicked...!!")
|
getEnrollmentsVsUnenrollmentsCount = (params, urlSet) => {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
let { statArray } = this.state;
|
||||||
|
|
||||||
|
console.log(urlSet);
|
||||||
|
|
||||||
|
const urlArray = [];
|
||||||
|
|
||||||
|
urlSet.paramsList.map(data => {
|
||||||
|
const paramsObj = {
|
||||||
|
from: urlSet.duration[0],
|
||||||
|
to: urlSet.duration[1],
|
||||||
|
};
|
||||||
|
const encodedExtraParams = Object.keys(paramsObj)
|
||||||
|
.map(key => key + '=' + paramsObj[key])
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
let apiUrl;
|
||||||
|
if (data === 'Enrollments') {
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/reports/devices/count?status=ACTIVE&status=INACTIVE&' +
|
||||||
|
encodedExtraParams;
|
||||||
|
} else {
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/reports/devices/count?status=REMOVED&' +
|
||||||
|
encodedExtraParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
urlArray.push(axios.get(apiUrl, data));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(urlArray);
|
||||||
|
|
||||||
|
axios
|
||||||
|
.all(urlArray)
|
||||||
|
.then(res => {
|
||||||
|
res.map(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
let countData = {
|
||||||
|
item: response.config[0],
|
||||||
|
// eslint-disable-next-line radix
|
||||||
|
count: parseInt(response.data.data),
|
||||||
|
};
|
||||||
|
statArray.push(countData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setState({ statArray });
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popup with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to get device count.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||||
|
getEnrollmentTypeCount = (params, urlSet) => {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
let { statArray } = this.state;
|
||||||
|
|
||||||
|
console.log(urlSet);
|
||||||
|
|
||||||
|
const urlArray = [];
|
||||||
|
|
||||||
|
urlSet.paramsList.map(data => {
|
||||||
|
const paramsObj = {
|
||||||
|
ownership: data,
|
||||||
|
from: urlSet.duration[0],
|
||||||
|
to: urlSet.duration[1],
|
||||||
|
};
|
||||||
|
const encodedExtraParams = Object.keys(paramsObj)
|
||||||
|
.map(key => key + '=' + paramsObj[key])
|
||||||
|
.join('&');
|
||||||
|
const apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/reports/devices/count?' +
|
||||||
|
encodedExtraParams;
|
||||||
|
|
||||||
|
urlArray.push(axios.get(apiUrl, data));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(urlArray);
|
||||||
|
|
||||||
|
axios
|
||||||
|
.all(urlArray)
|
||||||
|
.then(res => {
|
||||||
|
res.map(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
let countData = {
|
||||||
|
item: response.config[0],
|
||||||
|
// eslint-disable-next-line radix
|
||||||
|
count: parseInt(response.data.data),
|
||||||
|
};
|
||||||
|
statArray.push(countData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setState({ statArray });
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popup with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to get device count.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { DataView } = DataSet;
|
||||||
|
const { Html } = Guide;
|
||||||
|
const { statArray } = this.state;
|
||||||
|
|
||||||
|
const dv = new DataView();
|
||||||
|
dv.source(statArray).transform({
|
||||||
|
type: 'percent',
|
||||||
|
field: 'count',
|
||||||
|
dimension: 'item',
|
||||||
|
as: 'percent',
|
||||||
|
});
|
||||||
|
const cols = {
|
||||||
|
percent: {
|
||||||
|
formatter: val => {
|
||||||
|
val = val * 100 + '%';
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
onChartChange = (data) => {
|
return (
|
||||||
this.props.onClickPieChart(data);
|
<div>
|
||||||
};
|
<Chart
|
||||||
|
height={window.innerHeight / 2}
|
||||||
statArray = [];
|
data={dv}
|
||||||
|
scale={cols}
|
||||||
//Call count APIs and get count for given parameters, then create data object to build pie chart
|
padding={[20, 25, 20, 20]}
|
||||||
getCount = (params, urlSet) => {
|
forceFit
|
||||||
|
onPlotClick={this.onChartChange}
|
||||||
this.setState({loading: true});
|
animate={true}
|
||||||
|
>
|
||||||
let { statArray } = this.state;
|
<Coord type={'theta'} radius={0.75} innerRadius={0.6} />
|
||||||
|
<Axis name="percent" />
|
||||||
console.log(urlSet);
|
<Legend
|
||||||
|
position="right"
|
||||||
const urlArray = [];
|
offsetY={-window.innerHeight / 2 + 120}
|
||||||
|
offsetX={-100}
|
||||||
urlSet.paramsList.map((data) => {
|
/>
|
||||||
const paramsObj = {
|
<Tooltip
|
||||||
status:data,
|
showTitle={false}
|
||||||
from:urlSet.duration[0],
|
itemTpl='<li><span style="background-color:{color};" class="g2-tooltip-marker"></span>{name}: {value}</li>'
|
||||||
to:urlSet.duration[1]
|
/>
|
||||||
}
|
<Guide>
|
||||||
// console.log(paramsObj)
|
<Html
|
||||||
const encodedExtraParams = Object.keys(paramsObj)
|
position={['50%', '50%']}
|
||||||
.map(key => key + '=' + paramsObj[key]).join('&');
|
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>'
|
||||||
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
alignX="middle"
|
||||||
config.serverConfig.invoker.deviceMgt +
|
alignY="middle"
|
||||||
"/reports/devices/count?" + encodedExtraParams;
|
/>
|
||||||
|
</Guide>
|
||||||
urlArray.push(axios.get(apiUrl, data));
|
<div onClick={this.clicked}>
|
||||||
});
|
<Geom
|
||||||
|
type="intervalStack"
|
||||||
console.log(urlArray)
|
position="percent"
|
||||||
|
color="item"
|
||||||
|
tooltip={[
|
||||||
axios.all(urlArray).then(res => {
|
'item*percent',
|
||||||
|
(item, percent) => {
|
||||||
res.map((response) => {
|
percent = percent * 100 + '%';
|
||||||
if(response.status === 200){
|
return {
|
||||||
let countData = {item:response.config[0], count:parseInt(response.data.data)}
|
name: item,
|
||||||
statArray.push(countData);
|
value: percent,
|
||||||
}
|
};
|
||||||
})
|
},
|
||||||
this.setState({statArray})
|
]}
|
||||||
}).catch((error) => {
|
style={{
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
lineWidth: 1,
|
||||||
//todo display a popup with error
|
stroke: '#fff',
|
||||||
message.error('You are not logged in');
|
}}
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
>
|
||||||
} else {
|
<Label
|
||||||
notification["error"]({
|
content="percent"
|
||||||
message: "There was a problem",
|
formatter={(val, item) => {
|
||||||
duration: 0,
|
return item.point.item + ': ' + val;
|
||||||
description:"Error occurred while trying to get device count.",
|
}}
|
||||||
});
|
/>
|
||||||
}
|
</Geom>
|
||||||
});
|
</div>
|
||||||
};
|
</Chart>
|
||||||
|
</div>
|
||||||
//Call count APIs and get count for given parameters, then create data object to build pie chart
|
);
|
||||||
getEnrollmentsVsUnenrollmentsCount = (params, urlSet) => {
|
}
|
||||||
|
|
||||||
this.setState({loading: true});
|
|
||||||
|
|
||||||
let { statArray } = this.state;
|
|
||||||
|
|
||||||
console.log(urlSet);
|
|
||||||
|
|
||||||
const urlArray = [];
|
|
||||||
|
|
||||||
urlSet.paramsList.map((data) => {
|
|
||||||
const paramsObj = {
|
|
||||||
from:urlSet.duration[0],
|
|
||||||
to:urlSet.duration[1]
|
|
||||||
}
|
|
||||||
const encodedExtraParams = Object.keys(paramsObj)
|
|
||||||
.map(key => key + '=' + paramsObj[key]).join('&');
|
|
||||||
|
|
||||||
let apiUrl;
|
|
||||||
if(data==="Enrollments"){
|
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/reports/devices/count?status=ACTIVE&status=INACTIVE&" + encodedExtraParams;
|
|
||||||
}else{
|
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/reports/devices/count?status=REMOVED&" + encodedExtraParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
urlArray.push(axios.get(apiUrl, data));
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(urlArray)
|
|
||||||
|
|
||||||
|
|
||||||
axios.all(urlArray).then(res => {
|
|
||||||
res.map((response) => {
|
|
||||||
if(response.status === 200){
|
|
||||||
let countData = {item:response.config[0], count:parseInt(response.data.data)}
|
|
||||||
statArray.push(countData);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.setState({statArray})
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popup with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to get device count.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//Call count APIs and get count for given parameters, then create data object to build pie chart
|
|
||||||
getEnrollmentTypeCount = (params, urlSet) => {
|
|
||||||
|
|
||||||
this.setState({loading: true});
|
|
||||||
|
|
||||||
let { statArray } = this.state;
|
|
||||||
|
|
||||||
console.log(urlSet);
|
|
||||||
|
|
||||||
const urlArray = [];
|
|
||||||
|
|
||||||
urlSet.paramsList.map((data) => {
|
|
||||||
const paramsObj = {
|
|
||||||
ownership:data,
|
|
||||||
from:urlSet.duration[0],
|
|
||||||
to:urlSet.duration[1]
|
|
||||||
}
|
|
||||||
const encodedExtraParams = Object.keys(paramsObj)
|
|
||||||
.map(key => key + '=' + paramsObj[key]).join('&');
|
|
||||||
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/reports/devices/count?" + encodedExtraParams;
|
|
||||||
|
|
||||||
urlArray.push(axios.get(apiUrl, data));
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(urlArray)
|
|
||||||
|
|
||||||
|
|
||||||
axios.all(urlArray).then(res => {
|
|
||||||
res.map((response) => {
|
|
||||||
if(response.status === 200){
|
|
||||||
let countData = {item:response.config[0], count:parseInt(response.data.data)}
|
|
||||||
statArray.push(countData);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.setState({statArray})
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popup with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to get device count.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { DataView } = DataSet;
|
|
||||||
const { Html } = Guide;
|
|
||||||
const { statArray , loading} = this.state;
|
|
||||||
|
|
||||||
const dv = new DataView();
|
|
||||||
dv.source(statArray).transform({
|
|
||||||
type: "percent",
|
|
||||||
field: "count",
|
|
||||||
dimension: "item",
|
|
||||||
as: "percent"
|
|
||||||
});
|
|
||||||
const cols = {
|
|
||||||
percent: {
|
|
||||||
formatter: val => {
|
|
||||||
val = val * 100 + "%";
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Chart
|
|
||||||
height={window.innerHeight/2}
|
|
||||||
data={dv}
|
|
||||||
scale={cols}
|
|
||||||
padding={[20, 25, 20, 20]}
|
|
||||||
forceFit
|
|
||||||
onPlotClick={this.onChartChange}
|
|
||||||
animate={true}
|
|
||||||
>
|
|
||||||
<Coord type={"theta"} radius={0.75} innerRadius={0.6} />
|
|
||||||
<Axis name="percent" />
|
|
||||||
<Legend
|
|
||||||
position="right"
|
|
||||||
offsetY={-window.innerHeight / 2 + 120}
|
|
||||||
offsetX={-100}
|
|
||||||
/>
|
|
||||||
<Tooltip
|
|
||||||
showTitle={false}
|
|
||||||
itemTpl="<li><span style="background-color:{color};" class="g2-tooltip-marker"></span>{name}: {value}</li>"
|
|
||||||
/>
|
|
||||||
<Guide>
|
|
||||||
<Html
|
|
||||||
position={["50%", "50%"]}
|
|
||||||
html="<div style="color:#8c8c8c;font-size:1.16em;text-align: center;width: 10em;">Total<br><span style="color:#262626;font-size:2.5em">200</span>台</div>"
|
|
||||||
alignX="middle"
|
|
||||||
alignY="middle"
|
|
||||||
/>
|
|
||||||
</Guide>
|
|
||||||
<div onClick={this.clicked}>
|
|
||||||
<Geom
|
|
||||||
type="intervalStack"
|
|
||||||
position="percent"
|
|
||||||
color="item"
|
|
||||||
|
|
||||||
tooltip={[
|
|
||||||
"item*percent",
|
|
||||||
(item, percent) => {
|
|
||||||
percent = percent * 100 + "%";
|
|
||||||
return {
|
|
||||||
name: item,
|
|
||||||
value: percent
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
style={{
|
|
||||||
lineWidth: 1,
|
|
||||||
stroke: "#fff"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Label
|
|
||||||
content="percent"
|
|
||||||
formatter={(val, item) => {
|
|
||||||
return item.point.item + ": " + val;
|
|
||||||
}}/>
|
|
||||||
</Geom>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Chart>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(PieChart);
|
export default withConfigContext(PieChart);
|
||||||
|
|||||||
@ -1,340 +1,392 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Button, Form, Input, message, Modal, notification, Select, Tree} from "antd";
|
import {
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
Button,
|
||||||
import axios from "axios";
|
Form,
|
||||||
|
Input,
|
||||||
|
message,
|
||||||
|
Modal,
|
||||||
|
notification,
|
||||||
|
Select,
|
||||||
|
Tree,
|
||||||
|
} from 'antd';
|
||||||
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
const {Option} = Select;
|
const { Option } = Select;
|
||||||
const {TreeNode} = Tree;
|
const { TreeNode } = Tree;
|
||||||
|
|
||||||
class AddRole extends React.Component {
|
class AddRole extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.config = this.props.context;
|
||||||
|
this.expandKeys = [];
|
||||||
|
this.state = {
|
||||||
|
isAddRoleModalVisible: false,
|
||||||
|
isAddPermissionModalVisible: false,
|
||||||
|
roleName: '',
|
||||||
|
users: [],
|
||||||
|
nodeList: [],
|
||||||
|
expandedKeys: [],
|
||||||
|
autoExpandParent: true,
|
||||||
|
checkedKeys: [],
|
||||||
|
isNodeList: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
openAddModal = () => {
|
||||||
super(props);
|
this.setState({
|
||||||
this.config = this.props.context;
|
isAddRoleModalVisible: true,
|
||||||
this.expandKeys = [];
|
});
|
||||||
this.state = {
|
};
|
||||||
|
|
||||||
|
onCancelHandler = e => {
|
||||||
|
this.setState({
|
||||||
|
isAddRoleModalVisible: false,
|
||||||
|
isAddPermissionModalVisible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getCheckedPermissionsList = data => {
|
||||||
|
data.forEach(item => {
|
||||||
|
if (item !== null) {
|
||||||
|
this.expandKeys.push(item.resourcePath);
|
||||||
|
this.getCheckedPermissionsList(item.nodeList);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onAddRole = e => {
|
||||||
|
this.props.form.validateFields((err, values) => {
|
||||||
|
if (!err) {
|
||||||
|
this.onConfirmAddRole(values);
|
||||||
|
}
|
||||||
|
console.log(values);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onExpand = expandedKeys => {
|
||||||
|
this.setState({
|
||||||
|
expandedKeys,
|
||||||
|
autoExpandParent: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onCheck = checkedKeys => {
|
||||||
|
this.setState({ checkedKeys });
|
||||||
|
};
|
||||||
|
|
||||||
|
onConfirmAddRole = value => {
|
||||||
|
const roleData = {
|
||||||
|
roleName: value.roleName,
|
||||||
|
users: value.users,
|
||||||
|
};
|
||||||
|
this.setState({
|
||||||
|
roleName: value.roleName,
|
||||||
|
});
|
||||||
|
axios
|
||||||
|
.post(
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles',
|
||||||
|
roleData,
|
||||||
|
{ headers: { 'Content-Type': 'application-json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 201) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
this.setState({
|
||||||
isAddRoleModalVisible: false,
|
isAddRoleModalVisible: false,
|
||||||
isAddPermissionModalVisible: false,
|
isAddPermissionModalVisible: true,
|
||||||
roleName: '',
|
});
|
||||||
users: [],
|
notification.success({
|
||||||
nodeList: [],
|
message: 'Done',
|
||||||
expandedKeys: [],
|
duration: 4,
|
||||||
autoExpandParent: true,
|
description: 'Successfully added the role.',
|
||||||
checkedKeys: [],
|
});
|
||||||
isNodeList: false,
|
this.loadPermissionList();
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to add role.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
openAddModal = () => {
|
renderTreeNodes = data => {
|
||||||
this.setState({
|
return data.map(item => {
|
||||||
isAddRoleModalVisible: true
|
if (item !== null) {
|
||||||
});
|
if (item.hasOwnProperty('nodeList')) {
|
||||||
|
return (
|
||||||
|
<TreeNode
|
||||||
|
title={item.displayName}
|
||||||
|
key={item.resourcePath}
|
||||||
|
dataRef={item}
|
||||||
|
>
|
||||||
|
{this.renderTreeNodes(item.nodeList)}
|
||||||
|
</TreeNode>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <TreeNode key={item.resourcePath} {...item} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/jsx-key
|
||||||
|
return <TreeNode />;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onAssignPermissions = () => {
|
||||||
|
const roleData = {
|
||||||
|
roleName: this.state.roleName,
|
||||||
|
permissions: this.state.checkedKeys,
|
||||||
};
|
};
|
||||||
|
axios
|
||||||
onCancelHandler = e => {
|
.put(
|
||||||
this.setState({
|
window.location.origin +
|
||||||
isAddRoleModalVisible: false,
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles/' +
|
||||||
|
this.state.roleName,
|
||||||
|
roleData,
|
||||||
|
{ headers: { 'Content-Type': 'application-json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully Updated the Permissions.',
|
||||||
|
});
|
||||||
|
this.setState({
|
||||||
isAddPermissionModalVisible: false,
|
isAddPermissionModalVisible: false,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to add permissions.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
getCheckedPermissionsList = (data) =>{
|
loadPermissionList = () => {
|
||||||
data.forEach(item => {
|
let apiURL =
|
||||||
if (item !== null) {
|
window.location.origin +
|
||||||
this.expandKeys.push(item.resourcePath);
|
this.config.serverConfig.invoker.uri +
|
||||||
this.getCheckedPermissionsList(item.nodeList);
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
}else{
|
'/roles/' +
|
||||||
return null;
|
this.state.roleName +
|
||||||
}
|
'/permissions';
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onAddRole = e => {
|
axios
|
||||||
this.props.form.validateFields((err, values) => {
|
.get(apiURL)
|
||||||
if (!err) {
|
.then(res => {
|
||||||
this.onConfirmAddRole(values);
|
if (res.status === 200) {
|
||||||
}
|
this.getCheckedPermissionsList(res.data.data.nodeList);
|
||||||
console.log(values);
|
this.setState({
|
||||||
});
|
nodeList: res.data.data.nodeList,
|
||||||
};
|
isNodeList: true,
|
||||||
|
expandedKeys: this.expandKeys,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load permission.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onExpand = expandedKeys => {
|
loadUsersList = value => {
|
||||||
this.setState({
|
let apiURL =
|
||||||
expandedKeys,
|
window.location.origin +
|
||||||
autoExpandParent: false,
|
this.config.serverConfig.invoker.uri +
|
||||||
});
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
};
|
'/users/search/usernames?filter=' +
|
||||||
|
value +
|
||||||
|
'&domain=Primary';
|
||||||
|
axios
|
||||||
|
.get(apiURL)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
let user = JSON.parse(res.data.data);
|
||||||
|
let users = [];
|
||||||
|
for (let i = 0; i < user.length; i++) {
|
||||||
|
users.push(
|
||||||
|
<Option key={user[i].username}>{user[i].username}</Option>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
users: users,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load users.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onCheck = checkedKeys => {
|
render() {
|
||||||
this.setState({checkedKeys});
|
const { getFieldDecorator } = this.props.form;
|
||||||
};
|
return (
|
||||||
|
<div>
|
||||||
onConfirmAddRole = (value) => {
|
<div>
|
||||||
const roleData = {
|
<Button
|
||||||
roleName: value.roleName,
|
type="primary"
|
||||||
users: value.users,
|
icon="plus"
|
||||||
};
|
size={'default'}
|
||||||
this.setState({
|
onClick={this.openAddModal}
|
||||||
roleName: value.roleName,
|
style={{ marginBottom: '10px' }}
|
||||||
});
|
>
|
||||||
axios.post(
|
Add Role
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
</Button>
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
</div>
|
||||||
"/roles",
|
<div>
|
||||||
roleData,
|
<Modal
|
||||||
{headers: {'Content-Type': 'application-json'}}
|
title="ADD NEW ROLE"
|
||||||
).then(res => {
|
width="40%"
|
||||||
if (res.status === 201) {
|
visible={this.state.isAddRoleModalVisible}
|
||||||
this.props.fetchUsers();
|
onOk={this.onAddRole}
|
||||||
this.setState({
|
onCancel={this.onCancelHandler}
|
||||||
isAddRoleModalVisible: false,
|
footer={[
|
||||||
isAddPermissionModalVisible: true,
|
<Button key="cancel" onClick={this.onCancelHandler}>
|
||||||
|
Cancel
|
||||||
});
|
</Button>,
|
||||||
notification["success"]({
|
<Button key="submit" type="primary" onClick={this.onAddRole}>
|
||||||
message: "Done",
|
Add Role
|
||||||
duration: 4,
|
</Button>,
|
||||||
description:
|
]}
|
||||||
"Successfully added the role.",
|
>
|
||||||
});
|
<div style={{ alignItems: 'center' }}>
|
||||||
this.loadPermissionList();
|
<p>Create new user on IoT Server.</p>
|
||||||
}
|
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
||||||
}).catch((error) => {
|
<Form.Item
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
label="User Store Domain"
|
||||||
//todo display a popop with error
|
style={{ display: 'block' }}
|
||||||
message.error('You are not logged in');
|
>
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
{getFieldDecorator('userStoreDomain', {
|
||||||
} else {
|
initialValue: 'PRIMARY',
|
||||||
notification["error"]({
|
})(
|
||||||
message: "There was a problem",
|
<Select>
|
||||||
duration: 0,
|
<Option key="PRIMARY">PRIMARY</Option>
|
||||||
description:
|
</Select>,
|
||||||
"Error occurred while trying to add role.",
|
)}
|
||||||
});
|
</Form.Item>
|
||||||
}
|
<Form.Item label="Role Name" style={{ display: 'block' }}>
|
||||||
});
|
{getFieldDecorator('roleName', {
|
||||||
};
|
rules: [
|
||||||
|
{
|
||||||
renderTreeNodes = (data) => {
|
pattern: new RegExp('^(((?!(\\@|\\/|\\s)).){3,})*$'),
|
||||||
return data.map(item => {
|
message:
|
||||||
if (item !== null) {
|
'Role name should be in minimum 3 characters long and not ' +
|
||||||
if (item.hasOwnProperty("nodeList")) {
|
'include any whitespaces or @ or /',
|
||||||
return (
|
},
|
||||||
<TreeNode title={item.displayName} key={item.resourcePath} dataRef={item}>
|
{
|
||||||
{this.renderTreeNodes(item.nodeList)}
|
required: true,
|
||||||
</TreeNode>
|
message: 'This field is required.',
|
||||||
);
|
},
|
||||||
}
|
],
|
||||||
return <TreeNode key={item.resourcePath} {...item}/>;
|
})(<Input />)}
|
||||||
}
|
</Form.Item>
|
||||||
else{
|
<Form.Item label="User List" style={{ display: 'block' }}>
|
||||||
return <TreeNode/>;
|
{getFieldDecorator('users', {})(
|
||||||
}
|
<Select
|
||||||
});
|
mode="multiple"
|
||||||
};
|
style={{ width: '100%' }}
|
||||||
|
onSearch={this.loadUsersList}
|
||||||
onAssignPermissions = () =>{
|
>
|
||||||
const roleData = {
|
{this.state.users}
|
||||||
roleName : this.state.roleName,
|
</Select>,
|
||||||
permissions : this.state.checkedKeys
|
)}
|
||||||
};
|
</Form.Item>
|
||||||
axios.put(
|
</Form>
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/roles/"+ this.state.roleName,
|
|
||||||
roleData,
|
|
||||||
{headers: {'Content-Type' : 'application-json'}}
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully Updated the Permissions.",
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
isAddPermissionModalVisible : false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to add permissions.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
loadPermissionList = () => {
|
|
||||||
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt + "/roles/" + this.state.roleName + "/permissions";
|
|
||||||
|
|
||||||
axios.get(apiURL).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.getCheckedPermissionsList(res.data.data.nodeList);
|
|
||||||
this.setState({
|
|
||||||
nodeList: res.data.data.nodeList,
|
|
||||||
isNodeList: true,
|
|
||||||
expandedKeys : this.expandKeys
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description: "Error occurred while trying to load permission.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
loadUsersList = (value) => {
|
|
||||||
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt + "/users/search/usernames?filter=" + value + "&domain=Primary";
|
|
||||||
axios.get(apiURL).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let user = JSON.parse(res.data.data);
|
|
||||||
let users = [];
|
|
||||||
for (let i = 0; i < user.length; i++) {
|
|
||||||
users.push(<Option key={user[i].username}>{user[i].username}</Option>);
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
users: users
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description: "Error occurred while trying to load users.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {getFieldDecorator} = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal}
|
|
||||||
style={{marginBottom: '10px'}}>
|
|
||||||
Add Role
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="ADD NEW ROLE"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.isAddRoleModalVisible}
|
|
||||||
onOk={this.onAddRole}
|
|
||||||
onCancel={this.onCancelHandler}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.onAddRole}>
|
|
||||||
Add Role
|
|
||||||
</Button>,
|
|
||||||
]}>
|
|
||||||
<div style={{alignItems: "center"}}>
|
|
||||||
<p>Create new user on IoT Server.</p>
|
|
||||||
<Form
|
|
||||||
labelCol={{span: 5}}
|
|
||||||
wrapperCol={{span: 18}}>
|
|
||||||
<Form.Item label="User Store Domain" style={{display: "block"}}>
|
|
||||||
{getFieldDecorator('userStoreDomain', {
|
|
||||||
initialValue: 'PRIMARY'
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
<Option key="PRIMARY">PRIMARY</Option>
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Role Name" style={{display: "block"}}>
|
|
||||||
{getFieldDecorator('roleName', {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
pattern: new RegExp("^(((?!(\\@|\\/|\\s)).){3,})*$"),
|
|
||||||
message: 'Role name should be in minimum 3 characters long and not ' +
|
|
||||||
'include any whitespaces or @ or /',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required.',
|
|
||||||
},
|
|
||||||
|
|
||||||
],
|
|
||||||
})(<Input/>)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="User List" style={{display: "block"}}>
|
|
||||||
{getFieldDecorator('users', {})(<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{width: '100%'}}
|
|
||||||
onSearch={this.loadUsersList}>
|
|
||||||
{this.state.users}
|
|
||||||
</Select>)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="CHANGE ROLE PERMISSION"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.isAddPermissionModalVisible}
|
|
||||||
onOk={this.onAssignPermissions}
|
|
||||||
onCancel={this.onCancelHandler}
|
|
||||||
bodyStyle={{overflowY:"scroll", maxHeight:'500px', marginLeft:'10px'}}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.onAssignPermissions}>
|
|
||||||
Assign
|
|
||||||
</Button>,
|
|
||||||
]}>
|
|
||||||
<div style={{alignItems: "center"}}>
|
|
||||||
<div>
|
|
||||||
{(this.state.isNodeList) && (
|
|
||||||
<Tree
|
|
||||||
checkable
|
|
||||||
onExpand={this.onExpand}
|
|
||||||
expandedKeys={this.state.expandedKeys}
|
|
||||||
autoExpandParent={this.state.autoExpandParent}
|
|
||||||
onCheck={this.onCheck}
|
|
||||||
checkedKeys={this.state.checkedKeys}>
|
|
||||||
{this.renderTreeNodes(this.state.nodeList)}
|
|
||||||
</Tree>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</Modal>
|
||||||
}
|
</div>
|
||||||
|
<div>
|
||||||
|
<Modal
|
||||||
|
title="CHANGE ROLE PERMISSION"
|
||||||
|
width="40%"
|
||||||
|
visible={this.state.isAddPermissionModalVisible}
|
||||||
|
onOk={this.onAssignPermissions}
|
||||||
|
onCancel={this.onCancelHandler}
|
||||||
|
bodyStyle={{
|
||||||
|
overflowY: 'scroll',
|
||||||
|
maxHeight: '500px',
|
||||||
|
marginLeft: '10px',
|
||||||
|
}}
|
||||||
|
footer={[
|
||||||
|
<Button key="cancel" onClick={this.onCancelHandler}>
|
||||||
|
Cancel
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
key="submit"
|
||||||
|
type="primary"
|
||||||
|
onClick={this.onAssignPermissions}
|
||||||
|
>
|
||||||
|
Assign
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div style={{ alignItems: 'center' }}>
|
||||||
|
<div>
|
||||||
|
{this.state.isNodeList && (
|
||||||
|
<Tree
|
||||||
|
checkable
|
||||||
|
onExpand={this.onExpand}
|
||||||
|
expandedKeys={this.state.expandedKeys}
|
||||||
|
autoExpandParent={this.state.autoExpandParent}
|
||||||
|
onCheck={this.onCheck}
|
||||||
|
checkedKeys={this.state.checkedKeys}
|
||||||
|
>
|
||||||
|
{this.renderTreeNodes(this.state.nodeList)}
|
||||||
|
</Tree>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create({name: 'add-role'})(AddRole))
|
export default withConfigContext(Form.create({ name: 'add-role' })(AddRole));
|
||||||
|
|||||||
@ -1,428 +1,489 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Divider,
|
Divider,
|
||||||
Form,
|
Form,
|
||||||
Icon,
|
Icon,
|
||||||
Input,
|
Input,
|
||||||
message,
|
message,
|
||||||
Modal,
|
Modal,
|
||||||
notification,
|
notification,
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
Select,
|
Select,
|
||||||
Tooltip, Tree,
|
Tooltip,
|
||||||
Typography
|
Tree,
|
||||||
} from "antd";
|
Typography,
|
||||||
import axios from "axios";
|
} from 'antd';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import axios from 'axios';
|
||||||
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
const {Text} = Typography;
|
const { Text } = Typography;
|
||||||
const { TreeNode } = Tree;
|
const { TreeNode } = Tree;
|
||||||
|
|
||||||
class RoleAction extends React.Component {
|
class RoleAction extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.config = this.props.context;
|
this.config = this.props.context;
|
||||||
this.selected = [];
|
this.selected = [];
|
||||||
this.expandKeys = [];
|
this.expandKeys = [];
|
||||||
this.state = {
|
this.state = {
|
||||||
roleData: [],
|
roleData: [],
|
||||||
nodeList : [],
|
nodeList: [],
|
||||||
isNodeList: false,
|
isNodeList: false,
|
||||||
users : [],
|
users: [],
|
||||||
|
isEditRoleModalVisible: false,
|
||||||
|
isEditPermissionModalVisible: false,
|
||||||
|
expandedKeys: [],
|
||||||
|
autoExpandParent: true,
|
||||||
|
checkedKeys: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
openEditRoleModal = () => {
|
||||||
|
let apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles/' +
|
||||||
|
this.props.data;
|
||||||
|
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.setState({
|
||||||
|
roleData: res.data.data,
|
||||||
|
isEditRoleModalVisible: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load role.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
openEditPermissionModal = () => {
|
||||||
|
this.loadPermissionList();
|
||||||
|
this.setState({
|
||||||
|
isEditPermissionModalVisible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loadPermissionList = () => {
|
||||||
|
let apiURL =
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles/' +
|
||||||
|
this.props.data +
|
||||||
|
'/permissions';
|
||||||
|
|
||||||
|
axios
|
||||||
|
.get(apiURL)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.getCheckedPermissions(res.data.data.nodeList);
|
||||||
|
this.setState({
|
||||||
|
nodeList: res.data.data.nodeList,
|
||||||
|
isNodeList: true,
|
||||||
|
checkedKeys: this.selected,
|
||||||
|
expandedKeys: this.expandKeys,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load permission.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getCheckedPermissions = data => {
|
||||||
|
data.forEach(item => {
|
||||||
|
if (item !== null) {
|
||||||
|
this.expandKeys.push(item.resourcePath);
|
||||||
|
if (item.isSelected) {
|
||||||
|
this.selected.push(item.resourcePath);
|
||||||
|
}
|
||||||
|
this.getCheckedPermissions(item.nodeList);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onExpand = expandedKeys => {
|
||||||
|
this.setState({
|
||||||
|
expandedKeys,
|
||||||
|
autoExpandParent: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onCheck = checkedKeys => {
|
||||||
|
this.setState({ checkedKeys });
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTreeNodes = data => {
|
||||||
|
return data.map(item => {
|
||||||
|
if (item !== null) {
|
||||||
|
if (item.hasOwnProperty('nodeList')) {
|
||||||
|
return (
|
||||||
|
<TreeNode
|
||||||
|
title={item.displayName}
|
||||||
|
key={item.resourcePath}
|
||||||
|
dataRef={item}
|
||||||
|
>
|
||||||
|
{this.renderTreeNodes(item.nodeList)}
|
||||||
|
</TreeNode>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <TreeNode key={item.resourcePath} {...item} />;
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react/jsx-key
|
||||||
|
return <TreeNode />;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onUpdateRole = e => {
|
||||||
|
this.props.form.validateFields((err, values) => {
|
||||||
|
if (!err) {
|
||||||
|
this.onConfirmUpdateRole(values);
|
||||||
|
}
|
||||||
|
console.log(values);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onCancelHandler = e => {
|
||||||
|
this.setState({
|
||||||
|
isEditRoleModalVisible: false,
|
||||||
|
isEditPermissionModalVisible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onConfirmUpdateRole = value => {
|
||||||
|
const roleData = {
|
||||||
|
roleName: value.roleName,
|
||||||
|
users: value.users,
|
||||||
|
};
|
||||||
|
axios
|
||||||
|
.put(
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles/' +
|
||||||
|
this.props.data,
|
||||||
|
roleData,
|
||||||
|
{ headers: { 'Content-Type': 'application-json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
this.setState({
|
||||||
isEditRoleModalVisible: false,
|
isEditRoleModalVisible: false,
|
||||||
|
});
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully Updated the role.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to add role.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onAssignPermission = () => {
|
||||||
|
const roleData = {
|
||||||
|
roleName: this.props.data,
|
||||||
|
permissions: this.state.checkedKeys,
|
||||||
|
};
|
||||||
|
axios
|
||||||
|
.put(
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles/' +
|
||||||
|
this.props.data,
|
||||||
|
roleData,
|
||||||
|
{ headers: { 'Content-Type': 'application-json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully Updated the Permissions.',
|
||||||
|
});
|
||||||
|
this.setState({
|
||||||
isEditPermissionModalVisible: false,
|
isEditPermissionModalVisible: false,
|
||||||
expandedKeys: [],
|
});
|
||||||
autoExpandParent: true,
|
}
|
||||||
checkedKeys: [],
|
})
|
||||||
};
|
.catch(error => {
|
||||||
}
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to add permissions.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
openEditRoleModal = () =>{
|
loadUsersList = value => {
|
||||||
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
|
let apiURL =
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
window.location.origin +
|
||||||
"/roles/"+ this.props.data;
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/users/search/usernames?filter=' +
|
||||||
|
value +
|
||||||
|
'&domain=Primary';
|
||||||
|
axios
|
||||||
|
.get(apiURL)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
let user = JSON.parse(res.data.data);
|
||||||
|
let users = [];
|
||||||
|
for (let i = 0; i < user.length; i++) {
|
||||||
|
users.push(
|
||||||
|
<Option key={user[i].username}>{user[i].username}</Option>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
users: users,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load users.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
axios.get(apiUrl).then(res => {
|
onDeleteRole = () => {
|
||||||
if (res.status === 200) {
|
axios
|
||||||
this.setState({
|
.delete(
|
||||||
roleData : res.data.data,
|
window.location.origin +
|
||||||
isEditRoleModalVisible: true,
|
this.config.serverConfig.invoker.uri +
|
||||||
});
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
}
|
'/roles/' +
|
||||||
|
this.props.data,
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully deleted the Role.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to delete role.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}).catch((error) => {
|
render() {
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
const isAdminRole = this.props.data === 'admin';
|
||||||
//todo display a popop with error
|
const { getFieldDecorator } = this.props.form;
|
||||||
message.error('You are not logged in');
|
return (
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
<div>
|
||||||
} else {
|
<div style={{ display: isAdminRole ? 'none' : 'inline' }}>
|
||||||
notification["error"]({
|
<Tooltip placement="top" title={'Edit Role'}>
|
||||||
message: "There was a problem",
|
<a>
|
||||||
duration: 0,
|
<Icon type="edit" onClick={this.openEditRoleModal} />
|
||||||
description:"Error occurred while trying to load role.",
|
</a>
|
||||||
});
|
</Tooltip>
|
||||||
}
|
<Divider type="vertical" />
|
||||||
});
|
<Tooltip placement="top" title={'Edit Permissions'}>
|
||||||
};
|
<a>
|
||||||
|
<Icon type="file-add" onClick={this.openEditPermissionModal} />
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
<Divider type="vertical" />
|
||||||
|
<Tooltip placement="bottom" title={'Remove Role'}>
|
||||||
|
<Popconfirm
|
||||||
|
placement="top"
|
||||||
|
title={'Are you sure?'}
|
||||||
|
onConfirm={this.onDeleteRole}
|
||||||
|
okText="Ok"
|
||||||
|
cancelText="Cancel"
|
||||||
|
>
|
||||||
|
<a>
|
||||||
|
<Text type="danger">
|
||||||
|
<Icon type="delete" />
|
||||||
|
</Text>
|
||||||
|
</a>
|
||||||
|
</Popconfirm>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
openEditPermissionModal =()=>{
|
<div>
|
||||||
this.loadPermissionList();
|
<Modal
|
||||||
this.setState({
|
title="EDIT ROLE"
|
||||||
isEditPermissionModalVisible: true,
|
width="40%"
|
||||||
});
|
visible={this.state.isEditRoleModalVisible}
|
||||||
};
|
onOk={this.onUpdateRole}
|
||||||
|
onCancel={this.onCancelHandler}
|
||||||
loadPermissionList = () => {
|
footer={[
|
||||||
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
|
<Button key="cancel" onClick={this.onCancelHandler}>
|
||||||
this.config.serverConfig.invoker.deviceMgt + "/roles/"+this.props.data+"/permissions";
|
Cancel
|
||||||
|
</Button>,
|
||||||
axios.get(apiURL).then(res => {
|
<Button key="submit" type="primary" onClick={this.onUpdateRole}>
|
||||||
if (res.status === 200) {
|
Add Role
|
||||||
this.getCheckedPermissions(res.data.data.nodeList);
|
</Button>,
|
||||||
this.setState({
|
]}
|
||||||
nodeList : res.data.data.nodeList,
|
>
|
||||||
isNodeList: true,
|
<div style={{ alignItems: 'center' }}>
|
||||||
checkedKeys : this.selected,
|
<p>Create new user on IoT Server.</p>
|
||||||
expandedKeys : this.expandKeys
|
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
||||||
});
|
<Form.Item
|
||||||
}
|
label="User Store Domain"
|
||||||
}).catch((error) => {
|
style={{ display: 'block' }}
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
>
|
||||||
//todo display a popop with error
|
{getFieldDecorator('userStoreDomain', {
|
||||||
message.error('You are not logged in');
|
initialValue: 'PRIMARY',
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
})(
|
||||||
} else {
|
<Select>
|
||||||
notification["error"]({
|
<Option key="PRIMARY">PRIMARY</Option>
|
||||||
message: "There was a problem",
|
</Select>,
|
||||||
duration: 0,
|
)}
|
||||||
description:"Error occurred while trying to load permission.",
|
</Form.Item>
|
||||||
});
|
<Form.Item label="Role Name" style={{ display: 'block' }}>
|
||||||
}
|
{getFieldDecorator('roleName', {
|
||||||
})
|
initialValue: this.state.roleData.roleName,
|
||||||
};
|
rules: [
|
||||||
|
{
|
||||||
getCheckedPermissions = (data) =>{
|
pattern: new RegExp('^(((?!(\\@|\\/|\\s)).){3,})*$'),
|
||||||
data.forEach(item => {
|
message:
|
||||||
if (item !== null) {
|
'Role name should be in minimum 3 characters long and not ' +
|
||||||
this.expandKeys.push(item.resourcePath);
|
'include any whitespaces or @ or /',
|
||||||
if (item.isSelected) {
|
},
|
||||||
this.selected.push(item.resourcePath);
|
{
|
||||||
}
|
required: true,
|
||||||
this.getCheckedPermissions(item.nodeList);
|
message: 'This field is required.',
|
||||||
}else{
|
},
|
||||||
return null;
|
],
|
||||||
}
|
})(<Input />)}
|
||||||
});
|
</Form.Item>
|
||||||
};
|
<Form.Item label="User List" style={{ display: 'block' }}>
|
||||||
|
{getFieldDecorator('users', {
|
||||||
onExpand = expandedKeys => {
|
initialValue: this.state.roleData.users,
|
||||||
this.setState({
|
})(
|
||||||
expandedKeys,
|
<Select
|
||||||
autoExpandParent: false,
|
mode="multiple"
|
||||||
});
|
style={{ width: '100%' }}
|
||||||
};
|
onSearch={this.loadUsersList}
|
||||||
|
>
|
||||||
onCheck = checkedKeys => {
|
{this.state.users}
|
||||||
this.setState({checkedKeys});
|
</Select>,
|
||||||
};
|
)}
|
||||||
|
</Form.Item>
|
||||||
renderTreeNodes = (data) => {
|
</Form>
|
||||||
return data.map(item => {
|
|
||||||
if (item !== null) {
|
|
||||||
if (item.hasOwnProperty("nodeList")) {
|
|
||||||
return (
|
|
||||||
<TreeNode title={item.displayName} key={item.resourcePath} dataRef={item}>
|
|
||||||
{this.renderTreeNodes(item.nodeList)}
|
|
||||||
</TreeNode>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <TreeNode key={item.resourcePath} {...item}/>;
|
|
||||||
} else{
|
|
||||||
return <TreeNode/>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onUpdateRole = e => {
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
this.onConfirmUpdateRole(values);
|
|
||||||
}
|
|
||||||
console.log(values);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onCancelHandler = e =>{
|
|
||||||
this.setState({
|
|
||||||
isEditRoleModalVisible: false,
|
|
||||||
isEditPermissionModalVisible:false,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmUpdateRole = (value) =>{
|
|
||||||
const roleData = {
|
|
||||||
roleName : value.roleName,
|
|
||||||
users : value.users,
|
|
||||||
};
|
|
||||||
axios.put(
|
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/roles/"+ this.props.data,
|
|
||||||
roleData,
|
|
||||||
{headers: {'Content-Type' : 'application-json'}}
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
this.setState({
|
|
||||||
isEditRoleModalVisible: false,
|
|
||||||
});
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully Updated the role.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to add role.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onAssignPermission = () =>{
|
|
||||||
const roleData = {
|
|
||||||
roleName : this.props.data,
|
|
||||||
permissions : this.state.checkedKeys
|
|
||||||
};
|
|
||||||
axios.put(
|
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/roles/"+ this.props.data,
|
|
||||||
roleData,
|
|
||||||
{headers: {'Content-Type' : 'application-json'}}
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully Updated the Permissions.",
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
isEditPermissionModalVisible : false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to add permissions.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
loadUsersList = (value) => {
|
|
||||||
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt + "/users/search/usernames?filter="+value+"&domain=Primary";
|
|
||||||
axios.get(apiURL).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let user = JSON.parse(res.data.data);
|
|
||||||
let users = [];
|
|
||||||
for(let i=0; i<user.length; i++){
|
|
||||||
users.push(<Option key={user[i].username}>{user[i].username}</Option>);
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
users : users
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load users.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
onDeleteRole = () => {
|
|
||||||
axios.delete(
|
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/roles/" + this.props.data,
|
|
||||||
{headers: {'Content-Type': 'application/json'}}
|
|
||||||
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully deleted the Role.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to delete role.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const isAdminRole = this.props.data ==="admin";
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div style={{display:isAdminRole ? "none" : "inline"}}>
|
|
||||||
<Tooltip placement="top" title={"Edit Role"}>
|
|
||||||
<a><Icon type="edit" onClick={this.openEditRoleModal}/></a>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="top" title={"Edit Permissions"}>
|
|
||||||
<a><Icon type="file-add" onClick={this.openEditPermissionModal}/></a>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="bottom" title={"Remove Role"}>
|
|
||||||
<Popconfirm
|
|
||||||
placement="top"
|
|
||||||
title={"Are you sure?"}
|
|
||||||
onConfirm={this.onDeleteRole}
|
|
||||||
okText="Ok"
|
|
||||||
cancelText="Cancel">
|
|
||||||
<a><Text type="danger"><Icon type="delete"/></Text></a>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="EDIT ROLE"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.isEditRoleModalVisible}
|
|
||||||
onOk={this.onUpdateRole}
|
|
||||||
onCancel={this.onCancelHandler}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.onUpdateRole}>
|
|
||||||
Add Role
|
|
||||||
</Button>,
|
|
||||||
]}>
|
|
||||||
<div style={{alignItems:"center"}}>
|
|
||||||
<p>Create new user on IoT Server.</p>
|
|
||||||
<Form
|
|
||||||
labelCol={{ span: 5 }}
|
|
||||||
wrapperCol={{ span: 18 }}>
|
|
||||||
<Form.Item label="User Store Domain" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('userStoreDomain', {
|
|
||||||
initialValue : 'PRIMARY'
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
<Option key="PRIMARY">PRIMARY</Option>
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Role Name" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('roleName', {
|
|
||||||
initialValue: this.state.roleData.roleName,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
pattern : new RegExp("^(((?!(\\@|\\/|\\s)).){3,})*$"),
|
|
||||||
message: 'Role name should be in minimum 3 characters long and not ' +
|
|
||||||
'include any whitespaces or @ or /',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required.',
|
|
||||||
},
|
|
||||||
|
|
||||||
],
|
|
||||||
})(<Input/>)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="User List" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('users', {
|
|
||||||
initialValue: this.state.roleData.users,
|
|
||||||
})(<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
onSearch={this.loadUsersList}>
|
|
||||||
{this.state.users}
|
|
||||||
</Select>)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="CHANGE ROLE PERMISSION"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.isEditPermissionModalVisible}
|
|
||||||
onOk={this.onAssignPermission}
|
|
||||||
onCancel={this.onCancelHandler}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.onAssignPermission}>
|
|
||||||
Assign
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
bodyStyle={{overflowY:"scroll", maxHeight:'500px', marginLeft:'10px'}}>
|
|
||||||
<div>
|
|
||||||
{(this.state.isNodeList) &&(
|
|
||||||
<Tree
|
|
||||||
checkable
|
|
||||||
onExpand={this.onExpand}
|
|
||||||
expandedKeys={this.state.expandedKeys}
|
|
||||||
autoExpandParent={this.state.autoExpandParent}
|
|
||||||
onCheck={this.onCheck}
|
|
||||||
checkedKeys={this.state.checkedKeys}>
|
|
||||||
{this.renderTreeNodes(this.state.nodeList)}
|
|
||||||
</Tree>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</Modal>
|
||||||
}
|
</div>
|
||||||
|
<div>
|
||||||
|
<Modal
|
||||||
|
title="CHANGE ROLE PERMISSION"
|
||||||
|
width="40%"
|
||||||
|
visible={this.state.isEditPermissionModalVisible}
|
||||||
|
onOk={this.onAssignPermission}
|
||||||
|
onCancel={this.onCancelHandler}
|
||||||
|
footer={[
|
||||||
|
<Button key="cancel" onClick={this.onCancelHandler}>
|
||||||
|
Cancel
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
key="submit"
|
||||||
|
type="primary"
|
||||||
|
onClick={this.onAssignPermission}
|
||||||
|
>
|
||||||
|
Assign
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
bodyStyle={{
|
||||||
|
overflowY: 'scroll',
|
||||||
|
maxHeight: '500px',
|
||||||
|
marginLeft: '10px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{this.state.isNodeList && (
|
||||||
|
<Tree
|
||||||
|
checkable
|
||||||
|
onExpand={this.onExpand}
|
||||||
|
expandedKeys={this.state.expandedKeys}
|
||||||
|
autoExpandParent={this.state.autoExpandParent}
|
||||||
|
onCheck={this.onCheck}
|
||||||
|
checkedKeys={this.state.checkedKeys}
|
||||||
|
>
|
||||||
|
{this.renderTreeNodes(this.state.nodeList)}
|
||||||
|
</Tree>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create({name: 'role-actions'})(RoleAction));
|
export default withConfigContext(
|
||||||
|
Form.create({ name: 'role-actions' })(RoleAction),
|
||||||
|
);
|
||||||
|
|||||||
@ -16,243 +16,251 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {
|
import { Button, message, Modal, notification, Table, List } from 'antd';
|
||||||
Button,
|
import TimeAgo from 'javascript-time-ago';
|
||||||
message,
|
|
||||||
Modal,
|
|
||||||
notification,
|
|
||||||
Table, List
|
|
||||||
} from "antd";
|
|
||||||
import TimeAgo from 'javascript-time-ago'
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
import AddRole from "./AddRole";
|
import AddRole from './AddRole';
|
||||||
import RoleAction from "./RoleAction";
|
import RoleAction from './RoleAction';
|
||||||
import Filter from "../Utils/Filter/Filter";
|
import Filter from '../Utils/Filter/Filter';
|
||||||
|
|
||||||
const searchFields = [
|
const searchFields = [
|
||||||
{
|
{
|
||||||
name: 'filter',
|
name: 'filter',
|
||||||
placeholder: 'Name'
|
placeholder: 'Name',
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
class RolesTable extends React.Component {
|
class RolesTable extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.config = this.props.context;
|
this.config = this.props.context;
|
||||||
TimeAgo.addLocale(en);
|
TimeAgo.addLocale(en);
|
||||||
this.state = {
|
this.state = {
|
||||||
data: [],
|
data: [],
|
||||||
pagination: {},
|
pagination: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: [],
|
selectedRows: [],
|
||||||
userData: [],
|
userData: [],
|
||||||
users : [],
|
users: [],
|
||||||
isEditRoleModalVisible: false,
|
isEditRoleModalVisible: false,
|
||||||
isUserListModalVisible :false,
|
isUserListModalVisible: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rowSelection = {
|
rowSelection = {
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedRows: selectedRows
|
selectedRows: selectedRows,
|
||||||
})
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
openUserListModal = event => {
|
||||||
|
let apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles/' +
|
||||||
|
event;
|
||||||
|
|
||||||
|
// send request to the invokerss
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.setState({
|
||||||
|
userData: res.data.data.users,
|
||||||
|
isUserListModalVisible: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load users.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleOk = e => {
|
||||||
|
this.setState({
|
||||||
|
isUserListModalVisible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCancel = e => {
|
||||||
|
this.setState({
|
||||||
|
isUserListModalVisible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetchUsers = (params = {}, filters = {}) => {
|
||||||
|
// const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
// get current page
|
||||||
|
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (currentPage - 1), // calculate the offset
|
||||||
|
limit: 10,
|
||||||
|
...filters,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
const encodedExtraParams = Object.keys(extraParams)
|
||||||
this.fetchUsers();
|
.map(key => key + '=' + extraParams[key])
|
||||||
}
|
.join('&');
|
||||||
|
|
||||||
openUserListModal = (event) => {
|
let apiUrl =
|
||||||
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
|
window.location.origin +
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
this.config.serverConfig.invoker.uri +
|
||||||
"/roles/"+ event;
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles?' +
|
||||||
|
encodedExtraParams;
|
||||||
|
|
||||||
//send request to the invokerss
|
// send request to the invokerss
|
||||||
axios.get(apiUrl).then(res => {
|
axios
|
||||||
if (res.status === 200) {
|
.get(apiUrl)
|
||||||
this.setState({
|
.then(res => {
|
||||||
userData : res.data.data.users,
|
if (res.status === 200) {
|
||||||
isUserListModalVisible: true,
|
const pagination = { ...this.state.pagination };
|
||||||
});
|
this.setState({
|
||||||
}
|
loading: false,
|
||||||
|
data: res.data.data.roles,
|
||||||
|
pagination,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load users.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}).catch((error) => {
|
this.setState({ loading: false });
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
});
|
||||||
//todo display a popop with error
|
};
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load users.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleOk = e => {
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
this.setState({
|
const pager = { ...this.state.pagination };
|
||||||
isUserListModalVisible: false,
|
pager.current = pagination.current;
|
||||||
});
|
this.setState({
|
||||||
};
|
pagination: pager,
|
||||||
|
});
|
||||||
|
this.fetch({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
handleCancel = e => {
|
render() {
|
||||||
this.setState({
|
const { data, pagination, loading } = this.state;
|
||||||
isUserListModalVisible: false,
|
const columns = [
|
||||||
});
|
{
|
||||||
};
|
title: 'Role Name',
|
||||||
|
dataIndex: '',
|
||||||
//fetch data from api
|
key: 'role',
|
||||||
fetchUsers = (params = {}, filters={}) => {
|
width: '60%',
|
||||||
// const config = this.props.context;
|
},
|
||||||
this.setState({loading: true});
|
{
|
||||||
|
title: 'View',
|
||||||
// get current page
|
dataIndex: '',
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
key: 'users',
|
||||||
|
render: (id, row) => (
|
||||||
const extraParams = {
|
<Button
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
type="primary"
|
||||||
limit: 10,
|
size={'small'}
|
||||||
...filters
|
icon="book"
|
||||||
};
|
onClick={() => this.openUserListModal(row)}
|
||||||
|
>
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
Users
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
</Button>
|
||||||
|
),
|
||||||
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
|
},
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
{
|
||||||
"/roles?" + encodedExtraParams;
|
title: 'Action',
|
||||||
|
dataIndex: 'id',
|
||||||
//send request to the invokerss
|
key: 'action',
|
||||||
axios.get(apiUrl).then(res => {
|
render: (id, row) => (
|
||||||
if (res.status === 200) {
|
<span>
|
||||||
const pagination = {...this.state.pagination};
|
<RoleAction data={row} fetchUsers={this.fetchUsers} />
|
||||||
this.setState({
|
</span>
|
||||||
loading: false,
|
),
|
||||||
data: res.data.data.roles,
|
},
|
||||||
pagination,
|
];
|
||||||
});
|
return (
|
||||||
}
|
<div>
|
||||||
|
<div style={{ background: '#f0f2f5' }}>
|
||||||
}).catch((error) => {
|
<AddRole fetchUsers={this.fetchUsers} />
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
</div>
|
||||||
//todo display a popop with error
|
<div style={{ textAlign: 'right' }}>
|
||||||
message.error('You are not logged in');
|
<Filter fields={searchFields} callback={this.fetchUsers} />
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
</div>
|
||||||
} else {
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
notification["error"]({
|
<Table
|
||||||
message: "There was a problem",
|
columns={columns}
|
||||||
duration: 0,
|
rowKey={record => record}
|
||||||
description:"Error occurred while trying to load users.",
|
dataSource={data}
|
||||||
});
|
pagination={{
|
||||||
}
|
...pagination,
|
||||||
|
size: 'small',
|
||||||
this.setState({loading: false});
|
// position: "top",
|
||||||
});
|
showTotal: (total, range) =>
|
||||||
};
|
`showing ${range[0]}-${range[1]} of ${total} groups`,
|
||||||
|
// showQuickJumper: true
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
}}
|
||||||
const pager = {...this.state.pagination};
|
loading={loading}
|
||||||
pager.current = pagination.current;
|
onChange={this.handleTableChange}
|
||||||
this.setState({
|
rowSelection={this.rowSelection}
|
||||||
pagination: pager,
|
/>
|
||||||
});
|
</div>
|
||||||
this.fetch({
|
<div>
|
||||||
results: pagination.pageSize,
|
<Modal
|
||||||
page: pagination.current,
|
title="USERS"
|
||||||
sortField: sorter.field,
|
width="900px"
|
||||||
sortOrder: sorter.order,
|
visible={this.state.isUserListModalVisible}
|
||||||
...filters,
|
onOk={this.handleOk}
|
||||||
});
|
onCancel={this.handleCancel}
|
||||||
};
|
>
|
||||||
|
|
||||||
render() {
|
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
title: 'Role Name',
|
|
||||||
dataIndex: '',
|
|
||||||
key: "role",
|
|
||||||
width: "60%",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'View',
|
|
||||||
dataIndex: '',
|
|
||||||
key: 'users',
|
|
||||||
render: (id, row) =>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size={"small"}
|
|
||||||
icon="book"
|
|
||||||
onClick={()=>this.openUserListModal(row)}>Users</Button>
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Action',
|
|
||||||
dataIndex: 'id',
|
|
||||||
key: 'action',
|
|
||||||
render: (id, row) => (
|
|
||||||
<span>
|
|
||||||
<RoleAction data={row} fetchUsers={this.fetchUsers}/>
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
];
|
|
||||||
return (
|
|
||||||
<div>
|
<div>
|
||||||
<div style={{background: '#f0f2f5'}}>
|
<List
|
||||||
<AddRole fetchUsers={this.fetchUsers}/>
|
size="small"
|
||||||
</div>
|
bordered
|
||||||
<div style={{textAlign: 'right'}}>
|
dataSource={this.state.userData}
|
||||||
<Filter fields={searchFields} callback={this.fetchUsers}/>
|
renderItem={item => <List.Item>{item}</List.Item>}
|
||||||
</div>
|
/>
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
rowKey={record => (record)}
|
|
||||||
dataSource={data}
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: "small",
|
|
||||||
// position: "top",
|
|
||||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
|
|
||||||
// showQuickJumper: true
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={this.rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="USERS"
|
|
||||||
width="900px"
|
|
||||||
visible={this.state.isUserListModalVisible}
|
|
||||||
onOk={this.handleOk}
|
|
||||||
onCancel={this.handleCancel} >
|
|
||||||
<div>
|
|
||||||
<List
|
|
||||||
size="small"
|
|
||||||
bordered
|
|
||||||
dataSource={this.state.userData}
|
|
||||||
renderItem={item => <List.Item>{item}</List.Item>}/>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</Modal>
|
||||||
);
|
</div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(RolesTable);
|
export default withConfigContext(RolesTable);
|
||||||
|
|||||||
@ -17,21 +17,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Route} from 'react-router-dom';
|
import { Route } from 'react-router-dom';
|
||||||
class RouteWithSubRoutes extends React.Component{
|
class RouteWithSubRoutes extends React.Component {
|
||||||
props;
|
props;
|
||||||
constructor(props){
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.props = props;
|
this.props = props;
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return(
|
return (
|
||||||
<Route path={this.props.path} exact={this.props.exact} render={(props) => (
|
<Route
|
||||||
<this.props.component {...props} {...this.props} routes={this.props.routes}/>
|
path={this.props.path}
|
||||||
)}/>
|
exact={this.props.exact}
|
||||||
);
|
render={props => (
|
||||||
}
|
<this.props.component
|
||||||
|
{...props}
|
||||||
|
{...this.props}
|
||||||
|
routes={this.props.routes}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RouteWithSubRoutes;
|
export default RouteWithSubRoutes;
|
||||||
|
|||||||
@ -1,215 +1,245 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Button, Form, Select, Input, message, Modal, notification, Typography} from "antd";
|
import {
|
||||||
import axios from "axios";
|
Button,
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
Form,
|
||||||
|
Select,
|
||||||
|
Input,
|
||||||
|
message,
|
||||||
|
Modal,
|
||||||
|
notification,
|
||||||
|
} from 'antd';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
class AddUser extends React.Component {
|
class AddUser extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.config = this.props.context;
|
||||||
|
this.state = {
|
||||||
|
isModalVisible: false,
|
||||||
|
roles: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
componentDidMount() {
|
||||||
super(props);
|
this.getRole();
|
||||||
this.config = this.props.context;
|
}
|
||||||
this.state = {
|
|
||||||
|
openAddModal = () => {
|
||||||
|
this.setState({
|
||||||
|
isModalVisible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onSubmitHandler = e => {
|
||||||
|
this.props.form.validateFields((err, values) => {
|
||||||
|
if (!err) {
|
||||||
|
this.onConfirmAddUser(values);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onConfirmAddUser = value => {
|
||||||
|
const userData = {
|
||||||
|
username: value.userStoreDomain + '/' + value.userName,
|
||||||
|
firstname: value.firstName,
|
||||||
|
lastname: value.lastName,
|
||||||
|
emailAddress: value.email,
|
||||||
|
roles: value.userRoles,
|
||||||
|
};
|
||||||
|
axios
|
||||||
|
.post(
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/users',
|
||||||
|
userData,
|
||||||
|
{ headers: { 'Content-Type': 'application-json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 201) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
this.setState({
|
||||||
isModalVisible: false,
|
isModalVisible: false,
|
||||||
roles : []
|
});
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully added the user.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to add user.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
onCancelHandler = e => {
|
||||||
this.getRole();
|
this.setState({
|
||||||
}
|
isModalVisible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
openAddModal = () => {
|
getRole = () => {
|
||||||
this.setState({
|
let apiURL =
|
||||||
isModalVisible:true
|
window.location.origin +
|
||||||
});
|
this.config.serverConfig.invoker.uri +
|
||||||
};
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles?user-store=PRIMARY&limit=100';
|
||||||
|
|
||||||
onSubmitHandler = e => {
|
axios
|
||||||
this.props.form.validateFields((err, values) => {
|
.get(apiURL)
|
||||||
if (!err) {
|
.then(res => {
|
||||||
this.onConfirmAddUser(values);
|
if (res.status === 200) {
|
||||||
}
|
const roles = [];
|
||||||
});
|
for (let i = 0; i < res.data.data.roles.length; i++) {
|
||||||
};
|
roles.push(
|
||||||
|
<Option key={res.data.data.roles[i]}>
|
||||||
|
{res.data.data.roles[i]}
|
||||||
|
</Option>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
roles: roles,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
|
||||||
onConfirmAddUser = (value) =>{
|
message.error('You are not logged in');
|
||||||
const userData = {
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
username : value.userStoreDomain +"/"+value.userName,
|
} else {
|
||||||
firstname : value.firstName,
|
notification.error({
|
||||||
lastname : value.lastName,
|
message: 'There was a problem',
|
||||||
emailAddress : value.email,
|
duration: 0,
|
||||||
roles : value.userRoles
|
description: 'Error occurred while trying to load roles.',
|
||||||
};
|
});
|
||||||
axios.post(
|
}
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
});
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
};
|
||||||
"/users",
|
|
||||||
userData,
|
|
||||||
{headers: {'Content-Type' : 'application-json'}}
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 201) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
this.setState({
|
|
||||||
isModalVisible: false,
|
|
||||||
});
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully added the user.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to add user.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onCancelHandler = e => {
|
render() {
|
||||||
this.setState({
|
const { getFieldDecorator } = this.props.form;
|
||||||
isModalVisible: false,
|
return (
|
||||||
});
|
<div>
|
||||||
};
|
<div>
|
||||||
|
<Button
|
||||||
getRole = () => {
|
type="primary"
|
||||||
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
|
icon="plus"
|
||||||
this.config.serverConfig.invoker.deviceMgt + "/roles?user-store=PRIMARY&limit=100";
|
size={'default'}
|
||||||
|
onClick={this.openAddModal}
|
||||||
axios.get(apiURL).then(res => {
|
style={{ marginBottom: '10px' }}
|
||||||
if (res.status === 200) {
|
>
|
||||||
const roles = [];
|
Add User
|
||||||
for(let i=0; i<res.data.data.roles.length ; i++){
|
</Button>
|
||||||
roles.push(<Option key={res.data.data.roles[i]}>{res.data.data.roles[i]}</Option>);
|
</div>
|
||||||
}
|
<div>
|
||||||
this.setState({
|
<Modal
|
||||||
roles : roles
|
title="ADD NEW USER"
|
||||||
})
|
width="40%"
|
||||||
}
|
visible={this.state.isModalVisible}
|
||||||
}).catch((error) => {
|
onOk={this.onSubmitHandler}
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
onCancel={this.onCancelHandler}
|
||||||
//todo display a popop with error
|
footer={[
|
||||||
|
<Button key="cancel" onClick={this.onCancelHandler}>
|
||||||
message.error('You are not logged in');
|
Cancel
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
</Button>,
|
||||||
} else {
|
<Button
|
||||||
notification["error"]({
|
key="submit"
|
||||||
message: "There was a problem",
|
type="primary"
|
||||||
duration: 0,
|
onClick={this.onSubmitHandler}
|
||||||
description:"Error occurred while trying to load roles.",
|
>
|
||||||
});
|
Submit
|
||||||
}
|
</Button>,
|
||||||
})
|
]}
|
||||||
};
|
>
|
||||||
|
<div style={{ alignItems: 'center' }}>
|
||||||
render() {
|
<p>Create new user on IoT Server.</p>
|
||||||
const { getFieldDecorator } = this.props.form;
|
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
||||||
return (
|
<Form.Item
|
||||||
<div>
|
label="User Store Domain"
|
||||||
<div>
|
style={{ display: 'block' }}
|
||||||
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal} style={{marginBottom : '10px'}}>
|
>
|
||||||
Add User
|
{getFieldDecorator('userStoreDomain', {
|
||||||
</Button>
|
initialValue: 'PRIMARY',
|
||||||
</div>
|
})(
|
||||||
<div>
|
<Select>
|
||||||
<Modal
|
<Option key="PRIMARY">PRIMARY</Option>
|
||||||
title="ADD NEW USER"
|
</Select>,
|
||||||
width="40%"
|
)}
|
||||||
visible={this.state.isModalVisible}
|
</Form.Item>
|
||||||
onOk={this.onSubmitHandler}
|
<Form.Item label="User Name" style={{ display: 'block' }}>
|
||||||
onCancel={this.onCancelHandler}
|
{getFieldDecorator('userName', {
|
||||||
footer={[
|
rules: [
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
{
|
||||||
Cancel
|
required: true,
|
||||||
</Button>,
|
message:
|
||||||
<Button key="submit" type="primary" onClick={this.onSubmitHandler}>
|
'This field is required. Username should be at least 3 characters long with no white spaces.',
|
||||||
Submit
|
},
|
||||||
</Button>,
|
],
|
||||||
]}>
|
})(<Input />)}
|
||||||
<div style={{alignItems:"center"}}>
|
</Form.Item>
|
||||||
<p>Create new user on IoT Server.</p>
|
<Form.Item label="First Name" style={{ display: 'block' }}>
|
||||||
<Form
|
{getFieldDecorator('firstName', {
|
||||||
labelCol={{ span: 5 }}
|
rules: [
|
||||||
wrapperCol={{ span: 18 }}>
|
{
|
||||||
<Form.Item label="User Store Domain" style={{display:"block"}}>
|
required: true,
|
||||||
{getFieldDecorator('userStoreDomain', {
|
message: 'This field is required',
|
||||||
initialValue : 'PRIMARY'
|
},
|
||||||
})(
|
],
|
||||||
<Select>
|
})(<Input />)}
|
||||||
<Option key="PRIMARY">PRIMARY</Option>
|
</Form.Item>
|
||||||
</Select>
|
<Form.Item label="Last Name" style={{ display: 'block' }}>
|
||||||
)}
|
{getFieldDecorator('lastName', {
|
||||||
</Form.Item>
|
rules: [
|
||||||
<Form.Item label="User Name" style={{display:"block"}}>
|
{
|
||||||
{getFieldDecorator('userName', {
|
required: true,
|
||||||
rules: [
|
message: 'This field is required',
|
||||||
{
|
},
|
||||||
required: true,
|
],
|
||||||
message: 'This field is required. Username should be at least 3 characters long with no white spaces.',
|
})(<Input />)}
|
||||||
},
|
</Form.Item>
|
||||||
],
|
<Form.Item label="Email Address" style={{ display: 'block' }}>
|
||||||
})(<Input/>)}
|
{getFieldDecorator('email', {
|
||||||
</Form.Item>
|
rules: [
|
||||||
<Form.Item label="First Name" style={{display:"block"}}>
|
{
|
||||||
{getFieldDecorator('firstName', {
|
type: 'email',
|
||||||
rules: [
|
message: 'Invalid Email Address',
|
||||||
{
|
},
|
||||||
required: true,
|
{
|
||||||
message: 'This field is required',
|
required: true,
|
||||||
},
|
message: 'This field is required',
|
||||||
],
|
},
|
||||||
})(<Input/>)}
|
],
|
||||||
</Form.Item>
|
})(<Input />)}
|
||||||
<Form.Item label="Last Name" style={{display:"block"}}>
|
</Form.Item>
|
||||||
{getFieldDecorator('lastName', {
|
<Form.Item label="User Roles" style={{ display: 'block' }}>
|
||||||
rules: [
|
{getFieldDecorator('userRoles', {})(
|
||||||
{
|
<Select mode="multiple" style={{ width: '100%' }}>
|
||||||
required: true,
|
{this.state.roles}
|
||||||
message: 'This field is required',
|
</Select>,
|
||||||
},
|
)}
|
||||||
],
|
</Form.Item>
|
||||||
})(<Input/>)}
|
</Form>
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Email Address" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('email', {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
type: 'email',
|
|
||||||
message: 'Invalid Email Address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input/>)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="User Roles" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('userRoles', {
|
|
||||||
})(<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}>
|
|
||||||
{this.state.roles}
|
|
||||||
</Select>)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</Modal>
|
||||||
}
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create({name: 'add-user'})(AddUser))
|
export default withConfigContext(Form.create({ name: 'add-user' })(AddUser));
|
||||||
|
|||||||
@ -1,423 +1,472 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Divider,
|
Divider,
|
||||||
Form,
|
Form,
|
||||||
Icon,
|
Icon,
|
||||||
Input,
|
Input,
|
||||||
message,
|
message,
|
||||||
Modal,
|
Modal,
|
||||||
notification,
|
notification,
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
Select,
|
Select,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography } from "antd";
|
Typography,
|
||||||
import axios from "axios";
|
} from 'antd';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import axios from 'axios';
|
||||||
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
const {Text} = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
class UserActions extends React.Component {
|
class UserActions extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.config = this.props.context;
|
this.config = this.props.context;
|
||||||
this.state = {
|
this.state = {
|
||||||
isEditModalVisible: false,
|
isEditModalVisible: false,
|
||||||
isResetPasswordModalVisible: false,
|
isResetPasswordModalVisible: false,
|
||||||
rolesData: [],
|
rolesData: [],
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
openEditModal = () => {
|
||||||
|
this.setState({
|
||||||
|
isEditModalVisible: true,
|
||||||
|
});
|
||||||
|
this.fetchRoles(this.props.data.username);
|
||||||
|
};
|
||||||
|
openPasswordResetModal = () => {
|
||||||
|
this.setState({
|
||||||
|
isResetPasswordModalVisible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onCancelHandler = () => {
|
||||||
|
this.setState({
|
||||||
|
isEditModalVisible: false,
|
||||||
|
isResetPasswordModalVisible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
compareToFirstPassword = (rule, value, callback) => {
|
||||||
|
if (value && value !== this.props.form.getFieldValue('password')) {
|
||||||
|
callback("New password doesn't match the confirmation.");
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
}
|
}
|
||||||
openEditModal = () =>{
|
};
|
||||||
this.setState({
|
|
||||||
isEditModalVisible: true,
|
|
||||||
});
|
|
||||||
this.fetchRoles(this.props.data.username);
|
|
||||||
|
|
||||||
};
|
onSavePassword = () => {
|
||||||
openPasswordResetModal = () =>{
|
this.props.form.validateFields(
|
||||||
this.setState({
|
['password', 'confirmPassword'],
|
||||||
isResetPasswordModalVisible: true,
|
(err, values) => {
|
||||||
})
|
if (!err) {
|
||||||
};
|
this.onResetPassword(values);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
onCancelHandler = () =>{
|
onResetPassword = value => {
|
||||||
this.setState({
|
const password = {
|
||||||
isEditModalVisible: false,
|
newPassword: value.password,
|
||||||
|
};
|
||||||
|
axios
|
||||||
|
.post(
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/admin/users/' +
|
||||||
|
this.props.data.username +
|
||||||
|
'/credentials',
|
||||||
|
password,
|
||||||
|
{ headers: { 'Content-Type': 'application-json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
this.setState({
|
||||||
isResetPasswordModalVisible: false,
|
isResetPasswordModalVisible: false,
|
||||||
})
|
});
|
||||||
};
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
compareToFirstPassword = (rule, value, callback) => {
|
duration: 4,
|
||||||
if (value && value !== this.props.form.getFieldValue('password')) {
|
description: 'Successfully reset the password',
|
||||||
callback('New password doesn\'t match the confirmation.');
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.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 {
|
} else {
|
||||||
callback();
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to reset password.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.getRole();
|
||||||
|
}
|
||||||
|
|
||||||
|
getRole = () => {
|
||||||
|
let apiURL =
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/roles?user-store=PRIMARY&limit=100';
|
||||||
|
|
||||||
|
axios
|
||||||
|
.get(apiURL)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const roles = [];
|
||||||
|
for (let i = 0; i < res.data.data.roles.length; i++) {
|
||||||
|
roles.push(
|
||||||
|
<Option key={res.data.data.roles[i]}>
|
||||||
|
{res.data.data.roles[i]}
|
||||||
|
</Option>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
roles: roles,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load roles.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onConfirmDeleteUser = () => {
|
||||||
|
axios
|
||||||
|
.delete(
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/users/' +
|
||||||
|
this.props.data.username,
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully deleted the user.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to delete user.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchRoles = username => {
|
||||||
|
let apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/users/' +
|
||||||
|
username +
|
||||||
|
'/roles';
|
||||||
|
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.setState({
|
||||||
|
rolesData: res.data.data.roles,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load roles.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleEditOk = e => {
|
||||||
|
this.props.form.validateFields(
|
||||||
|
[
|
||||||
|
'userStoreDomain',
|
||||||
|
'userName',
|
||||||
|
'firstName',
|
||||||
|
'lastName',
|
||||||
|
'email',
|
||||||
|
'userRoles',
|
||||||
|
],
|
||||||
|
(err, values) => {
|
||||||
|
if (!err) {
|
||||||
|
this.onUpdateUser(values);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
onUpdateUser = value => {
|
||||||
|
const userData = {
|
||||||
|
username: value.userStoreDomain + '/' + value.userName,
|
||||||
|
firstname: value.firstName,
|
||||||
|
lastname: value.lastName,
|
||||||
|
emailAddress: value.email,
|
||||||
|
roles: value.userRoles,
|
||||||
};
|
};
|
||||||
|
axios
|
||||||
|
.put(
|
||||||
|
window.location.origin +
|
||||||
|
this.config.serverConfig.invoker.uri +
|
||||||
|
this.config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/users/' +
|
||||||
|
this.props.data.username,
|
||||||
|
userData,
|
||||||
|
{ headers: { 'Content-Type': 'application-json' } },
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.props.fetchUsers();
|
||||||
|
this.setState({
|
||||||
|
isEditModalVisible: false,
|
||||||
|
});
|
||||||
|
notification.success({
|
||||||
|
message: 'Done',
|
||||||
|
duration: 4,
|
||||||
|
description: 'Successfully updated the user.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to update user.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onSavePassword = () => {
|
render() {
|
||||||
this.props.form.validateFields((['password', 'confirmPassword']),(err, values) => {
|
const isAdminUser = this.props.data.username === 'admin';
|
||||||
if (!err) {
|
const { getFieldDecorator } = this.props.form;
|
||||||
this.onResetPassword(values);
|
return (
|
||||||
}
|
<div>
|
||||||
});
|
<div style={{ display: isAdminUser ? 'none' : 'inline' }}>
|
||||||
};
|
<Tooltip placement="top" title={'Edit User'}>
|
||||||
|
<a>
|
||||||
|
<Icon type="edit" onClick={this.openEditModal} />
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
<Divider type="vertical" />
|
||||||
|
<Tooltip placement="top" title={'Reset Password'}>
|
||||||
|
<a>
|
||||||
|
<Icon type="key" onClick={this.openPasswordResetModal} />
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
<Divider type="vertical" />
|
||||||
|
<Tooltip placement="bottom" title={'Remove User'}>
|
||||||
|
<Popconfirm
|
||||||
|
placement="top"
|
||||||
|
title={'Are you sure?'}
|
||||||
|
onConfirm={this.onConfirmDeleteUser}
|
||||||
|
okText="Ok"
|
||||||
|
cancelText="Cancel"
|
||||||
|
>
|
||||||
|
<a>
|
||||||
|
<Text type="danger">
|
||||||
|
<Icon type="delete" />
|
||||||
|
</Text>
|
||||||
|
</a>
|
||||||
|
</Popconfirm>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
onResetPassword = (value) =>{
|
<div>
|
||||||
const password = {
|
<Modal
|
||||||
newPassword : value.password,
|
title="Reset Password"
|
||||||
};
|
width="40%"
|
||||||
axios.post(
|
visible={this.state.isResetPasswordModalVisible}
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
onCancel={this.onCancelHandler}
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
onOk={this.onSavePassword}
|
||||||
"/admin/users/"+this.props.data.username+"/credentials",
|
footer={[
|
||||||
password,
|
<Button key="cancel" onClick={this.onCancelHandler}>
|
||||||
{headers: {'Content-Type' : 'application-json'}}
|
Cancel
|
||||||
).then(res => {
|
</Button>,
|
||||||
if (res.status === 200) {
|
<Button key="submit" type="primary" onClick={this.onSavePassword}>
|
||||||
this.props.fetchUsers();
|
Save
|
||||||
this.setState({
|
</Button>,
|
||||||
isResetPasswordModalVisible: false,
|
]}
|
||||||
});
|
>
|
||||||
notification["success"]({
|
<div style={{ alignItems: 'center' }}>
|
||||||
message: "Done",
|
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 17 }}>
|
||||||
duration: 4,
|
<Form.Item label="New Password" style={{ display: 'block' }}>
|
||||||
description:
|
{getFieldDecorator('password', {
|
||||||
"Successfully reset the password",
|
rules: [
|
||||||
});
|
{
|
||||||
}
|
required: true,
|
||||||
}).catch((error) => {
|
message: 'This field is required',
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
},
|
||||||
//todo display a popop with error
|
],
|
||||||
message.error('You are not logged in');
|
})(<Input.Password />)}
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
</Form.Item>
|
||||||
} else {
|
<Form.Item
|
||||||
notification["error"]({
|
label="Retype New Password"
|
||||||
message: "There was a problem",
|
style={{ display: 'block' }}
|
||||||
duration: 0,
|
>
|
||||||
description:
|
{getFieldDecorator('confirmPassword', {
|
||||||
"Error occurred while trying to reset password.",
|
rules: [
|
||||||
});
|
{
|
||||||
}
|
required: true,
|
||||||
});
|
message: 'This field is required',
|
||||||
|
},
|
||||||
};
|
{
|
||||||
|
validator: this.compareToFirstPassword,
|
||||||
componentDidMount() {
|
},
|
||||||
this.getRole();
|
],
|
||||||
}
|
})(<Input.Password />)}
|
||||||
|
</Form.Item>
|
||||||
getRole = () => {
|
</Form>
|
||||||
let apiURL = window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt + "/roles?user-store=PRIMARY&limit=100";
|
|
||||||
|
|
||||||
axios.get(apiURL).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
const roles = [];
|
|
||||||
for(let i=0; i<res.data.data.roles.length ; i++){
|
|
||||||
roles.push(<Option key={res.data.data.roles[i]}>{res.data.data.roles[i]}</Option>);
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
roles : roles
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load roles.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmDeleteUser = () => {
|
|
||||||
axios.delete(
|
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/users/" + this.props.data.username,
|
|
||||||
{headers: {'Content-Type': 'application/json'}}
|
|
||||||
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully deleted the user.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to delete user.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchRoles = (username) => {
|
|
||||||
let apiUrl = window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/users/" + username + "/roles";
|
|
||||||
|
|
||||||
axios.get(apiUrl).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
rolesData: res.data.data.roles,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load roles.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleEditOk = e =>{
|
|
||||||
this.props.form.validateFields((['userStoreDomain', 'userName', 'firstName', 'lastName' , 'email', 'userRoles']),(err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
this.onUpdateUser(values);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onUpdateUser = (value) =>{
|
|
||||||
const userData = {
|
|
||||||
username : value.userStoreDomain +"/"+value.userName,
|
|
||||||
firstname : value.firstName,
|
|
||||||
lastname : value.lastName,
|
|
||||||
emailAddress : value.email,
|
|
||||||
roles : value.userRoles
|
|
||||||
};
|
|
||||||
axios.put(
|
|
||||||
window.location.origin + this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
"/users/"+ this.props.data.username,
|
|
||||||
userData,
|
|
||||||
{headers: {'Content-Type' : 'application-json'}}
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
this.setState({
|
|
||||||
isEditModalVisible: false,
|
|
||||||
});
|
|
||||||
notification["success"]({
|
|
||||||
message: "Done",
|
|
||||||
duration: 4,
|
|
||||||
description:
|
|
||||||
"Successfully updated the user.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
//todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to update user.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const isAdminUser = this.props.data.username ==="admin";
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div style={{display:isAdminUser ? "none" : "inline"}}>
|
|
||||||
<Tooltip placement="top" title={"Edit User"}>
|
|
||||||
<a><Icon type="edit" onClick={this.openEditModal}/></a>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="top" title={"Reset Password"}>
|
|
||||||
<a><Icon type="key" onClick={this.openPasswordResetModal}/></a>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="bottom" title={"Remove User"}>
|
|
||||||
<Popconfirm
|
|
||||||
placement="top"
|
|
||||||
title={"Are you sure?"}
|
|
||||||
onConfirm={this.onConfirmDeleteUser}
|
|
||||||
okText="Ok"
|
|
||||||
cancelText="Cancel">
|
|
||||||
<a><Text type="danger"><Icon type="delete"/></Text></a>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="Reset Password"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.isResetPasswordModalVisible}
|
|
||||||
onCancel={this.onCancelHandler}
|
|
||||||
onOk={this.onSavePassword}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.onSavePassword} >
|
|
||||||
Save
|
|
||||||
</Button>,
|
|
||||||
]}>
|
|
||||||
<div style={{alignItems:"center"}}>
|
|
||||||
<Form
|
|
||||||
labelCol={{ span: 6 }}
|
|
||||||
wrapperCol={{ span: 17 }}>
|
|
||||||
<Form.Item label="New Password" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator(
|
|
||||||
'password',
|
|
||||||
{
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input.Password/>)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Retype New Password" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator(
|
|
||||||
'confirmPassword',
|
|
||||||
{
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: this.compareToFirstPassword,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input.Password/>)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="EDIT USER"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.isEditModalVisible}
|
|
||||||
onOk={this.handleEditOk}
|
|
||||||
onCancel={this.onCancelHandler}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.handleEditOk}>
|
|
||||||
Update
|
|
||||||
</Button>,
|
|
||||||
]}>
|
|
||||||
<div style={{alignItems:"center"}}>
|
|
||||||
<p>Create new user on IoT Server.</p>
|
|
||||||
<Form
|
|
||||||
labelCol={{ span: 5 }}
|
|
||||||
wrapperCol={{ span: 18 }}>
|
|
||||||
<Form.Item label="User Store Domain" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('userStoreDomain', {
|
|
||||||
initialValue : 'PRIMARY'
|
|
||||||
})(
|
|
||||||
<Select disabled={true}>
|
|
||||||
<Option key="PRIMARY">PRIMARY</Option>
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="User Name" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('userName', {
|
|
||||||
initialValue: this.props.data.username,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required. Username should be at least 3 characters long with no white spaces.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input disabled={true}/>)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="First Name" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('firstName', {
|
|
||||||
initialValue: this.props.data.firstname,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input/>)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Last Name" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('lastName', {
|
|
||||||
initialValue: this.props.data.lastname,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input/>)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Email Address" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('email', {
|
|
||||||
initialValue: this.props.data.emailAddress,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
type: 'email',
|
|
||||||
message: 'Invalid Email Address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input/>)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="User Roles" style={{display:"block"}}>
|
|
||||||
{getFieldDecorator('userRoles', {
|
|
||||||
initialValue: this.state.rolesData,
|
|
||||||
})(<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}>
|
|
||||||
{this.state.roles}
|
|
||||||
</Select>)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</Modal>
|
||||||
}
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Modal
|
||||||
|
title="EDIT USER"
|
||||||
|
width="40%"
|
||||||
|
visible={this.state.isEditModalVisible}
|
||||||
|
onOk={this.handleEditOk}
|
||||||
|
onCancel={this.onCancelHandler}
|
||||||
|
footer={[
|
||||||
|
<Button key="cancel" onClick={this.onCancelHandler}>
|
||||||
|
Cancel
|
||||||
|
</Button>,
|
||||||
|
<Button key="submit" type="primary" onClick={this.handleEditOk}>
|
||||||
|
Update
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div style={{ alignItems: 'center' }}>
|
||||||
|
<p>Create new user on IoT Server.</p>
|
||||||
|
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
||||||
|
<Form.Item
|
||||||
|
label="User Store Domain"
|
||||||
|
style={{ display: 'block' }}
|
||||||
|
>
|
||||||
|
{getFieldDecorator('userStoreDomain', {
|
||||||
|
initialValue: 'PRIMARY',
|
||||||
|
})(
|
||||||
|
<Select disabled={true}>
|
||||||
|
<Option key="PRIMARY">PRIMARY</Option>
|
||||||
|
</Select>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="User Name" style={{ display: 'block' }}>
|
||||||
|
{getFieldDecorator('userName', {
|
||||||
|
initialValue: this.props.data.username,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message:
|
||||||
|
'This field is required. Username should be at least 3 characters long with no white spaces.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})(<Input disabled={true} />)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="First Name" style={{ display: 'block' }}>
|
||||||
|
{getFieldDecorator('firstName', {
|
||||||
|
initialValue: this.props.data.firstname,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'This field is required',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})(<Input />)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="Last Name" style={{ display: 'block' }}>
|
||||||
|
{getFieldDecorator('lastName', {
|
||||||
|
initialValue: this.props.data.lastname,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'This field is required',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})(<Input />)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="Email Address" style={{ display: 'block' }}>
|
||||||
|
{getFieldDecorator('email', {
|
||||||
|
initialValue: this.props.data.emailAddress,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
type: 'email',
|
||||||
|
message: 'Invalid Email Address',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'This field is required',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})(<Input />)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="User Roles" style={{ display: 'block' }}>
|
||||||
|
{getFieldDecorator('userRoles', {
|
||||||
|
initialValue: this.state.rolesData,
|
||||||
|
})(
|
||||||
|
<Select mode="multiple" style={{ width: '100%' }}>
|
||||||
|
{this.state.roles}
|
||||||
|
</Select>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Form.create({name: 'user-actions'})(UserActions));
|
export default withConfigContext(
|
||||||
|
Form.create({ name: 'user-actions' })(UserActions),
|
||||||
|
);
|
||||||
|
|||||||
@ -16,233 +16,245 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {Icon, message, notification, Table, Tag, Tooltip, Typography} from "antd";
|
import { Icon, message, notification, Table, Tag, Tooltip } from 'antd';
|
||||||
import TimeAgo from 'javascript-time-ago'
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
|
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
let config = null;
|
||||||
let apiUrl;
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: 'Device',
|
title: 'Device',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Type',
|
title: 'Type',
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
key: 'type',
|
key: 'type',
|
||||||
render: type => {
|
// eslint-disable-next-line react/display-name
|
||||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
render: type => {
|
||||||
let icon = defaultPlatformIcons.default.icon;
|
const defaultPlatformIcons = config.defaultPlatformIcons;
|
||||||
let color = defaultPlatformIcons.default.color;
|
let icon = defaultPlatformIcons.default.icon;
|
||||||
let theme = defaultPlatformIcons.default.theme;
|
let color = defaultPlatformIcons.default.color;
|
||||||
|
let theme = defaultPlatformIcons.default.theme;
|
||||||
|
|
||||||
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
||||||
icon = defaultPlatformIcons[type].icon;
|
icon = defaultPlatformIcons[type].icon;
|
||||||
color = defaultPlatformIcons[type].color;
|
color = defaultPlatformIcons[type].color;
|
||||||
theme = defaultPlatformIcons[type].theme;
|
theme = defaultPlatformIcons[type].theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span style={{fontSize: 20, color: color, textAlign: "center"}}>
|
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
|
||||||
<Icon type={icon} theme={theme}/>
|
<Icon type={icon} theme={theme} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Owner',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
{
|
||||||
key: 'owner',
|
title: 'Owner',
|
||||||
render: enrolmentInfo => enrolmentInfo.owner
|
dataIndex: 'enrolmentInfo',
|
||||||
// todo add filtering options
|
key: 'owner',
|
||||||
|
render: enrolmentInfo => enrolmentInfo.owner,
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ownership',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'ownership',
|
||||||
|
width: 100,
|
||||||
|
render: enrolmentInfo => enrolmentInfo.ownership,
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Status',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
width: 100,
|
||||||
|
key: 'status',
|
||||||
|
// eslint-disable-next-line react/display-name
|
||||||
|
render: enrolmentInfo => {
|
||||||
|
const status = enrolmentInfo.status.toLowerCase();
|
||||||
|
let color = '#f9ca24';
|
||||||
|
switch (status) {
|
||||||
|
case 'active':
|
||||||
|
color = '#badc58';
|
||||||
|
break;
|
||||||
|
case 'created':
|
||||||
|
color = '#6ab04c';
|
||||||
|
break;
|
||||||
|
case 'removed':
|
||||||
|
color = '#ff7979';
|
||||||
|
break;
|
||||||
|
case 'inactive':
|
||||||
|
color = '#f9ca24';
|
||||||
|
break;
|
||||||
|
case 'blocked':
|
||||||
|
color = '#636e72';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return <Tag color={color}>{status}</Tag>;
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Ownership',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
{
|
||||||
key: 'ownership',
|
title: 'Last Updated',
|
||||||
width: 100,
|
dataIndex: 'enrolmentInfo',
|
||||||
render: enrolmentInfo => enrolmentInfo.ownership
|
key: 'dateOfLastUpdate',
|
||||||
// todo add filtering options
|
// 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>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
{
|
// todo add filtering options
|
||||||
title: 'Status',
|
},
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
width: 100,
|
|
||||||
key: 'status',
|
|
||||||
render: (enrolmentInfo) => {
|
|
||||||
const status = enrolmentInfo.status.toLowerCase();
|
|
||||||
let color = "#f9ca24";
|
|
||||||
switch (status) {
|
|
||||||
case "active":
|
|
||||||
color = "#badc58";
|
|
||||||
break;
|
|
||||||
case "created":
|
|
||||||
color = "#6ab04c";
|
|
||||||
break;
|
|
||||||
case "removed":
|
|
||||||
color = "#ff7979";
|
|
||||||
break;
|
|
||||||
case "inactive":
|
|
||||||
color = "#f9ca24";
|
|
||||||
break;
|
|
||||||
case "blocked":
|
|
||||||
color = "#636e72";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return <Tag color={color}>{status}</Tag>;
|
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Last Updated',
|
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'dateOfLastUpdate',
|
|
||||||
render: (data) => {
|
|
||||||
const {dateOfLastUpdate} = data;
|
|
||||||
const timeAgoString = getTimeAgo(dateOfLastUpdate);
|
|
||||||
return <Tooltip title={new Date(dateOfLastUpdate).toString()}>{timeAgoString}</Tooltip>;
|
|
||||||
}
|
|
||||||
// todo add filtering options
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const getTimeAgo = (time) => {
|
const getTimeAgo = time => {
|
||||||
const timeAgo = new TimeAgo('en-US');
|
const timeAgo = new TimeAgo('en-US');
|
||||||
return timeAgo.format(time);
|
return timeAgo.format(time);
|
||||||
};
|
};
|
||||||
|
|
||||||
class UsersDevices extends React.Component {
|
class UsersDevices extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
config = this.props.context;
|
||||||
TimeAgo.addLocale(en);
|
TimeAgo.addLocale(en);
|
||||||
this.state = {
|
this.state = {
|
||||||
data: [],
|
data: [],
|
||||||
pagination: {},
|
pagination: {},
|
||||||
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rowSelection = {
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
this.setState({
|
||||||
|
selectedRows: selectedRows,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rerender component when parameters change
|
||||||
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||||
|
if (prevProps.user !== this.props.user) {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
// get current page
|
||||||
|
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (currentPage - 1), // calculate the offset
|
||||||
|
limit: 10,
|
||||||
|
user: this.props.user,
|
||||||
|
requireDeviceInfo: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const encodedExtraParams = Object.keys(extraParams)
|
||||||
|
.map(key => key + '=' + extraParams[key])
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
// send request to the invoker
|
||||||
|
axios
|
||||||
|
.get(
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/devices?' +
|
||||||
|
encodedExtraParams,
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: []
|
data: res.data.data.devices,
|
||||||
};
|
pagination,
|
||||||
}
|
});
|
||||||
|
|
||||||
rowSelection = {
|
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
|
||||||
this.setState({
|
|
||||||
selectedRows: selectedRows
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
.catch(error => {
|
||||||
componentDidMount() {
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
this.fetch();
|
// todo display a popop with error
|
||||||
}
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
//Rerender component when parameters change
|
} else {
|
||||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
notification.error({
|
||||||
if(prevProps.user !== this.props.user){
|
message: 'There was a problem',
|
||||||
this.fetch();
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load devices.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//fetch data from api
|
this.setState({ loading: false });
|
||||||
fetch = (params = {}) => {
|
});
|
||||||
const config = this.props.context;
|
};
|
||||||
this.setState({loading: true});
|
|
||||||
// get current page
|
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
|
||||||
|
|
||||||
const extraParams = {
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
const pager = { ...this.state.pagination };
|
||||||
limit: 10,
|
pager.current = pagination.current;
|
||||||
user: this.props.user,
|
this.setState({
|
||||||
requireDeviceInfo: true,
|
pagination: pager,
|
||||||
};
|
});
|
||||||
|
this.fetch({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
render() {
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
const { data, pagination, loading } = this.state;
|
||||||
|
return (
|
||||||
//send request to the invoker
|
<div>
|
||||||
axios.get(
|
<Table
|
||||||
window.location.origin + config.serverConfig.invoker.uri +
|
columns={columns}
|
||||||
config.serverConfig.invoker.deviceMgt +
|
rowKey={record =>
|
||||||
"/devices?" + encodedExtraParams,
|
record.deviceIdentifier +
|
||||||
).then(res => {
|
record.enrolmentInfo.owner +
|
||||||
if (res.status === 200) {
|
record.enrolmentInfo.ownership
|
||||||
const pagination = {...this.state.pagination};
|
}
|
||||||
this.setState({
|
dataSource={data}
|
||||||
loading: false,
|
showHeader={false}
|
||||||
data: res.data.data.devices,
|
size="small"
|
||||||
pagination
|
pagination={{
|
||||||
});
|
...pagination,
|
||||||
}
|
size: 'small',
|
||||||
|
// position: "top",
|
||||||
}).catch((error) => {
|
showTotal: (total, range) =>
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
`showing ${range[0]}-${range[1]} of ${total} devices`,
|
||||||
//todo display a popop with error
|
// showQuickJumper: true
|
||||||
message.error('You are not logged in');
|
}}
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
loading={loading}
|
||||||
} else {
|
onChange={this.handleTableChange}
|
||||||
notification["error"]({
|
rowSelection={this.rowSelection}
|
||||||
message: "There was a problem",
|
/>
|
||||||
duration: 0,
|
</div>
|
||||||
description:
|
);
|
||||||
"Error occurred while trying to load devices.",
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = {...this.state.pagination};
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetch({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
|
|
||||||
dataSource={data}
|
|
||||||
showHeader={false}
|
|
||||||
size="small"
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: "small",
|
|
||||||
// position: "top",
|
|
||||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
|
|
||||||
// showQuickJumper: true
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={this.rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(UsersDevices);
|
export default withConfigContext(UsersDevices);
|
||||||
|
|||||||
@ -16,305 +16,322 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import {Button, Collapse, Icon, List, message, Modal, notification, Table, Tabs, Typography} from "antd";
|
import { Button, List, message, Modal, notification, Table } from 'antd';
|
||||||
import TimeAgo from 'javascript-time-ago'
|
import TimeAgo from 'javascript-time-ago';
|
||||||
// Load locale-specific relative date/time formatting rules.
|
// Load locale-specific relative date/time formatting rules.
|
||||||
import en from 'javascript-time-ago/locale/en'
|
import en from 'javascript-time-ago/locale/en';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
import UsersDevices from "./UsersDevices";
|
import UsersDevices from './UsersDevices';
|
||||||
import AddUser from "./AddUser";
|
import AddUser from './AddUser';
|
||||||
import UserActions from "./UserActions";
|
import UserActions from './UserActions';
|
||||||
import Filter from "../Utils/Filter/Filter";
|
import Filter from '../Utils/Filter/Filter';
|
||||||
const ButtonGroup = Button.Group;
|
const ButtonGroup = Button.Group;
|
||||||
const {Text} = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
let apiUrl;
|
let apiUrl;
|
||||||
|
|
||||||
const searchFields = [
|
const searchFields = [
|
||||||
{
|
{
|
||||||
name: 'username',
|
name: 'username',
|
||||||
placeholder: 'Username'
|
placeholder: 'Username',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'firstName',
|
name: 'firstName',
|
||||||
placeholder: 'First Name'
|
placeholder: 'First Name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'lastName',
|
name: 'lastName',
|
||||||
placeholder: 'Last Name'
|
placeholder: 'Last Name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'emailAddress',
|
name: 'emailAddress',
|
||||||
placeholder: 'Email Address'
|
placeholder: 'Email Address',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
class UsersTable extends React.Component {
|
class UsersTable extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
config = this.props.context;
|
TimeAgo.addLocale(en);
|
||||||
TimeAgo.addLocale(en);
|
this.state = {
|
||||||
this.state = {
|
data: [],
|
||||||
data: [],
|
pagination: {},
|
||||||
pagination: {},
|
loading: false,
|
||||||
|
selectedRows: [],
|
||||||
|
rolesModalVisible: false,
|
||||||
|
devicesModalVisible: false,
|
||||||
|
rolesData: [],
|
||||||
|
user: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rowSelection = {
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
this.setState({
|
||||||
|
selectedRows: selectedRows,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch data from api
|
||||||
|
fetchUsers = (params = {}, filters = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({ loading: true });
|
||||||
|
|
||||||
|
// get current page
|
||||||
|
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (currentPage - 1), // calculate the offset
|
||||||
|
limit: 10,
|
||||||
|
...filters,
|
||||||
|
};
|
||||||
|
|
||||||
|
const encodedExtraParams = Object.keys(extraParams)
|
||||||
|
.map(key => key + '=' + extraParams[key])
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
apiUrl =
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/users/search?' +
|
||||||
|
encodedExtraParams;
|
||||||
|
|
||||||
|
// send request to the invokerss
|
||||||
|
axios
|
||||||
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = { ...this.state.pagination };
|
||||||
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
selectedRows: [],
|
data: res.data.data.users,
|
||||||
rolesModalVisible: false,
|
pagination,
|
||||||
devicesModalVisible: false,
|
});
|
||||||
rolesData: [],
|
|
||||||
user:''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
rowSelection = {
|
console.log(res.data.data);
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
}
|
||||||
this.setState({
|
})
|
||||||
selectedRows: selectedRows
|
.catch(error => {
|
||||||
})
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load users.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
this.setState({ loading: false });
|
||||||
this.fetchUsers();
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
//fetch data from api
|
fetchRoles = username => {
|
||||||
fetchUsers = (params = {}, filters = {}) => {
|
const config = this.props.context;
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({loading: true});
|
|
||||||
|
|
||||||
// get current page
|
this.setState({
|
||||||
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
rolesModalVisible: true,
|
||||||
|
user: username,
|
||||||
|
});
|
||||||
|
|
||||||
const extraParams = {
|
apiUrl =
|
||||||
offset: 10 * (currentPage - 1), //calculate the offset
|
window.location.origin +
|
||||||
limit: 10,
|
config.serverConfig.invoker.uri +
|
||||||
...filters
|
config.serverConfig.invoker.deviceMgt +
|
||||||
};
|
'/users/' +
|
||||||
|
username +
|
||||||
|
'/roles';
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
axios
|
||||||
.map(key => key + '=' + extraParams[key]).join('&');
|
.get(apiUrl)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.setState({
|
||||||
|
rolesData: res.data.data.roles,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
// todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/entgra/login';
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to load roles.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
this.setState({ loading: false });
|
||||||
config.serverConfig.invoker.deviceMgt +
|
});
|
||||||
"/users/search?" + encodedExtraParams;
|
};
|
||||||
|
|
||||||
//send request to the invokerss
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
axios.get(apiUrl).then(res => {
|
const pager = { ...this.state.pagination };
|
||||||
if (res.status === 200) {
|
pager.current = pagination.current;
|
||||||
const pagination = {...this.state.pagination};
|
this.setState({
|
||||||
this.setState({
|
pagination: pager,
|
||||||
loading: false,
|
});
|
||||||
data: res.data.data.users,
|
this.fetch({
|
||||||
pagination,
|
results: pagination.pageSize,
|
||||||
});
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
console.log(res.data.data)
|
handleOk = e => {
|
||||||
}
|
this.setState({
|
||||||
|
rolesModalVisible: false,
|
||||||
|
devicesModalVisible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}).catch((error) => {
|
handleCancel = e => {
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
this.setState({
|
||||||
//todo display a popop with error
|
rolesModalVisible: false,
|
||||||
message.error('You are not logged in');
|
devicesModalVisible: false,
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
});
|
||||||
} else {
|
};
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:"Error occurred while trying to load users.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({loading: false});
|
openDeviceListModal = e => {
|
||||||
});
|
this.setState({
|
||||||
};
|
devicesModalVisible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
fetchRoles = (username) => {
|
render() {
|
||||||
const config = this.props.context;
|
const { data, pagination, loading } = this.state;
|
||||||
|
const columns = [
|
||||||
this.setState({
|
{
|
||||||
rolesModalVisible: true,
|
title: 'User Name',
|
||||||
user: username
|
dataIndex: 'username',
|
||||||
});
|
key: 'username',
|
||||||
|
},
|
||||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
{
|
||||||
config.serverConfig.invoker.deviceMgt +
|
title: 'First Name',
|
||||||
"/users/" + username + "/roles";
|
dataIndex: 'firstname',
|
||||||
|
key: 'firstname',
|
||||||
axios.get(apiUrl).then(res => {
|
},
|
||||||
if (res.status === 200) {
|
{
|
||||||
this.setState({
|
title: 'Last Name',
|
||||||
rolesData: res.data.data.roles,
|
dataIndex: 'lastname',
|
||||||
});
|
key: 'lastname',
|
||||||
}
|
},
|
||||||
|
{
|
||||||
}).catch((error) => {
|
title: 'Email',
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
dataIndex: 'emailAddress',
|
||||||
//todo display a popop with error
|
key: 'emailAddress',
|
||||||
message.error('You are not logged in');
|
},
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
{
|
||||||
} else {
|
title: 'View',
|
||||||
notification["error"]({
|
dataIndex: 'username',
|
||||||
message: "There was a problem",
|
key: 'roles',
|
||||||
duration: 0,
|
render: username => (
|
||||||
description:"Error occurred while trying to load roles.",
|
<ButtonGroup>
|
||||||
});
|
<Button
|
||||||
}
|
type="primary"
|
||||||
|
size={'small'}
|
||||||
this.setState({loading: false});
|
icon="book"
|
||||||
});
|
onClick={() => this.fetchRoles(username)}
|
||||||
};
|
>
|
||||||
|
Roles
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
</Button>
|
||||||
const pager = {...this.state.pagination};
|
<Button
|
||||||
pager.current = pagination.current;
|
type="primary"
|
||||||
this.setState({
|
size={'small'}
|
||||||
pagination: pager,
|
icon="desktop"
|
||||||
});
|
onClick={this.openDeviceListModal}
|
||||||
this.fetch({
|
>
|
||||||
results: pagination.pageSize,
|
Devices
|
||||||
page: pagination.current,
|
</Button>
|
||||||
sortField: sorter.field,
|
</ButtonGroup>
|
||||||
sortOrder: sorter.order,
|
),
|
||||||
...filters,
|
},
|
||||||
});
|
{
|
||||||
};
|
title: 'Action',
|
||||||
|
dataIndex: 'id',
|
||||||
handleOk = e => {
|
key: 'action',
|
||||||
this.setState({
|
render: (id, row) => (
|
||||||
rolesModalVisible: false,
|
<span>
|
||||||
devicesModalVisible: false
|
<UserActions data={row} fetchUsers={this.fetchUsers} />
|
||||||
});
|
</span>
|
||||||
};
|
),
|
||||||
|
},
|
||||||
handleCancel = e => {
|
];
|
||||||
this.setState({
|
return (
|
||||||
rolesModalVisible: false,
|
<div>
|
||||||
devicesModalVisible: false
|
<div style={{ background: '#f0f2f5' }}>
|
||||||
});
|
<AddUser fetchUsers={this.fetchUsers} />
|
||||||
};
|
</div>
|
||||||
|
<div style={{ textAlign: 'right' }}>
|
||||||
openDeviceListModal = e =>{
|
<Filter fields={searchFields} callback={this.fetchUsers} />
|
||||||
this.setState({
|
</div>
|
||||||
devicesModalVisible: true,
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
})
|
<Table
|
||||||
};
|
columns={columns}
|
||||||
|
rowKey={record => record.username}
|
||||||
render() {
|
dataSource={data}
|
||||||
const {data, pagination, loading, selectedRows} = this.state;
|
pagination={{
|
||||||
const { Panel } = Collapse;
|
...pagination,
|
||||||
const { TabPane } = Tabs;
|
size: 'small',
|
||||||
const columns = [
|
// position: "top",
|
||||||
{
|
showTotal: (total, range) =>
|
||||||
title: 'User Name',
|
`showing ${range[0]}-${range[1]} of ${total} groups`,
|
||||||
dataIndex: 'username',
|
// showQuickJumper: true
|
||||||
key: "username",
|
}}
|
||||||
},
|
loading={loading}
|
||||||
{
|
onChange={this.handleTableChange}
|
||||||
title: 'First Name',
|
rowSelection={this.rowSelection}
|
||||||
dataIndex: 'firstname',
|
/>
|
||||||
key: 'firstname',
|
</div>
|
||||||
},
|
<div>
|
||||||
{
|
<Modal
|
||||||
title: 'Last Name',
|
title="ROLES"
|
||||||
dataIndex: 'lastname',
|
width="900px"
|
||||||
key: 'lastname',
|
visible={this.state.rolesModalVisible}
|
||||||
},
|
onOk={this.handleOk}
|
||||||
{
|
onCancel={this.handleCancel}
|
||||||
title: 'Email',
|
>
|
||||||
dataIndex: 'emailAddress',
|
|
||||||
key: 'emailAddress',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'View',
|
|
||||||
dataIndex: 'username',
|
|
||||||
key: 'roles',
|
|
||||||
render: (username) =>
|
|
||||||
<ButtonGroup>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size={"small"}
|
|
||||||
icon="book"
|
|
||||||
onClick={() => this.fetchRoles(username)}>Roles</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size={"small"}
|
|
||||||
icon="desktop"
|
|
||||||
onClick={this.openDeviceListModal}>Devices</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Action',
|
|
||||||
dataIndex: 'id',
|
|
||||||
key: 'action',
|
|
||||||
render: (id, row) => (
|
|
||||||
<span>
|
|
||||||
<UserActions data={row} fetchUsers={this.fetchUsers}/>
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
];
|
|
||||||
return (
|
|
||||||
<div>
|
<div>
|
||||||
<div style={{background: '#f0f2f5'}}>
|
<List
|
||||||
<AddUser fetchUsers={this.fetchUsers}/>
|
size="small"
|
||||||
</div>
|
bordered
|
||||||
<div style={{textAlign: 'right'}}>
|
dataSource={this.state.rolesData}
|
||||||
<Filter fields={searchFields} callback={this.fetchUsers}/>
|
renderItem={item => <List.Item>{item}</List.Item>}
|
||||||
</div>
|
/>
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
rowKey={record => (record.username)}
|
|
||||||
dataSource={data}
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: "small",
|
|
||||||
// position: "top",
|
|
||||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
|
|
||||||
// showQuickJumper: true
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={this.rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="ROLES"
|
|
||||||
width="900px"
|
|
||||||
visible={this.state.rolesModalVisible}
|
|
||||||
onOk={this.handleOk}
|
|
||||||
onCancel={this.handleCancel} >
|
|
||||||
<div>
|
|
||||||
<List
|
|
||||||
size="small"
|
|
||||||
bordered
|
|
||||||
dataSource={this.state.rolesData}
|
|
||||||
renderItem={item => <List.Item>{item}</List.Item>}/>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="DEVICES"
|
|
||||||
width="900px"
|
|
||||||
visible={this.state.devicesModalVisible}
|
|
||||||
onOk={this.handleOk}
|
|
||||||
onCancel={this.handleCancel}>
|
|
||||||
<div>
|
|
||||||
<UsersDevices user={this.state.user}/>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</Modal>
|
||||||
}
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Modal
|
||||||
|
title="DEVICES"
|
||||||
|
width="900px"
|
||||||
|
visible={this.state.devicesModalVisible}
|
||||||
|
onOk={this.handleOk}
|
||||||
|
onCancel={this.handleCancel}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<UsersDevices user={this.state.user} />
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(UsersTable);
|
export default withConfigContext(UsersTable);
|
||||||
|
|||||||
@ -1,41 +1,38 @@
|
|||||||
import React from "react";
|
import React from 'react';
|
||||||
|
|
||||||
import {Form, Icon, Input, Button} from 'antd';
|
import { Form, Input, Button } from 'antd';
|
||||||
|
|
||||||
const hasErrors = (fieldsError) => {
|
|
||||||
return Object.keys(fieldsError).some(field => fieldsError[field]);
|
|
||||||
};
|
|
||||||
|
|
||||||
class HorizontalLoginForm extends React.Component {
|
class HorizontalLoginForm extends React.Component {
|
||||||
handleSubmit = e => {
|
handleSubmit = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.form.validateFields((err, values) => {
|
this.props.form.validateFields((err, values) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
Object.keys(values).forEach(key => values[key] === undefined && delete values[key]);
|
Object.keys(values).forEach(
|
||||||
this.props.callback({},values);
|
key => values[key] === undefined && delete values[key],
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {getFieldDecorator} = this.props.form;
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form layout="inline" onSubmit={this.handleSubmit}>
|
|
||||||
{this.props.fields.map((field) => (
|
|
||||||
<Form.Item key={field.name}>
|
|
||||||
{getFieldDecorator(field.name)(
|
|
||||||
<Input placeholder={field.placeholder}/>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
))}
|
|
||||||
<Form.Item>
|
|
||||||
<Button htmlType='submit' shape="circle" icon="search" />
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
);
|
);
|
||||||
}
|
this.props.callback({}, values);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { getFieldDecorator } = this.props.form;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form layout="inline" onSubmit={this.handleSubmit}>
|
||||||
|
{this.props.fields.map(field => (
|
||||||
|
<Form.Item key={field.name}>
|
||||||
|
{getFieldDecorator(field.name)(
|
||||||
|
<Input placeholder={field.placeholder} />,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
))}
|
||||||
|
<Form.Item>
|
||||||
|
<Button htmlType="submit" shape="circle" icon="search" />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Form.create({name: 'horizontal_login'})(HorizontalLoginForm);
|
export default Form.create({ name: 'horizontal_login' })(HorizontalLoginForm);
|
||||||
|
|||||||
@ -16,19 +16,19 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
|
|
||||||
const ConfigContext = React.createContext();
|
const ConfigContext = React.createContext();
|
||||||
|
|
||||||
export const withConfigContext = Component => {
|
export const withConfigContext = Component => {
|
||||||
return props => (
|
// eslint-disable-next-line react/display-name
|
||||||
<ConfigContext.Consumer>
|
return props => (
|
||||||
{context => {
|
<ConfigContext.Consumer>
|
||||||
return <Component {...props} context={context}/>;
|
{context => {
|
||||||
}}
|
return <Component {...props} context={context} />;
|
||||||
</ConfigContext.Consumer>
|
}}
|
||||||
);
|
</ConfigContext.Consumer>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ConfigContext;
|
export default ConfigContext;
|
||||||
|
|
||||||
|
|||||||
@ -19,119 +19,117 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import * as serviceWorker from './serviceWorker';
|
import * as serviceWorker from './serviceWorker';
|
||||||
import App from "./App";
|
import App from './App';
|
||||||
import Login from "./pages/Login";
|
import Login from './pages/Login';
|
||||||
import Dashboard from "./pages/Dashboard/Dashboard";
|
import Dashboard from './pages/Dashboard/Dashboard';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import Devices from "./pages/Dashboard/Devices/Devices";
|
import Devices from './pages/Dashboard/Devices/Devices';
|
||||||
import Reports from "./pages/Dashboard/Reports/Reports";
|
import Reports from './pages/Dashboard/Reports/Reports';
|
||||||
import Geo from "./pages/Dashboard/Geo/Geo";
|
import Geo from './pages/Dashboard/Geo/Geo';
|
||||||
import Groups from "./pages/Dashboard/Groups/Groups";
|
import Groups from './pages/Dashboard/Groups/Groups';
|
||||||
import Users from "./pages/Dashboard/Users/Users";
|
import Users from './pages/Dashboard/Users/Users';
|
||||||
import Policies from "./pages/Dashboard/Policies/Policies";
|
import Policies from './pages/Dashboard/Policies/Policies';
|
||||||
import Roles from "./pages/Dashboard/Roles/Roles";
|
import Roles from './pages/Dashboard/Roles/Roles';
|
||||||
import DeviceTypes from "./pages/Dashboard/DeviceTypes/DeviceTypes";
|
import DeviceTypes from './pages/Dashboard/DeviceTypes/DeviceTypes';
|
||||||
import DeviceEnroll from "./pages/Dashboard/Devices/DeviceEnroll";
|
import DeviceEnroll from './pages/Dashboard/Devices/DeviceEnroll';
|
||||||
import AddNewPolicy from "./pages/Dashboard/Policies/AddNewPolicy";
|
import AddNewPolicy from './pages/Dashboard/Policies/AddNewPolicy';
|
||||||
import Certificates from "./pages/Dashboard/Configurations/Certificates/Certificates";
|
import Certificates from './pages/Dashboard/Configurations/Certificates/Certificates';
|
||||||
import ReportDurationItemList from "./pages/Dashboard/Reports/ReportDurationItemList";
|
import ReportDurationItemList from './pages/Dashboard/Reports/ReportDurationItemList';
|
||||||
import EnrollmentsVsUnenrollmentsReport from "./components/Reports/Templates/EnrollmentsVsUnenrollmentsReport";
|
import EnrollmentsVsUnenrollmentsReport from './components/Reports/Templates/EnrollmentsVsUnenrollmentsReport';
|
||||||
import EnrollmentTypeReport from "./components/Reports/Templates/EnrollmentTypeReport";
|
import EnrollmentTypeReport from './components/Reports/Templates/EnrollmentTypeReport';
|
||||||
|
import DeviceStatusReport from './components/Reports/Templates/DeviceStatusReport';
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/entgra/login',
|
path: '/entgra/login',
|
||||||
|
exact: true,
|
||||||
|
component: Login,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/entgra',
|
||||||
|
exact: false,
|
||||||
|
component: Dashboard,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/entgra/devices',
|
||||||
|
component: Devices,
|
||||||
exact: true,
|
exact: true,
|
||||||
component: Login
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/devices/enroll',
|
||||||
path: '/entgra',
|
component: DeviceEnroll,
|
||||||
exact: false,
|
exact: true,
|
||||||
component: Dashboard,
|
},
|
||||||
routes: [
|
{
|
||||||
{
|
path: '/entgra/geo',
|
||||||
path: '/entgra/devices',
|
component: Geo,
|
||||||
component: Devices,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/reports',
|
||||||
path: '/entgra/devices/enroll',
|
component: Reports,
|
||||||
component: DeviceEnroll,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/groups',
|
||||||
path: '/entgra/geo',
|
component: Groups,
|
||||||
component: Geo,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/users',
|
||||||
path: '/entgra/reports',
|
component: Users,
|
||||||
component: Reports,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/policies',
|
||||||
path: '/entgra/groups',
|
component: Policies,
|
||||||
component: Groups,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/policy/add',
|
||||||
path: '/entgra/users',
|
component: AddNewPolicy,
|
||||||
component: Users,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/roles',
|
||||||
path: '/entgra/policies',
|
component: Roles,
|
||||||
component: Policies,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/devicetypes',
|
||||||
path: '/entgra/policy/add',
|
component: DeviceTypes,
|
||||||
component: AddNewPolicy,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/certificates',
|
||||||
path: '/entgra/roles',
|
component: Certificates,
|
||||||
component: Roles,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/reportList',
|
||||||
path: '/entgra/devicetypes',
|
component: ReportDurationItemList,
|
||||||
component: DeviceTypes,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/enrollmentsvsunenrollments',
|
||||||
path: '/entgra/certificates',
|
component: EnrollmentsVsUnenrollmentsReport,
|
||||||
component: Certificates,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/enrollmenttype',
|
||||||
path: '/entgra/reportList',
|
component: EnrollmentTypeReport,
|
||||||
component: ReportDurationItemList,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
{
|
||||||
{
|
path: '/entgra/devicestatus',
|
||||||
path: '/entgra/enrollmentsvsunenrollments',
|
component: DeviceStatusReport,
|
||||||
component: EnrollmentsVsUnenrollmentsReport,
|
exact: true,
|
||||||
exact: true
|
},
|
||||||
},
|
],
|
||||||
{
|
},
|
||||||
path: '/entgra/enrollmenttype',
|
|
||||||
component: EnrollmentTypeReport,
|
|
||||||
exact: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/devicestatus',
|
|
||||||
component: DeviceStatusReport,
|
|
||||||
exact: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
ReactDOM.render(<App routes={routes} />, document.getElementById('root'));
|
||||||
ReactDOM.render(
|
|
||||||
<App routes={routes}/>,
|
|
||||||
document.getElementById('root'));
|
|
||||||
|
|
||||||
// If you want your app e and load faster, you can change
|
// If you want your app e and load faster, you can change
|
||||||
// unregister() to register() below. Note this comes with some pitfalls.
|
// unregister() to register() below. Note this comes with some pitfalls.
|
||||||
|
|||||||
@ -16,52 +16,48 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import CertificateTable from '../../../../components/Configurations/Certificates/CertificateTable';
|
||||||
Breadcrumb,
|
|
||||||
Icon,
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import DeviceTable from "../../../../components/Devices/DevicesTable";
|
|
||||||
import CertificateTable from "../../../../components/Configurations/Certificates/CertificateTable";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class Certificates extends React.Component {
|
class Certificates extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
|
<Link to="/entgra/devices">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item>Configurations</Breadcrumb.Item>
|
</Link>
|
||||||
<Breadcrumb.Item>Certificates</Breadcrumb.Item>
|
</Breadcrumb.Item>
|
||||||
</Breadcrumb>
|
<Breadcrumb.Item>Configurations</Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Breadcrumb.Item>Certificates</Breadcrumb.Item>
|
||||||
<h3>Certificates</h3>
|
</Breadcrumb>
|
||||||
<Paragraph>Certificate configurations</Paragraph>
|
<div className="wrap">
|
||||||
</div>
|
<h3>Certificates</h3>
|
||||||
<div style={{backgroundColor: "#ffffff", borderRadius: 5}}>
|
<Paragraph>Certificate configurations</Paragraph>
|
||||||
<CertificateTable/>
|
</div>
|
||||||
</div>
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
</PageHeader>
|
<CertificateTable />
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
</div>
|
||||||
|
</PageHeader>
|
||||||
</div>
|
<div
|
||||||
</div>
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
);
|
></div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Certificates;
|
export default Certificates;
|
||||||
|
|||||||
@ -16,193 +16,197 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {Layout, Menu, Icon} from 'antd';
|
import { Layout, Menu, Icon } from 'antd';
|
||||||
import {Switch, Link} from "react-router-dom";
|
import { Switch, Link } from 'react-router-dom';
|
||||||
import RouteWithSubRoutes from "../../components/RouteWithSubRoutes"
|
import RouteWithSubRoutes from '../../components/RouteWithSubRoutes';
|
||||||
import {Redirect} from 'react-router'
|
import { Redirect } from 'react-router';
|
||||||
import "./Dashboard.css";
|
import './Dashboard.css';
|
||||||
import {withConfigContext} from "../../context/ConfigContext";
|
import { withConfigContext } from '../../context/ConfigContext';
|
||||||
import Logout from "./Logout/Logout";
|
import Logout from './Logout/Logout';
|
||||||
|
|
||||||
const {Header, Content, Footer, Sider} = Layout;
|
const { Header, Content, Footer } = Layout;
|
||||||
const {SubMenu} = Menu;
|
const { SubMenu } = Menu;
|
||||||
|
|
||||||
class Dashboard extends React.Component {
|
class Dashboard extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const mobileWidth = (window.innerWidth<=768 ? '0' : '80');
|
const mobileWidth = window.innerWidth <= 768 ? '0' : '80';
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
routes: props.routes,
|
routes: props.routes,
|
||||||
selectedKeys: [],
|
selectedKeys: [],
|
||||||
deviceTypes: [],
|
deviceTypes: [],
|
||||||
isNavBarCollapsed: false,
|
isNavBarCollapsed: false,
|
||||||
mobileWidth
|
mobileWidth,
|
||||||
};
|
|
||||||
this.logo = this.props.context.theme.logo;
|
|
||||||
this.config = this.props.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle = () => {
|
|
||||||
console.log(this.config)
|
|
||||||
this.setState({
|
|
||||||
isNavBarCollapsed: !this.state.isNavBarCollapsed,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
this.logo = this.props.context.theme.logo;
|
||||||
|
this.config = this.props.context;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
toggle = () => {
|
||||||
return (
|
console.log(this.config);
|
||||||
<div>
|
this.setState({
|
||||||
<Layout className="layout" >
|
isNavBarCollapsed: !this.state.isNavBarCollapsed,
|
||||||
<Layout>
|
});
|
||||||
<Header style={{background: '#fff', padding: 0}}>
|
};
|
||||||
<div className="logo-image">
|
|
||||||
<Link to="/entgra/devices"><img alt="logo" src={this.logo}/></Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Menu
|
render() {
|
||||||
theme="light"
|
return (
|
||||||
mode="horizontal"
|
<div>
|
||||||
style={{
|
<Layout className="layout">
|
||||||
lineHeight: '64px',
|
<Layout>
|
||||||
marginRight: 110
|
<Header style={{ background: '#fff', padding: 0 }}>
|
||||||
}}
|
<div className="logo-image">
|
||||||
>
|
<Link to="/entgra/devices">
|
||||||
<SubMenu
|
<img alt="logo" src={this.logo} />
|
||||||
key="devices"
|
</Link>
|
||||||
title={
|
</div>
|
||||||
<span>
|
|
||||||
<Icon type="appstore"/>
|
|
||||||
<span>Devices</span>
|
|
||||||
</span>}
|
|
||||||
>
|
|
||||||
<Menu.Item key="devices">
|
|
||||||
<Link to="/entgra/devices">
|
|
||||||
<span>View</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="deviceEnroll">
|
|
||||||
<Link to="/entgra/devices/enroll">
|
|
||||||
<span>Enroll</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</SubMenu>
|
|
||||||
<SubMenu
|
|
||||||
key="geo"
|
|
||||||
title={
|
|
||||||
<span>
|
|
||||||
<Icon type="environment"/>
|
|
||||||
<span>Geo</span>
|
|
||||||
</span>}
|
|
||||||
>
|
|
||||||
<Menu.Item key="singleDevice">
|
|
||||||
<Link to="/entgra/geo">
|
|
||||||
<span>Single Device View</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="deviceGroup">
|
|
||||||
<Link to="#">
|
|
||||||
<span>Device Group View</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</SubMenu>
|
|
||||||
<Menu.Item key="reports">
|
|
||||||
<Link to="/entgra/reports">
|
|
||||||
<Icon type="bar-chart"/>
|
|
||||||
<span>Reports</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="groups">
|
|
||||||
<Link to="/entgra/groups">
|
|
||||||
<Icon type="deployment-unit"/>
|
|
||||||
<span>Groups</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="users">
|
|
||||||
<Link to="/entgra/users">
|
|
||||||
<Icon type="user"/>
|
|
||||||
<span>Users</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<SubMenu
|
|
||||||
key="policies"
|
|
||||||
title={
|
|
||||||
<span>
|
|
||||||
<Icon type="audit"/>
|
|
||||||
<span>Policies</span>
|
|
||||||
</span>}
|
|
||||||
>
|
|
||||||
<Menu.Item key="policiesList">
|
|
||||||
<Link to="/entgra/policies">
|
|
||||||
<span>View</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="addPolicy">
|
|
||||||
<Link to="/entgra/policy/add">
|
|
||||||
<span>Add New Policy</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</SubMenu>
|
|
||||||
<Menu.Item key="roles">
|
|
||||||
<Link to="/entgra/roles">
|
|
||||||
<Icon type="book"/>
|
|
||||||
<span>Roles</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="devicetypes">
|
|
||||||
<Link to="/entgra/devicetypes">
|
|
||||||
<Icon type="desktop"/>
|
|
||||||
<span>Device Types</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<SubMenu
|
|
||||||
key="configurations"
|
|
||||||
title={
|
|
||||||
<span>
|
|
||||||
<Icon type="setting"/>
|
|
||||||
<span>Configurations</span>
|
|
||||||
</span>}
|
|
||||||
>
|
|
||||||
<Menu.Item key="certificates">
|
|
||||||
<Link to="/entgra/certificates">
|
|
||||||
<span>Certificates</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</SubMenu>
|
|
||||||
<Menu.Item key="trigger">
|
|
||||||
</Menu.Item>
|
|
||||||
<SubMenu className="profile"
|
|
||||||
title={
|
|
||||||
<span className="submenu-title-wrapper">
|
|
||||||
<Icon type="user"/>
|
|
||||||
{this.config.user}
|
|
||||||
</span> }>
|
|
||||||
<Logout/>
|
|
||||||
</SubMenu>
|
|
||||||
|
|
||||||
</Menu>
|
<Menu
|
||||||
</Header>
|
theme="light"
|
||||||
|
mode="horizontal"
|
||||||
|
style={{
|
||||||
|
lineHeight: '64px',
|
||||||
|
marginRight: 110,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SubMenu
|
||||||
|
key="devices"
|
||||||
|
title={
|
||||||
|
<span>
|
||||||
|
<Icon type="appstore" />
|
||||||
|
<span>Devices</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item key="devices">
|
||||||
|
<Link to="/entgra/devices">
|
||||||
|
<span>View</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="deviceEnroll">
|
||||||
|
<Link to="/entgra/devices/enroll">
|
||||||
|
<span>Enroll</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</SubMenu>
|
||||||
|
<SubMenu
|
||||||
|
key="geo"
|
||||||
|
title={
|
||||||
|
<span>
|
||||||
|
<Icon type="environment" />
|
||||||
|
<span>Geo</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item key="singleDevice">
|
||||||
|
<Link to="/entgra/geo">
|
||||||
|
<span>Single Device View</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="deviceGroup">
|
||||||
|
<Link to="#">
|
||||||
|
<span>Device Group View</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</SubMenu>
|
||||||
|
<Menu.Item key="reports">
|
||||||
|
<Link to="/entgra/reports">
|
||||||
|
<Icon type="bar-chart" />
|
||||||
|
<span>Reports</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="groups">
|
||||||
|
<Link to="/entgra/groups">
|
||||||
|
<Icon type="deployment-unit" />
|
||||||
|
<span>Groups</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="users">
|
||||||
|
<Link to="/entgra/users">
|
||||||
|
<Icon type="user" />
|
||||||
|
<span>Users</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<SubMenu
|
||||||
|
key="policies"
|
||||||
|
title={
|
||||||
|
<span>
|
||||||
|
<Icon type="audit" />
|
||||||
|
<span>Policies</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item key="policiesList">
|
||||||
|
<Link to="/entgra/policies">
|
||||||
|
<span>View</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="addPolicy">
|
||||||
|
<Link to="/entgra/policy/add">
|
||||||
|
<span>Add New Policy</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</SubMenu>
|
||||||
|
<Menu.Item key="roles">
|
||||||
|
<Link to="/entgra/roles">
|
||||||
|
<Icon type="book" />
|
||||||
|
<span>Roles</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="devicetypes">
|
||||||
|
<Link to="/entgra/devicetypes">
|
||||||
|
<Icon type="desktop" />
|
||||||
|
<span>Device Types</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<SubMenu
|
||||||
|
key="configurations"
|
||||||
|
title={
|
||||||
|
<span>
|
||||||
|
<Icon type="setting" />
|
||||||
|
<span>Configurations</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item key="certificates">
|
||||||
|
<Link to="/entgra/certificates">
|
||||||
|
<span>Certificates</span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</SubMenu>
|
||||||
|
<Menu.Item key="trigger"></Menu.Item>
|
||||||
|
<SubMenu
|
||||||
|
className="profile"
|
||||||
|
title={
|
||||||
|
<span className="submenu-title-wrapper">
|
||||||
|
<Icon type="user" />
|
||||||
|
{this.config.user}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Logout />
|
||||||
|
</SubMenu>
|
||||||
|
</Menu>
|
||||||
|
</Header>
|
||||||
|
|
||||||
<Content style={{marginTop: 10}}>
|
<Content style={{ marginTop: 10 }}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Redirect exact from="/entgra" to="/entgra/devices"/>
|
<Redirect exact from="/entgra" to="/entgra/devices" />
|
||||||
{this.state.routes.map((route) => (
|
{this.state.routes.map(route => (
|
||||||
<RouteWithSubRoutes key={route.path} {...route} />
|
<RouteWithSubRoutes key={route.path} {...route} />
|
||||||
))}
|
))}
|
||||||
</Switch>
|
</Switch>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
<Footer style={{textAlign: 'center'}}>
|
<Footer style={{ textAlign: 'center' }}>©2019 entgra.io</Footer>
|
||||||
©2019 entgra.io
|
</Layout>
|
||||||
</Footer>
|
</Layout>
|
||||||
|
</div>
|
||||||
</Layout>
|
);
|
||||||
</Layout>
|
}
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Dashboard);
|
export default withConfigContext(Dashboard);
|
||||||
|
|||||||
@ -16,50 +16,47 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import DeviceTypesTable from '../../../components/DeviceTypes/DeviceTypesTable';
|
||||||
Breadcrumb,
|
|
||||||
Icon
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import DeviceTypesTable from "../../../components/DeviceTypes/DeviceTypesTable";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class DeviceTypes extends React.Component {
|
class DeviceTypes extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
<Link to="/entgra">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item>Device Types</Breadcrumb.Item>
|
</Link>
|
||||||
</Breadcrumb>
|
</Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Breadcrumb.Item>Device Types</Breadcrumb.Item>
|
||||||
<h3>Device Types</h3>
|
</Breadcrumb>
|
||||||
<Paragraph>All device types for device management.</Paragraph>
|
<div className="wrap">
|
||||||
</div>
|
<h3>Device Types</h3>
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
<Paragraph>All device types for device management.</Paragraph>
|
||||||
<DeviceTypesTable/>
|
</div>
|
||||||
</div>
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
</PageHeader>
|
<DeviceTypesTable />
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
</div>
|
||||||
|
</PageHeader>
|
||||||
</div>
|
<div
|
||||||
</div>
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
);
|
></div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DeviceTypes;
|
export default DeviceTypes;
|
||||||
|
|||||||
@ -1,50 +1,47 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import AddDevice from '../../../components/Devices/AddDevice';
|
||||||
Breadcrumb,
|
|
||||||
Icon,
|
|
||||||
Button, Select
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import AddDevice from "../../../components/Devices/AddDevice";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class DeviceEnroll extends React.Component {
|
class DeviceEnroll extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
|
<Link to="/entgra/devices">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item><Link to="/entgra/devices">Devices</Link></Breadcrumb.Item>
|
</Link>
|
||||||
<Breadcrumb.Item>Enroll Device</Breadcrumb.Item>
|
</Breadcrumb.Item>
|
||||||
</Breadcrumb>
|
<Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Link to="/entgra/devices">Devices</Link>
|
||||||
<h3>Devices</h3>
|
</Breadcrumb.Item>
|
||||||
<Paragraph>All enrolled devices</Paragraph>
|
<Breadcrumb.Item>Enroll Device</Breadcrumb.Item>
|
||||||
</div>
|
</Breadcrumb>
|
||||||
<div style={{borderRadius: 5}}>
|
<div className="wrap">
|
||||||
<AddDevice/>
|
<h3>Devices</h3>
|
||||||
</div>
|
<Paragraph>All enrolled devices</Paragraph>
|
||||||
</PageHeader>
|
</div>
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
<div style={{ borderRadius: 5 }}>
|
||||||
|
<AddDevice />
|
||||||
</div>
|
</div>
|
||||||
|
</PageHeader>
|
||||||
</div>
|
<div
|
||||||
);
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
}
|
></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DeviceEnroll;
|
export default DeviceEnroll;
|
||||||
|
|||||||
@ -16,51 +16,47 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import DeviceTable from '../../../components/Devices/DevicesTable';
|
||||||
Breadcrumb,
|
|
||||||
Icon,
|
|
||||||
Button, Select
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import DeviceTable from "../../../components/Devices/DevicesTable";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class Devices extends React.Component {
|
class Devices extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
|
<Link to="/entgra/devices">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item>Devices</Breadcrumb.Item>
|
</Link>
|
||||||
</Breadcrumb>
|
</Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Breadcrumb.Item>Devices</Breadcrumb.Item>
|
||||||
<h3>Devices</h3>
|
</Breadcrumb>
|
||||||
<Paragraph>All enrolled devices</Paragraph>
|
<div className="wrap">
|
||||||
</div>
|
<h3>Devices</h3>
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
<Paragraph>All enrolled devices</Paragraph>
|
||||||
<DeviceTable/>
|
</div>
|
||||||
</div>
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
</PageHeader>
|
<DeviceTable />
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
</div>
|
||||||
|
</PageHeader>
|
||||||
</div>
|
<div
|
||||||
</div>
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
);
|
></div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Devices;
|
export default Devices;
|
||||||
|
|||||||
@ -16,49 +16,51 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import GeoDashboard from '../../../components/Geo/geo-dashboard/GeoDashboard';
|
||||||
Breadcrumb,
|
|
||||||
Icon,
|
|
||||||
Card
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import GeoDashboard from "../../../components/Geo/geo-dashboard/GeoDashboard";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class Geo extends React.Component {
|
class Geo extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
render() {
|
||||||
|
return (
|
||||||
render() {
|
<div>
|
||||||
return (
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<div>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<Breadcrumb.Item>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Link to="/entgra">
|
||||||
<Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
</Link>
|
||||||
</Breadcrumb.Item>
|
</Breadcrumb.Item>
|
||||||
<Breadcrumb.Item>Geo</Breadcrumb.Item>
|
<Breadcrumb.Item>Geo</Breadcrumb.Item>
|
||||||
</Breadcrumb>
|
</Breadcrumb>
|
||||||
<div className="wrap">
|
<div className="wrap">
|
||||||
<h3>Geo</h3>
|
<h3>Geo</h3>
|
||||||
<Paragraph>Geo Location Service</Paragraph>
|
<Paragraph>Geo Location Service</Paragraph>
|
||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720, alignItems: "center"}}>
|
<div
|
||||||
<GeoDashboard/>
|
style={{
|
||||||
</div>
|
background: '#f0f2f5',
|
||||||
</div>
|
padding: 24,
|
||||||
);
|
minHeight: 720,
|
||||||
}
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<GeoDashboard />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Geo;
|
export default Geo;
|
||||||
|
|||||||
@ -16,47 +16,44 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import GroupsTable from '../../../components/Groups/GroupsTable';
|
||||||
Breadcrumb,
|
|
||||||
Icon
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import GroupsTable from "../../../components/Groups/GroupsTable";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class Groups extends React.Component {
|
class Groups extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
<Link to="/entgra">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item>Groups</Breadcrumb.Item>
|
</Link>
|
||||||
</Breadcrumb>
|
</Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Breadcrumb.Item>Groups</Breadcrumb.Item>
|
||||||
<h3>Groups</h3>
|
</Breadcrumb>
|
||||||
<Paragraph>All device groups.</Paragraph>
|
<div className="wrap">
|
||||||
</div>
|
<h3>Groups</h3>
|
||||||
</PageHeader>
|
<Paragraph>All device groups.</Paragraph>
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
</div>
|
||||||
<GroupsTable/>
|
</PageHeader>
|
||||||
</div>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
||||||
</div>
|
<GroupsTable />
|
||||||
);
|
</div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Groups;
|
export default Groups;
|
||||||
|
|||||||
@ -16,65 +16,66 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {notification, Menu, Icon} from 'antd';
|
import { notification, Menu, Icon } from 'antd';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import {withConfigContext} from "../../../context/ConfigContext";
|
import { withConfigContext } from '../../../context/ConfigContext';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This class for call the logout api by sending request
|
This class for call the logout api by sending request
|
||||||
*/
|
*/
|
||||||
class Logout extends React.Component {
|
class Logout extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
constructor(props) {
|
super(props);
|
||||||
super(props);
|
this.state = {
|
||||||
this.state = {
|
inValid: false,
|
||||||
inValid: false,
|
loading: false,
|
||||||
loading: false
|
};
|
||||||
};
|
}
|
||||||
}
|
/*
|
||||||
/*
|
|
||||||
This function call the logout api when the request is success
|
This function call the logout api when the request is success
|
||||||
*/
|
*/
|
||||||
handleSubmit = () => {
|
handleSubmit = () => {
|
||||||
|
const thisForm = this;
|
||||||
|
const config = this.props.context;
|
||||||
|
|
||||||
const thisForm = this;
|
thisForm.setState({
|
||||||
const config = this.props.context;
|
inValid: false,
|
||||||
|
});
|
||||||
|
|
||||||
thisForm.setState({
|
axios
|
||||||
inValid: false
|
.post(window.location.origin + config.serverConfig.logoutUri)
|
||||||
});
|
.then(res => {
|
||||||
|
// if the api call status is correct then user will logout and then it goes to login page
|
||||||
|
if (res.status === 200) {
|
||||||
|
window.location = window.location.origin + '/entgra/login';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 400) {
|
||||||
|
thisForm.setState({
|
||||||
|
inValid: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: 'There was a problem',
|
||||||
|
duration: 0,
|
||||||
|
description: 'Error occurred while trying to logout.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
axios.post(window.location.origin + config.serverConfig.logoutUri
|
render() {
|
||||||
).then(res => {
|
return (
|
||||||
//if the api call status is correct then user will logout and then it goes to login page
|
<Menu>
|
||||||
if (res.status === 200) {
|
<Menu.Item key="1" onClick={this.handleSubmit}>
|
||||||
window.location = window.location.origin + "/entgra/login";
|
<Icon type="logout" />
|
||||||
}
|
Logout
|
||||||
}).catch(function (error) {
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 400) {
|
);
|
||||||
thisForm.setState({
|
}
|
||||||
inValid: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
notification["error"]({
|
|
||||||
message: "There was a problem",
|
|
||||||
duration: 0,
|
|
||||||
description:
|
|
||||||
"Error occurred while trying to logout.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item key="1" onClick={this.handleSubmit}><Icon type="logout"/>Logout</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withConfigContext(Logout);
|
export default withConfigContext(Logout);
|
||||||
|
|||||||
@ -16,50 +16,47 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import AddPolicy from '../../../components/Policies/AddPolicy';
|
||||||
Breadcrumb,
|
|
||||||
Icon
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import AddPolicy from "../../../components/Policies/AddPolicy";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class AddNewPolicy extends React.Component {
|
class AddNewPolicy extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
<Link to="/entgra">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item>Policies</Breadcrumb.Item>
|
</Link>
|
||||||
</Breadcrumb>
|
</Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Breadcrumb.Item>Policies</Breadcrumb.Item>
|
||||||
<h3>Policies</h3>
|
</Breadcrumb>
|
||||||
<Paragraph>Create new policy on IoT Server.</Paragraph>
|
<div className="wrap">
|
||||||
</div>
|
<h3>Policies</h3>
|
||||||
<div style={{ borderRadius: 5}}>
|
<Paragraph>Create new policy on IoT Server.</Paragraph>
|
||||||
<AddPolicy/>
|
</div>
|
||||||
</div>
|
<div style={{ borderRadius: 5 }}>
|
||||||
</PageHeader>
|
<AddPolicy />
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
</div>
|
||||||
|
</PageHeader>
|
||||||
</div>
|
<div
|
||||||
</div>
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
);
|
></div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AddNewPolicy;
|
export default AddNewPolicy;
|
||||||
|
|||||||
@ -16,50 +16,47 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import PoliciesTable from '../../../components/Policies/PoliciesTable';
|
||||||
Breadcrumb,
|
|
||||||
Icon
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import PoliciesTable from "../../../components/Policies/PoliciesTable";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class Policies extends React.Component {
|
class Policies extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
<Link to="/entgra">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item>Policies</Breadcrumb.Item>
|
</Link>
|
||||||
</Breadcrumb>
|
</Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Breadcrumb.Item>Policies</Breadcrumb.Item>
|
||||||
<h3>Policies</h3>
|
</Breadcrumb>
|
||||||
<Paragraph>All policies for device management</Paragraph>
|
<div className="wrap">
|
||||||
</div>
|
<h3>Policies</h3>
|
||||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
<Paragraph>All policies for device management</Paragraph>
|
||||||
<PoliciesTable/>
|
</div>
|
||||||
</div>
|
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||||
</PageHeader>
|
<PoliciesTable />
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
</div>
|
||||||
|
</PageHeader>
|
||||||
</div>
|
<div
|
||||||
</div>
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
);
|
></div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Policies;
|
export default Policies;
|
||||||
|
|||||||
@ -16,137 +16,181 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { Icon, Col, Row, Card } from 'antd';
|
||||||
Icon,
|
|
||||||
Col,
|
|
||||||
Row, Select,
|
|
||||||
Radio, Card,
|
|
||||||
Button
|
|
||||||
} from "antd";
|
|
||||||
|
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from 'react-router-dom';
|
||||||
import moment from "moment";
|
import moment from 'moment';
|
||||||
|
|
||||||
|
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
class ReportDurationItemList extends React.Component {
|
class ReportDurationItemList extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
reportParams: ['ACTIVE', 'INACTIVE', 'REMOVED'],
|
||||||
|
enrollmentsVsUnenrollmentsParams: ['Enrollments', 'Unenrollments'],
|
||||||
|
enrollmentTypeParams: ['BYOD', 'COPE'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
durationItemArray = [
|
||||||
super(props);
|
{
|
||||||
this.state = {
|
name: 'Daily Report',
|
||||||
reportParams:["ACTIVE","INACTIVE","REMOVED"],
|
description: 'Enrollments of today',
|
||||||
enrollmentsVsUnenrollmentsParams:["Enrollments", "Unenrollments"],
|
duration: [
|
||||||
enrollmentTypeParams:["BYOD", "COPE"]
|
moment().format('YYYY-MM-DD'),
|
||||||
}
|
moment()
|
||||||
}
|
.add(1, 'days')
|
||||||
|
.format('YYYY-MM-DD'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Weekly Report',
|
||||||
|
description: 'Enrollments of last 7 days',
|
||||||
|
duration: [
|
||||||
|
moment()
|
||||||
|
.subtract(6, 'days')
|
||||||
|
.format('YYYY-MM-DD'),
|
||||||
|
moment()
|
||||||
|
.add(1, 'days')
|
||||||
|
.format('YYYY-MM-DD'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Monthly Report',
|
||||||
|
description: 'Enrollments of last month',
|
||||||
|
duration: [
|
||||||
|
moment()
|
||||||
|
.subtract(29, 'days')
|
||||||
|
.format('YYYY-MM-DD'),
|
||||||
|
moment()
|
||||||
|
.add(1, 'days')
|
||||||
|
.format('YYYY-MM-DD'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
durationItemArray = [
|
render() {
|
||||||
{name:"Daily Report", description:"Enrollments of today", duration:[moment().format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]},
|
let itemStatus = this.durationItemArray.map(data => (
|
||||||
{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')]},
|
<Col key={data.name} span={6}>
|
||||||
{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')]}]
|
<Link
|
||||||
|
to={{
|
||||||
|
// Path to respective report page
|
||||||
render(){
|
pathname: '/entgra/devicestatus',
|
||||||
|
reportData: {
|
||||||
let itemStatus = this.durationItemArray.map((data) =>
|
duration: data.duration,
|
||||||
<Col key={data.name} span={6}>
|
reportType: data.reportType,
|
||||||
<Link
|
params: this.state.reportParams,
|
||||||
to={{
|
paramsType: data.paramsType,
|
||||||
//Path to respective report page
|
},
|
||||||
pathname: "/entgra/devicestatus",
|
}}
|
||||||
reportData: {
|
>
|
||||||
duration: data.duration,
|
<Card
|
||||||
reportType: data.reportType,
|
key={data.name}
|
||||||
params: this.state.reportParams,
|
bordered={true}
|
||||||
paramsType: data.paramsType
|
hoverable={true}
|
||||||
}
|
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||||
}}>
|
>
|
||||||
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
|
<div align="center">
|
||||||
|
<Icon
|
||||||
<div align='center'>
|
type="desktop"
|
||||||
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
|
style={{ fontSize: '25px', color: '#08c' }}
|
||||||
<h2><b>{data.name}</b></h2>
|
/>
|
||||||
<p>{data.description}</p>
|
<h2>
|
||||||
{/*<p>{data.duration}</p>*/}
|
<b>{data.name}</b>
|
||||||
</div>
|
</h2>
|
||||||
</Card>
|
<p>{data.description}</p>
|
||||||
</Link>
|
{/* <p>{data.duration}</p>*/}
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
|
|
||||||
let itemEnrollmentsVsUnenrollments = this.durationItemArray.map((data) =>
|
|
||||||
<Col key={data.name} span={6}>
|
|
||||||
<Link
|
|
||||||
to={{
|
|
||||||
//Path to respective report page
|
|
||||||
pathname: "/entgra/enrollmentsvsunenrollments",
|
|
||||||
reportData: {
|
|
||||||
duration: data.duration,
|
|
||||||
reportType: data.reportType,
|
|
||||||
params: this.state.enrollmentsVsUnenrollmentsParams,
|
|
||||||
paramsType: data.paramsType
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
|
|
||||||
|
|
||||||
<div align='center'>
|
|
||||||
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
|
|
||||||
<h2><b>{data.name}</b></h2>
|
|
||||||
<p>{data.description}</p>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Link>
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
|
|
||||||
let itemEnrollmentType = this.durationItemArray.map((data) =>
|
|
||||||
<Col key={data.name} span={6}>
|
|
||||||
<Link
|
|
||||||
to={{
|
|
||||||
//Path to respective report page
|
|
||||||
pathname: "/entgra/enrollmenttype",
|
|
||||||
reportData: {
|
|
||||||
duration: data.duration,
|
|
||||||
reportType: data.reportType,
|
|
||||||
params: this.state.enrollmentTypeParams,
|
|
||||||
paramsType: data.paramsType
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
|
|
||||||
|
|
||||||
<div align='center'>
|
|
||||||
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
|
|
||||||
<h2><b>{data.name}</b></h2>
|
|
||||||
<p>{data.description}</p>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Link>
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
return(
|
|
||||||
<div>
|
|
||||||
<div style={{borderRadius: 5}}>
|
|
||||||
<Row gutter={16} >
|
|
||||||
{itemStatus}
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{borderRadius: 5}}>
|
|
||||||
<Row gutter={16} >
|
|
||||||
{itemEnrollmentsVsUnenrollments}
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{borderRadius: 5}}>
|
|
||||||
<Row gutter={16} >
|
|
||||||
{itemEnrollmentType}
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
</Card>
|
||||||
}
|
</Link>
|
||||||
|
</Col>
|
||||||
|
));
|
||||||
|
|
||||||
|
let itemEnrollmentsVsUnenrollments = this.durationItemArray.map(data => (
|
||||||
|
<Col key={data.name} span={6}>
|
||||||
|
<Link
|
||||||
|
to={{
|
||||||
|
// Path to respective report page
|
||||||
|
pathname: '/entgra/enrollmentsvsunenrollments',
|
||||||
|
reportData: {
|
||||||
|
duration: data.duration,
|
||||||
|
reportType: data.reportType,
|
||||||
|
params: this.state.enrollmentsVsUnenrollmentsParams,
|
||||||
|
paramsType: data.paramsType,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
key={data.name}
|
||||||
|
bordered={true}
|
||||||
|
hoverable={true}
|
||||||
|
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||||
|
>
|
||||||
|
<div align="center">
|
||||||
|
<Icon
|
||||||
|
type="desktop"
|
||||||
|
style={{ fontSize: '25px', color: '#08c' }}
|
||||||
|
/>
|
||||||
|
<h2>
|
||||||
|
<b>{data.name}</b>
|
||||||
|
</h2>
|
||||||
|
<p>{data.description}</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Link>
|
||||||
|
</Col>
|
||||||
|
));
|
||||||
|
|
||||||
|
let itemEnrollmentType = this.durationItemArray.map(data => (
|
||||||
|
<Col key={data.name} span={6}>
|
||||||
|
<Link
|
||||||
|
to={{
|
||||||
|
// Path to respective report page
|
||||||
|
pathname: '/entgra/enrollmenttype',
|
||||||
|
reportData: {
|
||||||
|
duration: data.duration,
|
||||||
|
reportType: data.reportType,
|
||||||
|
params: this.state.enrollmentTypeParams,
|
||||||
|
paramsType: data.paramsType,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
key={data.name}
|
||||||
|
bordered={true}
|
||||||
|
hoverable={true}
|
||||||
|
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||||
|
>
|
||||||
|
<div align="center">
|
||||||
|
<Icon
|
||||||
|
type="desktop"
|
||||||
|
style={{ fontSize: '25px', color: '#08c' }}
|
||||||
|
/>
|
||||||
|
<h2>
|
||||||
|
<b>{data.name}</b>
|
||||||
|
</h2>
|
||||||
|
<p>{data.description}</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Link>
|
||||||
|
</Col>
|
||||||
|
));
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ borderRadius: 5 }}>
|
||||||
|
<Row gutter={16}>{itemStatus}</Row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ borderRadius: 5 }}>
|
||||||
|
<Row gutter={16}>{itemEnrollmentsVsUnenrollments}</Row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ borderRadius: 5 }}>
|
||||||
|
<Row gutter={16}>{itemEnrollmentType}</Row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ReportDurationItemList;
|
export default ReportDurationItemList;
|
||||||
|
|||||||
@ -16,80 +16,69 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import ReportDurationItemList from './ReportDurationItemList';
|
||||||
Breadcrumb,
|
|
||||||
Icon
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import ReportDurationItemList from "./ReportDurationItemList";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
|
||||||
|
|
||||||
class Reports extends React.Component {
|
class Reports extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
this.state = {
|
this.state = {
|
||||||
paramsObject:{},
|
paramsObject: {},
|
||||||
}
|
|
||||||
}
|
|
||||||
//Get modified value from datepicker and set it to paramsObject
|
|
||||||
updateDurationValue = (modifiedFromDate,modifiedToDate) => {
|
|
||||||
let tempParamObj = this.state.paramsObject;
|
|
||||||
tempParamObj.from = modifiedFromDate;
|
|
||||||
tempParamObj.to = modifiedToDate;
|
|
||||||
this.setState({paramsObject:tempParamObj});
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
// Get modified value from datepicker and set it to paramsObject
|
||||||
|
updateDurationValue = (modifiedFromDate, modifiedToDate) => {
|
||||||
|
let tempParamObj = this.state.paramsObject;
|
||||||
|
tempParamObj.from = modifiedFromDate;
|
||||||
|
tempParamObj.to = modifiedToDate;
|
||||||
|
this.setState({ paramsObject: tempParamObj });
|
||||||
|
};
|
||||||
|
|
||||||
//Get modified value from filters and set it to paramsObject
|
// Get modified value from filters and set it to paramsObject
|
||||||
updateFiltersValue = (modifiedValue,filterType) => {
|
updateFiltersValue = (modifiedValue, filterType) => {
|
||||||
let tempParamObj = this.state.paramsObject;
|
let tempParamObj = this.state.paramsObject;
|
||||||
if(filterType=="Device Status"){
|
if (filterType == 'Device Status') {
|
||||||
tempParamObj.status = modifiedValue;
|
tempParamObj.status = modifiedValue;
|
||||||
if(modifiedValue=="ALL" && tempParamObj.status){
|
if (modifiedValue == 'ALL' && tempParamObj.status) {
|
||||||
delete tempParamObj.status;
|
delete tempParamObj.status;
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
tempParamObj.ownership = modifiedValue;
|
tempParamObj.ownership = modifiedValue;
|
||||||
if(modifiedValue=="ALL" && tempParamObj.ownership){
|
if (modifiedValue == 'ALL' && tempParamObj.ownership) {
|
||||||
delete tempParamObj.ownership;
|
delete tempParamObj.ownership;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
this.setState({paramsObject:tempParamObj});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
//Arrays for filters
|
|
||||||
const statusObj = ['ALL','ACTIVE','INACTIVE','REMOVED'];
|
|
||||||
const ownershipObj = ['ALL','BYOD','COPE'];
|
|
||||||
|
|
||||||
const params = {...this.state.paramsObject};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Reports</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Reports</h3>
|
|
||||||
<ReportDurationItemList/>
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
this.setState({ paramsObject: tempParamObj });
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
|
<Breadcrumb.Item>
|
||||||
|
<Link to="/entgra">
|
||||||
|
<Icon type="home" /> Home
|
||||||
|
</Link>
|
||||||
|
</Breadcrumb.Item>
|
||||||
|
<Breadcrumb.Item>Reports</Breadcrumb.Item>
|
||||||
|
</Breadcrumb>
|
||||||
|
<div className="wrap">
|
||||||
|
<h3>Reports</h3>
|
||||||
|
<ReportDurationItemList />
|
||||||
|
</div>
|
||||||
|
</PageHeader>
|
||||||
|
<div
|
||||||
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Reports;
|
export default Reports;
|
||||||
|
|||||||
@ -16,47 +16,44 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import RolesTable from '../../../components/Roles/RolesTable';
|
||||||
Breadcrumb,
|
|
||||||
Icon
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import RolesTable from "../../../components/Roles/RolesTable";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class Roles extends React.Component {
|
class Roles extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
<Link to="/entgra">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item>Roles</Breadcrumb.Item>
|
</Link>
|
||||||
</Breadcrumb>
|
</Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Breadcrumb.Item>Roles</Breadcrumb.Item>
|
||||||
<h3>Roles</h3>
|
</Breadcrumb>
|
||||||
<Paragraph>All user roles</Paragraph>
|
<div className="wrap">
|
||||||
</div>
|
<h3>Roles</h3>
|
||||||
</PageHeader>
|
<Paragraph>All user roles</Paragraph>
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
</div>
|
||||||
<RolesTable/>
|
</PageHeader>
|
||||||
</div>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
||||||
</div>
|
<RolesTable />
|
||||||
);
|
</div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Roles;
|
export default Roles;
|
||||||
|
|||||||
@ -16,48 +16,45 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
||||||
PageHeader,
|
import { Link } from 'react-router-dom';
|
||||||
Typography,
|
import UsersTable from '../../../components/Users/UsersTable';
|
||||||
Breadcrumb,
|
|
||||||
Icon
|
|
||||||
} from "antd";
|
|
||||||
import {Link} from "react-router-dom";
|
|
||||||
import UsersTable from "../../../components/Users/UsersTable";
|
|
||||||
|
|
||||||
const {Paragraph} = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
class Users extends React.Component {
|
class Users extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.routes = props.routes;
|
this.routes = props.routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader style={{paddingTop: 0}}>
|
<PageHeader style={{ paddingTop: 0 }}>
|
||||||
<Breadcrumb style={{paddingBottom: 16}}>
|
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
<Link to="/entgra">
|
||||||
</Breadcrumb.Item>
|
<Icon type="home" /> Home
|
||||||
<Breadcrumb.Item>Users</Breadcrumb.Item>
|
</Link>
|
||||||
</Breadcrumb>
|
</Breadcrumb.Item>
|
||||||
<div className="wrap">
|
<Breadcrumb.Item>Users</Breadcrumb.Item>
|
||||||
<h3>Users</h3>
|
</Breadcrumb>
|
||||||
<Paragraph>All users for device management.</Paragraph>
|
<div className="wrap">
|
||||||
</div>
|
<h3>Users</h3>
|
||||||
<UsersTable/>
|
<Paragraph>All users for device management.</Paragraph>
|
||||||
</PageHeader>
|
</div>
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
<UsersTable />
|
||||||
|
</PageHeader>
|
||||||
</div>
|
<div
|
||||||
</div>
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
);
|
></div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Users;
|
export default Users;
|
||||||
|
|||||||
@ -16,161 +16,180 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {Typography, Row, Col, Form, Icon, Input, Button, Checkbox} from 'antd';
|
import {
|
||||||
|
Typography,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Form,
|
||||||
|
Icon,
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
} from 'antd';
|
||||||
import './Login.css';
|
import './Login.css';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import {withConfigContext} from "../context/ConfigContext";
|
import { withConfigContext } from '../context/ConfigContext';
|
||||||
|
|
||||||
const {Title} = Typography;
|
const { Title } = Typography;
|
||||||
const {Text} = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
class Login extends React.Component {
|
class Login extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const config = this.props.context;
|
const config = this.props.context;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="background">
|
<div className="background"></div>
|
||||||
</div>
|
<div className="content">
|
||||||
<div className="content">
|
<Row>
|
||||||
<Row>
|
<Col xs={3} sm={3} md={10}></Col>
|
||||||
<Col xs={3} sm={3} md={10}>
|
<Col xs={18} sm={18} md={4}>
|
||||||
|
<Row style={{ marginBottom: 20 }}>
|
||||||
</Col>
|
<Col style={{ textAlign: 'center' }}>
|
||||||
<Col xs={18} sm={18} md={4}>
|
<img
|
||||||
<Row style={{marginBottom: 20}}>
|
style={{
|
||||||
<Col style={{textAlign: "center"}}>
|
marginTop: 36,
|
||||||
<img style={
|
height: 60,
|
||||||
{
|
}}
|
||||||
marginTop: 36,
|
src={config.theme.logo}
|
||||||
height: 60
|
/>
|
||||||
}
|
</Col>
|
||||||
}
|
</Row>
|
||||||
src={config.theme.logo}/>
|
<Title level={2}>Login</Title>
|
||||||
</Col>
|
<WrappedNormalLoginForm />
|
||||||
</Row>
|
</Col>
|
||||||
<Title level={2}>Login</Title>
|
</Row>
|
||||||
<WrappedNormalLoginForm/>
|
<Row>
|
||||||
|
<Col span={4} offset={10}></Col>
|
||||||
</Col>
|
</Row>
|
||||||
</Row>
|
</div>
|
||||||
<Row>
|
</div>
|
||||||
<Col span={4} offset={10}>
|
);
|
||||||
|
}
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class NormalLoginForm extends React.Component {
|
class NormalLoginForm extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
constructor(props) {
|
super(props);
|
||||||
super(props);
|
this.state = {
|
||||||
this.state = {
|
inValid: false,
|
||||||
inValid: false,
|
loading: false,
|
||||||
loading: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSubmit = (e) => {
|
|
||||||
const thisForm = this;
|
|
||||||
const config = this.props.context;
|
|
||||||
console.log(config);
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
thisForm.setState({
|
|
||||||
inValid: false
|
|
||||||
});
|
|
||||||
if (!err) {
|
|
||||||
thisForm.setState({
|
|
||||||
loading: true
|
|
||||||
});
|
|
||||||
const parameters = {
|
|
||||||
username: values.username,
|
|
||||||
password: values.password,
|
|
||||||
platform: "entgra"
|
|
||||||
};
|
|
||||||
|
|
||||||
const request = Object.keys(parameters).map(key => key + '=' + parameters[key]).join('&');
|
|
||||||
|
|
||||||
axios.post(window.location.origin+ config.serverConfig.loginUri, request
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let redirectUrl = window.location.origin + "/entgra";
|
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
|
||||||
if (searchParams.has("redirect")) {
|
|
||||||
redirectUrl = searchParams.get("redirect");
|
|
||||||
}
|
|
||||||
window.location = redirectUrl;
|
|
||||||
}
|
|
||||||
}).catch(function (error) {
|
|
||||||
if (error.response.status === 400) {
|
|
||||||
thisForm.setState({
|
|
||||||
inValid: true,
|
|
||||||
loading: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
handleSubmit = e => {
|
||||||
const {getFieldDecorator} = this.props.form;
|
const thisForm = this;
|
||||||
let errorMsg = "";
|
const config = this.props.context;
|
||||||
if (this.state.inValid) {
|
console.log(config);
|
||||||
errorMsg = <Text type="danger">Invalid Login Details</Text>;
|
|
||||||
}
|
e.preventDefault();
|
||||||
let loading = "";
|
this.props.form.validateFields((err, values) => {
|
||||||
if (this.state.loading) {
|
thisForm.setState({
|
||||||
loading = <Text type="secondary">Loading..</Text>;
|
inValid: false,
|
||||||
}
|
});
|
||||||
return (
|
if (!err) {
|
||||||
<Form onSubmit={this.handleSubmit} className="login-form">
|
thisForm.setState({
|
||||||
<Form.Item>
|
loading: true,
|
||||||
{getFieldDecorator('username', {
|
});
|
||||||
rules: [{required: true, message: 'Please input your username!'}],
|
const parameters = {
|
||||||
})(
|
username: values.username,
|
||||||
<Input name="username" style={{height: 32}}
|
password: values.password,
|
||||||
prefix={<Icon type="user" style={{color: 'rgba(0,0,0,.25)'}}/>}
|
platform: 'entgra',
|
||||||
placeholder="Username"/>
|
};
|
||||||
)}
|
|
||||||
</Form.Item>
|
const request = Object.keys(parameters)
|
||||||
<Form.Item>
|
.map(key => key + '=' + parameters[key])
|
||||||
{getFieldDecorator('password', {
|
.join('&');
|
||||||
rules: [{required: true, message: 'Please input your Password!'}],
|
|
||||||
})(
|
axios
|
||||||
<Input name="password" style={{height: 32}}
|
.post(window.location.origin + config.serverConfig.loginUri, request)
|
||||||
prefix={<Icon type="lock" style={{color: 'rgba(0,0,0,.25)'}}/>} type="password"
|
.then(res => {
|
||||||
placeholder="Password"/>
|
if (res.status === 200) {
|
||||||
)}
|
let redirectUrl = window.location.origin + '/entgra';
|
||||||
</Form.Item>
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
{loading}
|
if (searchParams.has('redirect')) {
|
||||||
{errorMsg}
|
redirectUrl = searchParams.get('redirect');
|
||||||
<Form.Item>
|
}
|
||||||
{getFieldDecorator('remember', {
|
window.location = redirectUrl;
|
||||||
valuePropName: 'checked',
|
}
|
||||||
initialValue: true,
|
})
|
||||||
})(
|
.catch(function(error) {
|
||||||
<Checkbox>Remember me</Checkbox>
|
if (error.response.status === 400) {
|
||||||
)}
|
thisForm.setState({
|
||||||
<br/>
|
inValid: true,
|
||||||
<a className="login-form-forgot" href="">Forgot password</a>
|
loading: false,
|
||||||
<Button loading={this.state.loading} block type="primary" htmlType="submit" className="login-form-button">
|
});
|
||||||
Log in
|
}
|
||||||
</Button>
|
});
|
||||||
</Form.Item>
|
}
|
||||||
</Form>
|
});
|
||||||
);
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { getFieldDecorator } = this.props.form;
|
||||||
|
let errorMsg = '';
|
||||||
|
if (this.state.inValid) {
|
||||||
|
errorMsg = <Text type="danger">Invalid Login Details</Text>;
|
||||||
}
|
}
|
||||||
|
let loading = '';
|
||||||
|
if (this.state.loading) {
|
||||||
|
loading = <Text type="secondary">Loading..</Text>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Form onSubmit={this.handleSubmit} className="login-form">
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('username', {
|
||||||
|
rules: [{ required: true, message: 'Please input your username!' }],
|
||||||
|
})(
|
||||||
|
<Input
|
||||||
|
name="username"
|
||||||
|
style={{ height: 32 }}
|
||||||
|
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
|
||||||
|
placeholder="Username"
|
||||||
|
/>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('password', {
|
||||||
|
rules: [{ required: true, message: 'Please input your Password!' }],
|
||||||
|
})(
|
||||||
|
<Input
|
||||||
|
name="password"
|
||||||
|
style={{ height: 32 }}
|
||||||
|
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
|
||||||
|
type="password"
|
||||||
|
placeholder="Password"
|
||||||
|
/>,
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
{loading}
|
||||||
|
{errorMsg}
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('remember', {
|
||||||
|
valuePropName: 'checked',
|
||||||
|
initialValue: true,
|
||||||
|
})(<Checkbox>Remember me</Checkbox>)}
|
||||||
|
<br />
|
||||||
|
<a className="login-form-forgot" href="">
|
||||||
|
Forgot password
|
||||||
|
</a>
|
||||||
|
<Button
|
||||||
|
loading={this.state.loading}
|
||||||
|
block
|
||||||
|
type="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
className="login-form-button"
|
||||||
|
>
|
||||||
|
Log in
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const WrappedNormalLoginForm = withConfigContext(Form.create({name: 'normal_login'})(NormalLoginForm));
|
const WrappedNormalLoginForm = withConfigContext(
|
||||||
|
Form.create({ name: 'normal_login' })(NormalLoginForm),
|
||||||
|
);
|
||||||
|
|
||||||
export default withConfigContext(Login);
|
export default withConfigContext(Login);
|
||||||
|
|||||||
@ -34,8 +34,8 @@ const isLocalhost = Boolean(
|
|||||||
window.location.hostname === '[::1]' ||
|
window.location.hostname === '[::1]' ||
|
||||||
// 127.0.0.1/8 is considered localhost for IPv4.
|
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||||
window.location.hostname.match(
|
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) {
|
export function register(config) {
|
||||||
@ -61,7 +61,7 @@ export function register(config) {
|
|||||||
navigator.serviceWorker.ready.then(() => {
|
navigator.serviceWorker.ready.then(() => {
|
||||||
console.log(
|
console.log(
|
||||||
'This web app is being served cache-first by a service ' +
|
'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 {
|
} else {
|
||||||
@ -89,7 +89,7 @@ function registerValidSW(swUrl, config) {
|
|||||||
// content until all client tabs are closed.
|
// content until all client tabs are closed.
|
||||||
console.log(
|
console.log(
|
||||||
'New content is available and will be used when all ' +
|
'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
|
// Execute callback
|
||||||
@ -139,7 +139,7 @@ function checkValidServiceWorker(swUrl, config) {
|
|||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
console.log(
|
console.log(
|
||||||
'No internet connection found. App is running in offline mode.'
|
'No internet connection found. App is running in offline mode.',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,119 +16,119 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
const HtmlWebPackPlugin = require("html-webpack-plugin");
|
const HtmlWebPackPlugin = require('html-webpack-plugin');
|
||||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const configurations = require("./public/conf/config.json");
|
const configurations = require('./public/conf/config.json');
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
devtool: "source-map",
|
devtool: 'source-map',
|
||||||
output: {
|
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/'),
|
||||||
},
|
},
|
||||||
watch: false,
|
extensions: ['.jsx', '.js', '.ttf', '.woff', '.woff2', '.svg'],
|
||||||
resolve: {
|
},
|
||||||
alias: {
|
module: {
|
||||||
AppData: path.resolve(__dirname, 'source/src/app/common/'),
|
rules: [
|
||||||
AppComponents: path.resolve(__dirname, 'source/src/app/components/')
|
{
|
||||||
},
|
test: /\.(js|jsx)$/,
|
||||||
extensions: ['.jsx', '.js', '.ttf', '.woff', '.woff2', '.svg']
|
exclude: /node_modules/,
|
||||||
},
|
use: [
|
||||||
module: {
|
{
|
||||||
rules: [
|
loader: 'babel-loader',
|
||||||
{
|
},
|
||||||
test: /\.(js|jsx)$/,
|
],
|
||||||
exclude: /node_modules/,
|
},
|
||||||
use: [
|
{
|
||||||
{
|
test: /\.html$/,
|
||||||
loader: 'babel-loader'
|
use: [
|
||||||
}
|
{
|
||||||
]
|
loader: 'html-loader',
|
||||||
|
options: { minimize: true },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: [
|
||||||
|
MiniCssExtractPlugin.loader,
|
||||||
|
'css-loader',
|
||||||
|
'postcss-loader',
|
||||||
|
'sass-loader',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: ['style-loader', 'scss-loader'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.less$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'style-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'css-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'less-loader',
|
||||||
|
options: {
|
||||||
|
modifyVars: {
|
||||||
|
'primary-color': configurations.theme.primaryColor,
|
||||||
|
'link-color': configurations.theme.primaryColor,
|
||||||
|
},
|
||||||
|
javascriptEnabled: true,
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
test: /\.html$/,
|
],
|
||||||
use: [
|
},
|
||||||
{
|
{
|
||||||
loader: "html-loader",
|
test: /\.(woff|woff2|eot|ttf|svg)$/,
|
||||||
options: { minimize: true }
|
loader: 'url-loader?limit=100000',
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
|
test: /\.(png|jpe?g)/i,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
name: './img/[name].[ext]',
|
||||||
|
limit: 10000,
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
test: /\.css$/,
|
{
|
||||||
use: [MiniCssExtractPlugin.loader, "css-loader"]
|
loader: 'img-loader',
|
||||||
},
|
},
|
||||||
{
|
],
|
||||||
test: /\.scss$/,
|
},
|
||||||
use: [
|
|
||||||
MiniCssExtractPlugin.loader,
|
|
||||||
"css-loader",
|
|
||||||
"postcss-loader",
|
|
||||||
"sass-loader"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.scss$/,
|
|
||||||
use: [ 'style-loader', 'scss-loader' ]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.less$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: "style-loader"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: "css-loader",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: "less-loader",
|
|
||||||
options: {
|
|
||||||
modifyVars: {
|
|
||||||
'primary-color': configurations.theme.primaryColor,
|
|
||||||
'link-color': configurations.theme.primaryColor,
|
|
||||||
},
|
|
||||||
javascriptEnabled: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(woff|woff2|eot|ttf|svg)$/,
|
|
||||||
loader: 'url-loader?limit=100000',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpe?g)/i,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: "url-loader",
|
|
||||||
options: {
|
|
||||||
name: "./img/[name].[ext]",
|
|
||||||
limit: 10000
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: "img-loader"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new HtmlWebPackPlugin({
|
|
||||||
template: "./src/index.html",
|
|
||||||
filename: "./index.html"
|
|
||||||
}),
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
filename: "[name].css",
|
|
||||||
chunkFilename: "[id].css"
|
|
||||||
})
|
|
||||||
],
|
],
|
||||||
externals: {
|
},
|
||||||
'Config': JSON.stringify(require('./public/conf/config.json'))
|
plugins: [
|
||||||
}
|
new HtmlWebPackPlugin({
|
||||||
|
template: './src/index.html',
|
||||||
|
filename: './index.html',
|
||||||
|
}),
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: '[name].css',
|
||||||
|
chunkFilename: '[id].css',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
externals: {
|
||||||
|
Config: JSON.stringify(require('./public/conf/config.json')),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
config.watch = true;
|
config.watch = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user