Remove device-mgt react UI app from device-mgt-core
@ -1,132 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
~ Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
~
|
|
||||||
~ Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
~ Version 2.0 (the "License"); you may not use this file except
|
|
||||||
~ in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing,
|
|
||||||
~ software distributed under the License is distributed on an
|
|
||||||
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
~ KIND, either express or implied. See the License for the
|
|
||||||
~ specific language governing permissions and limitations
|
|
||||||
~ under the License.
|
|
||||||
-->
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>org.wso2.carbon.devicemgt</groupId>
|
|
||||||
<artifactId>device-mgt</artifactId>
|
|
||||||
<version>4.1.7-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>io.entgra.device.mgt.ui</artifactId>
|
|
||||||
<version>4.1.7-SNAPSHOT</version>
|
|
||||||
<packaging>war</packaging>
|
|
||||||
<name>Entgra - Device Management UI Component</name>
|
|
||||||
<url>https://entgra.io</url>
|
|
||||||
<description>This Component contains Device Management UI</description>
|
|
||||||
<dependencies>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-war-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<packagingExcludes>WEB-INF/lib/*cxf*.jar</packagingExcludes>
|
|
||||||
<warName>entgra</warName>
|
|
||||||
<webResources>
|
|
||||||
<resource>
|
|
||||||
<directory>${npm.output.directory}/dist</directory>
|
|
||||||
</resource>
|
|
||||||
<resource>
|
|
||||||
<directory>${npm.output.directory}/public</directory>
|
|
||||||
<targetPath>public</targetPath>
|
|
||||||
</resource>
|
|
||||||
</webResources>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>com.github.eirslett</groupId>
|
|
||||||
<artifactId>frontend-maven-plugin</artifactId>
|
|
||||||
<version>${frontend.mave.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<workingDirectory>${npm.working.dir}</workingDirectory>
|
|
||||||
<!-- where to install npm -->
|
|
||||||
<installDirectory>${npm.install.dir}</installDirectory>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>install node and npm</id>
|
|
||||||
<goals>
|
|
||||||
<goal>install-node-and-npm</goal>
|
|
||||||
</goals>
|
|
||||||
<phase>generate-resources</phase>
|
|
||||||
<configuration>
|
|
||||||
<nodeVersion>${node.version}</nodeVersion>
|
|
||||||
<npmVersion>${npm.version}</npmVersion>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>npm install</id>
|
|
||||||
<goals>
|
|
||||||
<goal>npm</goal>
|
|
||||||
</goals>
|
|
||||||
<!-- Optional configuration which provides for running any npm command -->
|
|
||||||
<configuration>
|
|
||||||
<arguments>install</arguments>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>lint</id>
|
|
||||||
<goals>
|
|
||||||
<goal>npm</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<arguments>run-script lint</arguments>
|
|
||||||
</configuration>
|
|
||||||
<phase>generate-resources</phase>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>prod</id>
|
|
||||||
<goals>
|
|
||||||
<goal>npm</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<arguments>run-script ${npm.build.command}</arguments>
|
|
||||||
</configuration>
|
|
||||||
<phase>generate-resources</phase>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>platform-windows</id>
|
|
||||||
<activation>
|
|
||||||
<os>
|
|
||||||
<family>windows</family>
|
|
||||||
</os>
|
|
||||||
</activation>
|
|
||||||
<properties>
|
|
||||||
<!-- Override the executable names for Windows -->
|
|
||||||
<npm.executable>npm.cmd</npm.executable>
|
|
||||||
</properties>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
<properties>
|
|
||||||
<maven.test.skip>false</maven.test.skip>
|
|
||||||
<npm.executable>npm</npm.executable>
|
|
||||||
<npm.build.command>build_prod</npm.build.command>
|
|
||||||
<npm.working.dir>./react-app</npm.working.dir>
|
|
||||||
<npm.install.dir>./react-app/tmp</npm.install.dir>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<npm.output.directory>react-app</npm.output.directory>
|
|
||||||
</properties>
|
|
||||||
</project>
|
|
||||||
@ -1,325 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "all",
|
|
||||||
"parser": "flow"
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = function(api) {
|
|
||||||
api.cache(true);
|
|
||||||
const presets = ['@babel/preset-env', '@babel/preset-react'];
|
|
||||||
const plugins = ['@babel/plugin-proposal-class-properties'];
|
|
||||||
|
|
||||||
return {
|
|
||||||
presets,
|
|
||||||
plugins,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,101 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "entgra",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Entgra device management",
|
|
||||||
"main": "App.js",
|
|
||||||
"license": "Apache License 2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"acorn": "^6.2.0",
|
|
||||||
"antd": "^3.23.5",
|
|
||||||
"axios": "^0.18.1",
|
|
||||||
"babel-eslint": "^9.0.0",
|
|
||||||
"bizcharts": "^3.5.6",
|
|
||||||
"bootstrap": "^4.3.1",
|
|
||||||
"javascript-time-ago": "^2.0.1",
|
|
||||||
"keymirror": "^0.1.1",
|
|
||||||
"leaflet": "^1.3.4",
|
|
||||||
"leaflet-routing-machine": "^3.2.12",
|
|
||||||
"lodash.debounce": "^4.0.8",
|
|
||||||
"moment": "latest",
|
|
||||||
"prop-types": "latest",
|
|
||||||
"rc-viewer": "0.0.9",
|
|
||||||
"react-bootstrap": "^1.0.0-beta.12",
|
|
||||||
"react-highlight-words": "^0.16.0",
|
|
||||||
"react-icons": "^3.8.0",
|
|
||||||
"react-image-viewer-zoom": "^1.0.36",
|
|
||||||
"react-infinite-scroller": "^1.2.4",
|
|
||||||
"react-leaflet": "^2.4.0",
|
|
||||||
"react-moment": "^0.9.7",
|
|
||||||
"react-router": "^5.0.1",
|
|
||||||
"react-router-config": "^5.0.1",
|
|
||||||
"react-router-dom": "^5.0.1",
|
|
||||||
"react-scripts": "2.1.8",
|
|
||||||
"react-star-ratings": "^2.3.0",
|
|
||||||
"react-twemoji": "^0.2.3",
|
|
||||||
"react-virtualized": "^9.21.1",
|
|
||||||
"react-websocket": "^2.1.0",
|
|
||||||
"reqwest": "^2.0.5",
|
|
||||||
"storm-react-diagrams": "^5.2.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@antv/data-set": "^0.10.2",
|
|
||||||
"@babel/core": "^7.5.4",
|
|
||||||
"@babel/plugin-proposal-class-properties": "^7.5.0",
|
|
||||||
"@babel/preset-env": "^7.5.4",
|
|
||||||
"@babel/preset-react": "^7.0.0",
|
|
||||||
"@babel/register": "^7.4.4",
|
|
||||||
"babel-loader": "^8.0.6",
|
|
||||||
"body-parser": "^1.19.0",
|
|
||||||
"chai": "^4.1.2",
|
|
||||||
"cross-env": "^7.0.0",
|
|
||||||
"css-loader": "^0.28.11",
|
|
||||||
"eslint": "^5.16.0",
|
|
||||||
"eslint-config-prettier": "4.3.0",
|
|
||||||
"eslint-plugin-babel": "5.3.0",
|
|
||||||
"eslint-plugin-jsx": "0.0.2",
|
|
||||||
"eslint-plugin-prettier": "3.1.0",
|
|
||||||
"eslint-plugin-react": "7.14.2",
|
|
||||||
"express": "^4.17.1",
|
|
||||||
"express-pino-logger": "^4.0.0",
|
|
||||||
"file-loader": "^2.0.0",
|
|
||||||
"html-loader": "^0.5.5",
|
|
||||||
"html-webpack-plugin": "^3.2.0",
|
|
||||||
"img-loader": "^3.0.1",
|
|
||||||
"json-loader": "^0.5.7",
|
|
||||||
"less": "^3.9.0",
|
|
||||||
"less-loader": "^4.1.0",
|
|
||||||
"mini-css-extract-plugin": "^0.5.0",
|
|
||||||
"mocha": "^5.2.0",
|
|
||||||
"mock-local-storage": "^1.0.5",
|
|
||||||
"node-env-run": "^3.0.2",
|
|
||||||
"node-sass": "^4.12.0",
|
|
||||||
"nodemon": "^1.19.1",
|
|
||||||
"npm-run-all": "^4.1.5",
|
|
||||||
"pino-colada": "^1.4.5",
|
|
||||||
"postcss-loader": "^3.0.0",
|
|
||||||
"prettier": "1.18.1",
|
|
||||||
"qrcode.react": "^1.0.0",
|
|
||||||
"react": "^16.8.6",
|
|
||||||
"react-dom": "^16.8.6",
|
|
||||||
"react-intl": "^2.9.0",
|
|
||||||
"sass-loader": "^6.0.7",
|
|
||||||
"style-loader": "^0.18.2",
|
|
||||||
"url-loader": "^1.1.2",
|
|
||||||
"webpack": "^4.35.3",
|
|
||||||
"webpack-cli": "^3.3.5",
|
|
||||||
"webpack-dev-server": "^3.7.2"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "webpack-dev-server --mode development --open",
|
|
||||||
"dev": "webpack --mode development",
|
|
||||||
"build": "webpack --mode production",
|
|
||||||
"watch": "webpack --watch --mode development",
|
|
||||||
"test": "react-scripts test --env=jsdom",
|
|
||||||
"eject": "react-scripts eject",
|
|
||||||
"build_prod": "cross-env NODE_ENV=production NODE_OPTIONS=--max_old_space_size=4096 webpack -p --display errors-only --hide-modules",
|
|
||||||
"build_dev": "cross-env NODE_ENV=development webpack -d --watch ",
|
|
||||||
"server": "node-env-run server --exec nodemon | pino-colada",
|
|
||||||
"dev2": "run-p server start",
|
|
||||||
"lint": "eslint \"src/**/*.js\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"theme": {
|
|
||||||
"logo": "https://entgra.io/assets/images/svg/logo.svg",
|
|
||||||
"primaryColor": "rgb(24, 144, 255)"
|
|
||||||
},
|
|
||||||
"serverConfig": {
|
|
||||||
"invoker": {
|
|
||||||
"uri": "/entgra-ui-request-handler/invoke",
|
|
||||||
"deviceMgt": "/device-mgt/v1.0"
|
|
||||||
},
|
|
||||||
"loginUri": "/entgra-ui-request-handler/login",
|
|
||||||
"logoutUri": "/entgra-ui-request-handler/logout",
|
|
||||||
"platform": "entgra"
|
|
||||||
},
|
|
||||||
"defaultPlatformIcons": {
|
|
||||||
"default": {
|
|
||||||
"icon": "hdd",
|
|
||||||
"color": "#535c68",
|
|
||||||
"theme": "outlined"
|
|
||||||
},
|
|
||||||
"android": {
|
|
||||||
"icon": "android",
|
|
||||||
"color": "#7db343",
|
|
||||||
"theme": "filled"
|
|
||||||
},
|
|
||||||
"ios": {
|
|
||||||
"icon": "apple",
|
|
||||||
"color": "#535c68",
|
|
||||||
"theme": "filled"
|
|
||||||
},
|
|
||||||
"windows": {
|
|
||||||
"icon": "windows",
|
|
||||||
"color": "#008cc4",
|
|
||||||
"theme": "filled"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"geoMap": {
|
|
||||||
"url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
||||||
"attribution": "© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors",
|
|
||||||
"defaultZoomLevel": 16,
|
|
||||||
"timeout": 120
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"short_name": "App Store",
|
|
||||||
"name": "WSO2 IoT App Store",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "images/favicon.png",
|
|
||||||
"sizes": "16x16",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"start_url": "./index.html",
|
|
||||||
"display": "standalone",
|
|
||||||
"theme_color": "#000000",
|
|
||||||
"background_color": "#ffffff"
|
|
||||||
}
|
|
||||||
@ -1,636 +0,0 @@
|
|||||||
/* required styles */
|
|
||||||
|
|
||||||
.leaflet-pane,
|
|
||||||
.leaflet-tile,
|
|
||||||
.leaflet-marker-icon,
|
|
||||||
.leaflet-marker-shadow,
|
|
||||||
.leaflet-tile-container,
|
|
||||||
.leaflet-pane > svg,
|
|
||||||
.leaflet-pane > canvas,
|
|
||||||
.leaflet-zoom-box,
|
|
||||||
.leaflet-image-layer,
|
|
||||||
.leaflet-layer {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
.leaflet-container {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.leaflet-tile,
|
|
||||||
.leaflet-marker-icon,
|
|
||||||
.leaflet-marker-shadow {
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-drag: none;
|
|
||||||
}
|
|
||||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
|
||||||
.leaflet-safari .leaflet-tile {
|
|
||||||
image-rendering: -webkit-optimize-contrast;
|
|
||||||
}
|
|
||||||
/* hack that prevents hw layers "stretching" when loading new tiles */
|
|
||||||
.leaflet-safari .leaflet-tile-container {
|
|
||||||
width: 1600px;
|
|
||||||
height: 1600px;
|
|
||||||
-webkit-transform-origin: 0 0;
|
|
||||||
}
|
|
||||||
.leaflet-marker-icon,
|
|
||||||
.leaflet-marker-shadow {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
|
||||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
|
||||||
.leaflet-container .leaflet-overlay-pane svg,
|
|
||||||
.leaflet-container .leaflet-marker-pane img,
|
|
||||||
.leaflet-container .leaflet-shadow-pane img,
|
|
||||||
.leaflet-container .leaflet-tile-pane img,
|
|
||||||
.leaflet-container img.leaflet-image-layer {
|
|
||||||
max-width: none !important;
|
|
||||||
max-height: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-container.leaflet-touch-zoom {
|
|
||||||
-ms-touch-action: pan-x pan-y;
|
|
||||||
touch-action: pan-x pan-y;
|
|
||||||
}
|
|
||||||
.leaflet-container.leaflet-touch-drag {
|
|
||||||
-ms-touch-action: pinch-zoom;
|
|
||||||
/* Fallback for FF which doesn't support pinch-zoom */
|
|
||||||
touch-action: none;
|
|
||||||
touch-action: pinch-zoom;
|
|
||||||
}
|
|
||||||
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
|
|
||||||
-ms-touch-action: none;
|
|
||||||
touch-action: none;
|
|
||||||
}
|
|
||||||
.leaflet-container {
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
.leaflet-container a {
|
|
||||||
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
|
|
||||||
}
|
|
||||||
.leaflet-tile {
|
|
||||||
filter: inherit;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
.leaflet-tile-loaded {
|
|
||||||
visibility: inherit;
|
|
||||||
}
|
|
||||||
.leaflet-zoom-box {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 800;
|
|
||||||
}
|
|
||||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
|
||||||
.leaflet-overlay-pane svg {
|
|
||||||
-moz-user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-pane { z-index: 400; }
|
|
||||||
|
|
||||||
.leaflet-tile-pane { z-index: 200; }
|
|
||||||
.leaflet-overlay-pane { z-index: 400; }
|
|
||||||
.leaflet-shadow-pane { z-index: 500; }
|
|
||||||
.leaflet-marker-pane { z-index: 600; }
|
|
||||||
.leaflet-tooltip-pane { z-index: 650; }
|
|
||||||
.leaflet-popup-pane { z-index: 700; }
|
|
||||||
|
|
||||||
.leaflet-map-pane canvas { z-index: 100; }
|
|
||||||
.leaflet-map-pane svg { z-index: 200; }
|
|
||||||
|
|
||||||
.leaflet-vml-shape {
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
}
|
|
||||||
.lvml {
|
|
||||||
behavior: url(#default#VML);
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* control positioning */
|
|
||||||
|
|
||||||
.leaflet-control {
|
|
||||||
position: relative;
|
|
||||||
z-index: 800;
|
|
||||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
.leaflet-top,
|
|
||||||
.leaflet-bottom {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1000;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.leaflet-top {
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
.leaflet-right {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
.leaflet-bottom {
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
.leaflet-left {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.leaflet-control {
|
|
||||||
float: left;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.leaflet-right .leaflet-control {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
.leaflet-top .leaflet-control {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
.leaflet-bottom .leaflet-control {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.leaflet-left .leaflet-control {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
.leaflet-right .leaflet-control {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* zoom and fade animations */
|
|
||||||
|
|
||||||
.leaflet-fade-anim .leaflet-tile {
|
|
||||||
will-change: opacity;
|
|
||||||
}
|
|
||||||
.leaflet-fade-anim .leaflet-popup {
|
|
||||||
opacity: 0;
|
|
||||||
-webkit-transition: opacity 0.2s linear;
|
|
||||||
-moz-transition: opacity 0.2s linear;
|
|
||||||
-o-transition: opacity 0.2s linear;
|
|
||||||
transition: opacity 0.2s linear;
|
|
||||||
}
|
|
||||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.leaflet-zoom-animated {
|
|
||||||
-webkit-transform-origin: 0 0;
|
|
||||||
-ms-transform-origin: 0 0;
|
|
||||||
transform-origin: 0 0;
|
|
||||||
}
|
|
||||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
|
||||||
will-change: transform;
|
|
||||||
}
|
|
||||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
|
||||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
|
||||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
|
||||||
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
|
|
||||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
|
||||||
}
|
|
||||||
.leaflet-zoom-anim .leaflet-tile,
|
|
||||||
.leaflet-pan-anim .leaflet-tile {
|
|
||||||
-webkit-transition: none;
|
|
||||||
-moz-transition: none;
|
|
||||||
-o-transition: none;
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* cursors */
|
|
||||||
|
|
||||||
.leaflet-interactive {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.leaflet-grab {
|
|
||||||
cursor: -webkit-grab;
|
|
||||||
cursor: -moz-grab;
|
|
||||||
}
|
|
||||||
.leaflet-crosshair,
|
|
||||||
.leaflet-crosshair .leaflet-interactive {
|
|
||||||
cursor: crosshair;
|
|
||||||
}
|
|
||||||
.leaflet-popup-pane,
|
|
||||||
.leaflet-control {
|
|
||||||
cursor: auto;
|
|
||||||
}
|
|
||||||
.leaflet-dragging .leaflet-grab,
|
|
||||||
.leaflet-dragging .leaflet-grab .leaflet-interactive,
|
|
||||||
.leaflet-dragging .leaflet-marker-draggable {
|
|
||||||
cursor: move;
|
|
||||||
cursor: -webkit-grabbing;
|
|
||||||
cursor: -moz-grabbing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* marker & overlays interactivity */
|
|
||||||
.leaflet-marker-icon,
|
|
||||||
.leaflet-marker-shadow,
|
|
||||||
.leaflet-image-layer,
|
|
||||||
.leaflet-pane > svg path,
|
|
||||||
.leaflet-tile-container {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-marker-icon.leaflet-interactive,
|
|
||||||
.leaflet-image-layer.leaflet-interactive,
|
|
||||||
.leaflet-pane > svg path.leaflet-interactive {
|
|
||||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* visual tweaks */
|
|
||||||
|
|
||||||
.leaflet-container {
|
|
||||||
background: #ddd;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
.leaflet-container a {
|
|
||||||
color: #0078A8;
|
|
||||||
}
|
|
||||||
.leaflet-container a.leaflet-active {
|
|
||||||
outline: 2px solid orange;
|
|
||||||
}
|
|
||||||
.leaflet-zoom-box {
|
|
||||||
border: 2px dotted #38f;
|
|
||||||
background: rgba(255,255,255,0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* general typography */
|
|
||||||
.leaflet-container {
|
|
||||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* general toolbar styles */
|
|
||||||
|
|
||||||
.leaflet-bar {
|
|
||||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
.leaflet-bar a,
|
|
||||||
.leaflet-bar a:hover {
|
|
||||||
background-color: #fff;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
width: 26px;
|
|
||||||
height: 26px;
|
|
||||||
line-height: 26px;
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
.leaflet-bar a,
|
|
||||||
.leaflet-control-layers-toggle {
|
|
||||||
background-position: 50% 50%;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.leaflet-bar a:hover {
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
}
|
|
||||||
.leaflet-bar a:first-child {
|
|
||||||
border-top-left-radius: 4px;
|
|
||||||
border-top-right-radius: 4px;
|
|
||||||
}
|
|
||||||
.leaflet-bar a:last-child {
|
|
||||||
border-bottom-left-radius: 4px;
|
|
||||||
border-bottom-right-radius: 4px;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.leaflet-bar a.leaflet-disabled {
|
|
||||||
cursor: default;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
color: #bbb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-touch .leaflet-bar a {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
line-height: 30px;
|
|
||||||
}
|
|
||||||
.leaflet-touch .leaflet-bar a:first-child {
|
|
||||||
border-top-left-radius: 2px;
|
|
||||||
border-top-right-radius: 2px;
|
|
||||||
}
|
|
||||||
.leaflet-touch .leaflet-bar a:last-child {
|
|
||||||
border-bottom-left-radius: 2px;
|
|
||||||
border-bottom-right-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* zoom control */
|
|
||||||
|
|
||||||
.leaflet-control-zoom-in,
|
|
||||||
.leaflet-control-zoom-out {
|
|
||||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
|
||||||
text-indent: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* layers control */
|
|
||||||
|
|
||||||
.leaflet-control-layers {
|
|
||||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
.leaflet-control-layers-toggle {
|
|
||||||
background-image: url(images/layers.png);
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
}
|
|
||||||
.leaflet-retina .leaflet-control-layers-toggle {
|
|
||||||
background-image: url(images/layers-2x.png);
|
|
||||||
background-size: 26px 26px;
|
|
||||||
}
|
|
||||||
.leaflet-touch .leaflet-control-layers-toggle {
|
|
||||||
width: 44px;
|
|
||||||
height: 44px;
|
|
||||||
}
|
|
||||||
.leaflet-control-layers .leaflet-control-layers-list,
|
|
||||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.leaflet-control-layers-expanded {
|
|
||||||
padding: 6px 10px 6px 6px;
|
|
||||||
color: #333;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
.leaflet-control-layers-scrollbar {
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
padding-right: 5px;
|
|
||||||
}
|
|
||||||
.leaflet-control-layers-selector {
|
|
||||||
margin-top: 2px;
|
|
||||||
position: relative;
|
|
||||||
top: 1px;
|
|
||||||
}
|
|
||||||
.leaflet-control-layers label {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.leaflet-control-layers-separator {
|
|
||||||
height: 0;
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
margin: 5px -10px 5px -6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default icon URLs */
|
|
||||||
.leaflet-default-icon-path {
|
|
||||||
background-image: url(images/marker-icon.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* attribution and scale controls */
|
|
||||||
|
|
||||||
.leaflet-container .leaflet-control-attribution {
|
|
||||||
background: #fff;
|
|
||||||
background: rgba(255, 255, 255, 0.7);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.leaflet-control-attribution,
|
|
||||||
.leaflet-control-scale-line {
|
|
||||||
padding: 0 5px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.leaflet-control-attribution a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.leaflet-control-attribution a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
.leaflet-container .leaflet-control-attribution,
|
|
||||||
.leaflet-container .leaflet-control-scale {
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
.leaflet-left .leaflet-control-scale {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
.leaflet-bottom .leaflet-control-scale {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
.leaflet-control-scale-line {
|
|
||||||
border: 2px solid #777;
|
|
||||||
border-top: none;
|
|
||||||
line-height: 1.1;
|
|
||||||
padding: 2px 5px 1px;
|
|
||||||
font-size: 11px;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
background: #fff;
|
|
||||||
background: rgba(255, 255, 255, 0.5);
|
|
||||||
}
|
|
||||||
.leaflet-control-scale-line:not(:first-child) {
|
|
||||||
border-top: 2px solid #777;
|
|
||||||
border-bottom: none;
|
|
||||||
margin-top: -2px;
|
|
||||||
}
|
|
||||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
|
||||||
border-bottom: 2px solid #777;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-touch .leaflet-control-attribution,
|
|
||||||
.leaflet-touch .leaflet-control-layers,
|
|
||||||
.leaflet-touch .leaflet-bar {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
.leaflet-touch .leaflet-control-layers,
|
|
||||||
.leaflet-touch .leaflet-bar {
|
|
||||||
border: 2px solid rgba(0,0,0,0.2);
|
|
||||||
background-clip: padding-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* popup */
|
|
||||||
|
|
||||||
.leaflet-popup {
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.leaflet-popup-content-wrapper {
|
|
||||||
padding: 1px;
|
|
||||||
text-align: left;
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
.leaflet-popup-content {
|
|
||||||
margin: 13px 19px;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.leaflet-popup-content p {
|
|
||||||
margin: 18px 0;
|
|
||||||
}
|
|
||||||
.leaflet-popup-tip-container {
|
|
||||||
width: 40px;
|
|
||||||
height: 20px;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -20px;
|
|
||||||
overflow: hidden;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.leaflet-popup-tip {
|
|
||||||
width: 17px;
|
|
||||||
height: 17px;
|
|
||||||
padding: 1px;
|
|
||||||
|
|
||||||
margin: -10px auto 0;
|
|
||||||
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
-moz-transform: rotate(45deg);
|
|
||||||
-ms-transform: rotate(45deg);
|
|
||||||
-o-transform: rotate(45deg);
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
.leaflet-popup-content-wrapper,
|
|
||||||
.leaflet-popup-tip {
|
|
||||||
background: white;
|
|
||||||
color: #333;
|
|
||||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
|
||||||
}
|
|
||||||
.leaflet-container a.leaflet-popup-close-button {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 4px 4px 0 0;
|
|
||||||
border: none;
|
|
||||||
text-align: center;
|
|
||||||
width: 18px;
|
|
||||||
height: 14px;
|
|
||||||
font: 16px/14px Tahoma, Verdana, sans-serif;
|
|
||||||
color: #c3c3c3;
|
|
||||||
text-decoration: none;
|
|
||||||
font-weight: bold;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
.leaflet-container a.leaflet-popup-close-button:hover {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
.leaflet-popup-scrolled {
|
|
||||||
overflow: auto;
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
|
||||||
zoom: 1;
|
|
||||||
}
|
|
||||||
.leaflet-oldie .leaflet-popup-tip {
|
|
||||||
width: 24px;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
|
||||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
|
||||||
}
|
|
||||||
.leaflet-oldie .leaflet-popup-tip-container {
|
|
||||||
margin-top: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-oldie .leaflet-control-zoom,
|
|
||||||
.leaflet-oldie .leaflet-control-layers,
|
|
||||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
|
||||||
.leaflet-oldie .leaflet-popup-tip {
|
|
||||||
border: 1px solid #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* div icon */
|
|
||||||
|
|
||||||
.leaflet-div-icon {
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Tooltip */
|
|
||||||
/* Base styles for the element that has a tooltip */
|
|
||||||
.leaflet-tooltip {
|
|
||||||
position: absolute;
|
|
||||||
padding: 6px;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid #fff;
|
|
||||||
border-radius: 3px;
|
|
||||||
color: #222;
|
|
||||||
white-space: nowrap;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
pointer-events: none;
|
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
|
||||||
}
|
|
||||||
.leaflet-tooltip.leaflet-clickable {
|
|
||||||
cursor: pointer;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-top:before,
|
|
||||||
.leaflet-tooltip-bottom:before,
|
|
||||||
.leaflet-tooltip-left:before,
|
|
||||||
.leaflet-tooltip-right:before {
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none;
|
|
||||||
border: 6px solid transparent;
|
|
||||||
background: transparent;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Directions */
|
|
||||||
|
|
||||||
.leaflet-tooltip-bottom {
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-top {
|
|
||||||
margin-top: -6px;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-bottom:before,
|
|
||||||
.leaflet-tooltip-top:before {
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -6px;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-top:before {
|
|
||||||
bottom: 0;
|
|
||||||
margin-bottom: -12px;
|
|
||||||
border-top-color: #fff;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-bottom:before {
|
|
||||||
top: 0;
|
|
||||||
margin-top: -12px;
|
|
||||||
margin-left: -6px;
|
|
||||||
border-bottom-color: #fff;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-left {
|
|
||||||
margin-left: -6px;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-right {
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-left:before,
|
|
||||||
.leaflet-tooltip-right:before {
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -6px;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-left:before {
|
|
||||||
right: 0;
|
|
||||||
margin-right: -12px;
|
|
||||||
border-left-color: #fff;
|
|
||||||
}
|
|
||||||
.leaflet-tooltip-right:before {
|
|
||||||
left: 0;
|
|
||||||
margin-left: -12px;
|
|
||||||
border-right-color: #fff;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 443 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.7 MiB |
@ -1,798 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 232 81" style="enable-background:new 0 0 232 81;" xml:space="preserve">
|
|
||||||
<style type="text/css">
|
|
||||||
.st0{fill:#FFFFFF;}
|
|
||||||
.st1{clip-path:url(#SVGID_2_);fill:#308BD6;}
|
|
||||||
.st2{clip-path:url(#SVGID_2_);fill:#318CD6;}
|
|
||||||
.st3{clip-path:url(#SVGID_2_);fill:#328DD7;}
|
|
||||||
.st4{clip-path:url(#SVGID_2_);fill:#338ED7;}
|
|
||||||
.st5{clip-path:url(#SVGID_2_);fill:#348FD8;}
|
|
||||||
.st6{clip-path:url(#SVGID_2_);fill:#3590D8;}
|
|
||||||
.st7{clip-path:url(#SVGID_2_);fill:#3691D9;}
|
|
||||||
.st8{clip-path:url(#SVGID_2_);fill:#3792D9;}
|
|
||||||
.st9{clip-path:url(#SVGID_2_);fill:#3893DA;}
|
|
||||||
.st10{clip-path:url(#SVGID_2_);fill:#3994DA;}
|
|
||||||
.st11{clip-path:url(#SVGID_2_);fill:#3A95DA;}
|
|
||||||
.st12{clip-path:url(#SVGID_2_);fill:#3B96DB;}
|
|
||||||
.st13{clip-path:url(#SVGID_2_);fill:#3C97DB;}
|
|
||||||
.st14{clip-path:url(#SVGID_2_);fill:#3D98DC;}
|
|
||||||
.st15{clip-path:url(#SVGID_2_);fill:#3E99DC;}
|
|
||||||
.st16{clip-path:url(#SVGID_2_);fill:#3F9ADD;}
|
|
||||||
.st17{clip-path:url(#SVGID_2_);fill:#409BDD;}
|
|
||||||
.st18{clip-path:url(#SVGID_2_);fill:#419CDE;}
|
|
||||||
.st19{clip-path:url(#SVGID_2_);fill:#429DDE;}
|
|
||||||
.st20{clip-path:url(#SVGID_2_);fill:#439EDE;}
|
|
||||||
.st21{clip-path:url(#SVGID_2_);fill:#449FDF;}
|
|
||||||
.st22{clip-path:url(#SVGID_2_);fill:#45A0DF;}
|
|
||||||
.st23{clip-path:url(#SVGID_2_);fill:#46A1E0;}
|
|
||||||
.st24{clip-path:url(#SVGID_2_);fill:#47A2E0;}
|
|
||||||
.st25{clip-path:url(#SVGID_2_);fill:#48A4E1;}
|
|
||||||
.st26{clip-path:url(#SVGID_2_);fill:#49A5E1;}
|
|
||||||
.st27{clip-path:url(#SVGID_2_);fill:#4AA6E2;}
|
|
||||||
.st28{clip-path:url(#SVGID_2_);fill:#4BA7E2;}
|
|
||||||
.st29{clip-path:url(#SVGID_2_);fill:#4CA8E3;}
|
|
||||||
.st30{clip-path:url(#SVGID_2_);fill:#4DA9E3;}
|
|
||||||
.st31{clip-path:url(#SVGID_2_);fill:#4EAAE3;}
|
|
||||||
.st32{clip-path:url(#SVGID_2_);fill:#4FABE4;}
|
|
||||||
.st33{clip-path:url(#SVGID_2_);fill:#50ACE4;}
|
|
||||||
.st34{clip-path:url(#SVGID_2_);fill:#51ADE5;}
|
|
||||||
.st35{clip-path:url(#SVGID_2_);fill:#52AEE5;}
|
|
||||||
.st36{clip-path:url(#SVGID_2_);fill:#53AFE6;}
|
|
||||||
.st37{clip-path:url(#SVGID_2_);fill:#54B0E6;}
|
|
||||||
.st38{clip-path:url(#SVGID_2_);fill:#55B1E7;}
|
|
||||||
.st39{clip-path:url(#SVGID_2_);fill:#56B2E7;}
|
|
||||||
.st40{clip-path:url(#SVGID_2_);fill:#57B3E7;}
|
|
||||||
.st41{clip-path:url(#SVGID_2_);fill:#58B4E8;}
|
|
||||||
.st42{clip-path:url(#SVGID_2_);fill:#59B5E8;}
|
|
||||||
.st43{clip-path:url(#SVGID_2_);fill:#5AB6E9;}
|
|
||||||
.st44{clip-path:url(#SVGID_2_);fill:#5BB7E9;}
|
|
||||||
.st45{clip-path:url(#SVGID_2_);fill:#5CB8EA;}
|
|
||||||
.st46{clip-path:url(#SVGID_2_);fill:#5DB9EA;}
|
|
||||||
.st47{clip-path:url(#SVGID_2_);fill:#5EBAEB;}
|
|
||||||
.st48{clip-path:url(#SVGID_2_);fill:#5FBBEB;}
|
|
||||||
.st49{clip-path:url(#SVGID_4_);fill:#2E5E87;}
|
|
||||||
.st50{clip-path:url(#SVGID_4_);fill:#2E5F88;}
|
|
||||||
.st51{clip-path:url(#SVGID_4_);fill:#2F5F89;}
|
|
||||||
.st52{clip-path:url(#SVGID_4_);fill:#2F608A;}
|
|
||||||
.st53{clip-path:url(#SVGID_4_);fill:#30618B;}
|
|
||||||
.st54{clip-path:url(#SVGID_4_);fill:#30628C;}
|
|
||||||
.st55{clip-path:url(#SVGID_4_);fill:#31628D;}
|
|
||||||
.st56{clip-path:url(#SVGID_4_);fill:#31638E;}
|
|
||||||
.st57{clip-path:url(#SVGID_4_);fill:#31648F;}
|
|
||||||
.st58{clip-path:url(#SVGID_4_);fill:#326590;}
|
|
||||||
.st59{clip-path:url(#SVGID_4_);fill:#326591;}
|
|
||||||
.st60{clip-path:url(#SVGID_4_);fill:#336692;}
|
|
||||||
.st61{clip-path:url(#SVGID_4_);fill:#336793;}
|
|
||||||
.st62{clip-path:url(#SVGID_4_);fill:#346894;}
|
|
||||||
.st63{clip-path:url(#SVGID_4_);fill:#346895;}
|
|
||||||
.st64{clip-path:url(#SVGID_4_);fill:#356996;}
|
|
||||||
.st65{clip-path:url(#SVGID_4_);fill:#356A97;}
|
|
||||||
.st66{clip-path:url(#SVGID_4_);fill:#356B98;}
|
|
||||||
.st67{clip-path:url(#SVGID_4_);fill:#366B99;}
|
|
||||||
.st68{clip-path:url(#SVGID_4_);fill:#366C9A;}
|
|
||||||
.st69{clip-path:url(#SVGID_4_);fill:#376D9B;}
|
|
||||||
.st70{clip-path:url(#SVGID_4_);fill:#376E9C;}
|
|
||||||
.st71{clip-path:url(#SVGID_4_);fill:#386E9D;}
|
|
||||||
.st72{clip-path:url(#SVGID_4_);fill:#386F9E;}
|
|
||||||
.st73{clip-path:url(#SVGID_4_);fill:#38709F;}
|
|
||||||
.st74{clip-path:url(#SVGID_4_);fill:#3971A0;}
|
|
||||||
.st75{clip-path:url(#SVGID_4_);fill:#3971A1;}
|
|
||||||
.st76{clip-path:url(#SVGID_4_);fill:#3A72A2;}
|
|
||||||
.st77{clip-path:url(#SVGID_4_);fill:#3A73A3;}
|
|
||||||
.st78{clip-path:url(#SVGID_4_);fill:#3B74A4;}
|
|
||||||
.st79{clip-path:url(#SVGID_4_);fill:#3B74A5;}
|
|
||||||
.st80{clip-path:url(#SVGID_4_);fill:#3C75A7;}
|
|
||||||
.st81{clip-path:url(#SVGID_4_);fill:#3C76A8;}
|
|
||||||
.st82{clip-path:url(#SVGID_4_);fill:#3C76A9;}
|
|
||||||
.st83{clip-path:url(#SVGID_4_);fill:#3D77AA;}
|
|
||||||
.st84{clip-path:url(#SVGID_4_);fill:#3D78AB;}
|
|
||||||
.st85{clip-path:url(#SVGID_4_);fill:#3E79AC;}
|
|
||||||
.st86{clip-path:url(#SVGID_4_);fill:#3E79AD;}
|
|
||||||
.st87{clip-path:url(#SVGID_4_);fill:#3F7AAE;}
|
|
||||||
.st88{clip-path:url(#SVGID_4_);fill:#3F7BAF;}
|
|
||||||
.st89{clip-path:url(#SVGID_4_);fill:#3F7CB0;}
|
|
||||||
.st90{clip-path:url(#SVGID_4_);fill:#407CB1;}
|
|
||||||
.st91{clip-path:url(#SVGID_4_);fill:#407DB2;}
|
|
||||||
.st92{clip-path:url(#SVGID_4_);fill:#417EB3;}
|
|
||||||
.st93{clip-path:url(#SVGID_4_);fill:#417FB4;}
|
|
||||||
.st94{clip-path:url(#SVGID_4_);fill:#427FB5;}
|
|
||||||
.st95{clip-path:url(#SVGID_4_);fill:#4280B6;}
|
|
||||||
.st96{clip-path:url(#SVGID_4_);fill:#4281B7;}
|
|
||||||
.st97{clip-path:url(#SVGID_4_);fill:#4382B8;}
|
|
||||||
.st98{clip-path:url(#SVGID_4_);fill:#4382B9;}
|
|
||||||
.st99{clip-path:url(#SVGID_4_);fill:#4483BA;}
|
|
||||||
.st100{clip-path:url(#SVGID_4_);fill:#4484BB;}
|
|
||||||
.st101{clip-path:url(#SVGID_4_);fill:#4585BC;}
|
|
||||||
.st102{clip-path:url(#SVGID_4_);fill:#4585BD;}
|
|
||||||
.st103{clip-path:url(#SVGID_4_);fill:#4686BE;}
|
|
||||||
.st104{clip-path:url(#SVGID_4_);fill:#4687BF;}
|
|
||||||
.st105{clip-path:url(#SVGID_4_);fill:#4688C0;}
|
|
||||||
.st106{clip-path:url(#SVGID_4_);fill:#4788C1;}
|
|
||||||
.st107{clip-path:url(#SVGID_4_);fill:#4789C2;}
|
|
||||||
.st108{clip-path:url(#SVGID_4_);fill:#488AC3;}
|
|
||||||
.st109{clip-path:url(#SVGID_4_);fill:#488BC4;}
|
|
||||||
.st110{clip-path:url(#SVGID_4_);fill:#498BC5;}
|
|
||||||
.st111{clip-path:url(#SVGID_4_);fill:#498CC6;}
|
|
||||||
.st112{clip-path:url(#SVGID_6_);fill:#4CE8C6;}
|
|
||||||
.st113{clip-path:url(#SVGID_6_);fill:#4BE8C7;}
|
|
||||||
.st114{clip-path:url(#SVGID_6_);fill:#4AE7C7;}
|
|
||||||
.st115{clip-path:url(#SVGID_6_);fill:#49E7C8;}
|
|
||||||
.st116{clip-path:url(#SVGID_6_);fill:#48E6C8;}
|
|
||||||
.st117{clip-path:url(#SVGID_6_);fill:#47E6C9;}
|
|
||||||
.st118{clip-path:url(#SVGID_6_);fill:#46E6C9;}
|
|
||||||
.st119{clip-path:url(#SVGID_6_);fill:#45E5CA;}
|
|
||||||
.st120{clip-path:url(#SVGID_6_);fill:#44E5CB;}
|
|
||||||
.st121{clip-path:url(#SVGID_6_);fill:#43E4CB;}
|
|
||||||
.st122{clip-path:url(#SVGID_6_);fill:#42E4CC;}
|
|
||||||
.st123{clip-path:url(#SVGID_6_);fill:#41E4CC;}
|
|
||||||
.st124{clip-path:url(#SVGID_6_);fill:#40E3CD;}
|
|
||||||
.st125{clip-path:url(#SVGID_6_);fill:#3FE3CE;}
|
|
||||||
.st126{clip-path:url(#SVGID_6_);fill:#3EE2CE;}
|
|
||||||
.st127{clip-path:url(#SVGID_6_);fill:#3DE2CF;}
|
|
||||||
.st128{clip-path:url(#SVGID_6_);fill:#3CE2CF;}
|
|
||||||
.st129{clip-path:url(#SVGID_6_);fill:#3BE1D0;}
|
|
||||||
.st130{clip-path:url(#SVGID_6_);fill:#3AE1D0;}
|
|
||||||
.st131{clip-path:url(#SVGID_6_);fill:#39E0D1;}
|
|
||||||
.st132{clip-path:url(#SVGID_6_);fill:#38E0D2;}
|
|
||||||
.st133{clip-path:url(#SVGID_6_);fill:#37E0D2;}
|
|
||||||
.st134{clip-path:url(#SVGID_6_);fill:#36DFD3;}
|
|
||||||
.st135{clip-path:url(#SVGID_6_);fill:#35DFD3;}
|
|
||||||
.st136{clip-path:url(#SVGID_6_);fill:#34DED4;}
|
|
||||||
.st137{clip-path:url(#SVGID_6_);fill:#33DED5;}
|
|
||||||
.st138{clip-path:url(#SVGID_6_);fill:#31DED5;}
|
|
||||||
.st139{clip-path:url(#SVGID_6_);fill:#30DDD6;}
|
|
||||||
.st140{clip-path:url(#SVGID_6_);fill:#2FDDD6;}
|
|
||||||
.st141{clip-path:url(#SVGID_6_);fill:#2EDCD7;}
|
|
||||||
.st142{clip-path:url(#SVGID_6_);fill:#2DDCD7;}
|
|
||||||
.st143{clip-path:url(#SVGID_6_);fill:#2CDCD8;}
|
|
||||||
.st144{clip-path:url(#SVGID_6_);fill:#2BDBD9;}
|
|
||||||
.st145{clip-path:url(#SVGID_6_);fill:#2ADBD9;}
|
|
||||||
.st146{clip-path:url(#SVGID_6_);fill:#29DADA;}
|
|
||||||
.st147{clip-path:url(#SVGID_6_);fill:#28DADA;}
|
|
||||||
.st148{clip-path:url(#SVGID_6_);fill:#27DADB;}
|
|
||||||
.st149{clip-path:url(#SVGID_6_);fill:#26D9DB;}
|
|
||||||
.st150{clip-path:url(#SVGID_6_);fill:#25D9DC;}
|
|
||||||
.st151{clip-path:url(#SVGID_6_);fill:#24D8DD;}
|
|
||||||
.st152{clip-path:url(#SVGID_6_);fill:#23D8DD;}
|
|
||||||
.st153{clip-path:url(#SVGID_6_);fill:#22D8DE;}
|
|
||||||
.st154{clip-path:url(#SVGID_6_);fill:#21D7DE;}
|
|
||||||
.st155{clip-path:url(#SVGID_6_);fill:#20D7DF;}
|
|
||||||
.st156{clip-path:url(#SVGID_6_);fill:#1FD6E0;}
|
|
||||||
.st157{clip-path:url(#SVGID_6_);fill:#1ED6E0;}
|
|
||||||
.st158{clip-path:url(#SVGID_6_);fill:#1DD6E1;}
|
|
||||||
.st159{clip-path:url(#SVGID_6_);fill:#1CD5E1;}
|
|
||||||
.st160{clip-path:url(#SVGID_6_);fill:#1BD5E2;}
|
|
||||||
.st161{clip-path:url(#SVGID_6_);fill:#1AD4E2;}
|
|
||||||
.st162{clip-path:url(#SVGID_6_);fill:#19D4E3;}
|
|
||||||
.st163{opacity:0.4;}
|
|
||||||
.st164{clip-path:url(#SVGID_8_);fill:#4CE8C6;}
|
|
||||||
.st165{clip-path:url(#SVGID_8_);fill:#4BE8C7;}
|
|
||||||
.st166{clip-path:url(#SVGID_8_);fill:#4AE7C7;}
|
|
||||||
.st167{clip-path:url(#SVGID_8_);fill:#49E7C8;}
|
|
||||||
.st168{clip-path:url(#SVGID_8_);fill:#48E6C8;}
|
|
||||||
.st169{clip-path:url(#SVGID_8_);fill:#47E6C9;}
|
|
||||||
.st170{clip-path:url(#SVGID_8_);fill:#46E6C9;}
|
|
||||||
.st171{clip-path:url(#SVGID_8_);fill:#45E5CA;}
|
|
||||||
.st172{clip-path:url(#SVGID_8_);fill:#44E5CB;}
|
|
||||||
.st173{clip-path:url(#SVGID_8_);fill:#43E4CB;}
|
|
||||||
.st174{clip-path:url(#SVGID_8_);fill:#42E4CC;}
|
|
||||||
.st175{clip-path:url(#SVGID_8_);fill:#41E4CC;}
|
|
||||||
.st176{clip-path:url(#SVGID_8_);fill:#40E3CD;}
|
|
||||||
.st177{clip-path:url(#SVGID_8_);fill:#3FE3CE;}
|
|
||||||
.st178{clip-path:url(#SVGID_8_);fill:#3EE2CE;}
|
|
||||||
.st179{clip-path:url(#SVGID_8_);fill:#3DE2CF;}
|
|
||||||
.st180{clip-path:url(#SVGID_8_);fill:#3CE2CF;}
|
|
||||||
.st181{clip-path:url(#SVGID_8_);fill:#3BE1D0;}
|
|
||||||
.st182{clip-path:url(#SVGID_8_);fill:#3AE1D0;}
|
|
||||||
.st183{clip-path:url(#SVGID_8_);fill:#39E0D1;}
|
|
||||||
.st184{clip-path:url(#SVGID_8_);fill:#38E0D2;}
|
|
||||||
.st185{clip-path:url(#SVGID_8_);fill:#37E0D2;}
|
|
||||||
.st186{clip-path:url(#SVGID_8_);fill:#36DFD3;}
|
|
||||||
.st187{clip-path:url(#SVGID_8_);fill:#35DFD3;}
|
|
||||||
.st188{clip-path:url(#SVGID_8_);fill:#34DED4;}
|
|
||||||
.st189{clip-path:url(#SVGID_8_);fill:#33DED5;}
|
|
||||||
.st190{clip-path:url(#SVGID_8_);fill:#31DED5;}
|
|
||||||
.st191{clip-path:url(#SVGID_8_);fill:#30DDD6;}
|
|
||||||
.st192{clip-path:url(#SVGID_8_);fill:#2FDDD6;}
|
|
||||||
.st193{clip-path:url(#SVGID_8_);fill:#2EDCD7;}
|
|
||||||
.st194{clip-path:url(#SVGID_8_);fill:#2DDCD7;}
|
|
||||||
.st195{clip-path:url(#SVGID_8_);fill:#2CDCD8;}
|
|
||||||
.st196{clip-path:url(#SVGID_8_);fill:#2BDBD9;}
|
|
||||||
.st197{clip-path:url(#SVGID_8_);fill:#2ADBD9;}
|
|
||||||
.st198{clip-path:url(#SVGID_8_);fill:#29DADA;}
|
|
||||||
.st199{clip-path:url(#SVGID_8_);fill:#28DADA;}
|
|
||||||
.st200{clip-path:url(#SVGID_8_);fill:#27DADB;}
|
|
||||||
.st201{clip-path:url(#SVGID_8_);fill:#26D9DB;}
|
|
||||||
.st202{clip-path:url(#SVGID_8_);fill:#25D9DC;}
|
|
||||||
.st203{clip-path:url(#SVGID_8_);fill:#24D8DD;}
|
|
||||||
.st204{clip-path:url(#SVGID_8_);fill:#23D8DD;}
|
|
||||||
.st205{clip-path:url(#SVGID_8_);fill:#22D8DE;}
|
|
||||||
.st206{clip-path:url(#SVGID_8_);fill:#21D7DE;}
|
|
||||||
.st207{clip-path:url(#SVGID_8_);fill:#20D7DF;}
|
|
||||||
.st208{clip-path:url(#SVGID_8_);fill:#1FD6E0;}
|
|
||||||
.st209{clip-path:url(#SVGID_8_);fill:#1ED6E0;}
|
|
||||||
.st210{clip-path:url(#SVGID_8_);fill:#1DD6E1;}
|
|
||||||
.st211{clip-path:url(#SVGID_8_);fill:#1CD5E1;}
|
|
||||||
.st212{clip-path:url(#SVGID_8_);fill:#1BD5E2;}
|
|
||||||
.st213{clip-path:url(#SVGID_8_);fill:#1AD4E2;}
|
|
||||||
.st214{clip-path:url(#SVGID_8_);fill:#19D4E3;}
|
|
||||||
.st215{opacity:0.5;}
|
|
||||||
.st216{clip-path:url(#SVGID_10_);fill:#316490;}
|
|
||||||
.st217{clip-path:url(#SVGID_10_);fill:#316591;}
|
|
||||||
.st218{clip-path:url(#SVGID_10_);fill:#326692;}
|
|
||||||
.st219{clip-path:url(#SVGID_10_);fill:#326693;}
|
|
||||||
.st220{clip-path:url(#SVGID_10_);fill:#336794;}
|
|
||||||
.st221{clip-path:url(#SVGID_10_);fill:#336895;}
|
|
||||||
.st222{clip-path:url(#SVGID_10_);fill:#346996;}
|
|
||||||
.st223{clip-path:url(#SVGID_10_);fill:#346997;}
|
|
||||||
.st224{clip-path:url(#SVGID_10_);fill:#356A98;}
|
|
||||||
.st225{clip-path:url(#SVGID_10_);fill:#356B99;}
|
|
||||||
.st226{clip-path:url(#SVGID_10_);fill:#366C9A;}
|
|
||||||
.st227{clip-path:url(#SVGID_10_);fill:#366C9B;}
|
|
||||||
.st228{clip-path:url(#SVGID_10_);fill:#366D9C;}
|
|
||||||
.st229{clip-path:url(#SVGID_10_);fill:#376E9D;}
|
|
||||||
.st230{clip-path:url(#SVGID_10_);fill:#376F9E;}
|
|
||||||
.st231{clip-path:url(#SVGID_10_);fill:#386F9F;}
|
|
||||||
.st232{clip-path:url(#SVGID_10_);fill:#3870A0;}
|
|
||||||
.st233{clip-path:url(#SVGID_10_);fill:#3971A1;}
|
|
||||||
.st234{clip-path:url(#SVGID_10_);fill:#3972A2;}
|
|
||||||
.st235{clip-path:url(#SVGID_10_);fill:#3A72A3;}
|
|
||||||
.st236{clip-path:url(#SVGID_10_);fill:#3A73A4;}
|
|
||||||
.st237{clip-path:url(#SVGID_10_);fill:#3B74A5;}
|
|
||||||
.st238{clip-path:url(#SVGID_10_);fill:#3B75A6;}
|
|
||||||
.st239{clip-path:url(#SVGID_10_);fill:#3B75A7;}
|
|
||||||
.st240{clip-path:url(#SVGID_10_);fill:#3C76A8;}
|
|
||||||
.st241{clip-path:url(#SVGID_10_);fill:#3C77A9;}
|
|
||||||
.st242{clip-path:url(#SVGID_10_);fill:#3D78AA;}
|
|
||||||
.st243{clip-path:url(#SVGID_10_);fill:#3D78AC;}
|
|
||||||
.st244{clip-path:url(#SVGID_10_);fill:#3E79AD;}
|
|
||||||
.st245{clip-path:url(#SVGID_10_);fill:#3E7AAE;}
|
|
||||||
.st246{clip-path:url(#SVGID_10_);fill:#3F7BAF;}
|
|
||||||
.st247{clip-path:url(#SVGID_10_);fill:#3F7BB0;}
|
|
||||||
.st248{clip-path:url(#SVGID_10_);fill:#3F7CB1;}
|
|
||||||
.st249{clip-path:url(#SVGID_10_);fill:#407DB2;}
|
|
||||||
.st250{clip-path:url(#SVGID_10_);fill:#407EB3;}
|
|
||||||
.st251{clip-path:url(#SVGID_10_);fill:#417EB4;}
|
|
||||||
.st252{clip-path:url(#SVGID_10_);fill:#417FB5;}
|
|
||||||
.st253{clip-path:url(#SVGID_10_);fill:#4280B6;}
|
|
||||||
.st254{clip-path:url(#SVGID_10_);fill:#4281B7;}
|
|
||||||
.st255{clip-path:url(#SVGID_10_);fill:#4381B8;}
|
|
||||||
.st256{clip-path:url(#SVGID_10_);fill:#4382B9;}
|
|
||||||
.st257{clip-path:url(#SVGID_10_);fill:#4483BA;}
|
|
||||||
.st258{clip-path:url(#SVGID_10_);fill:#4484BB;}
|
|
||||||
.st259{clip-path:url(#SVGID_10_);fill:#4484BC;}
|
|
||||||
.st260{clip-path:url(#SVGID_10_);fill:#4585BD;}
|
|
||||||
.st261{clip-path:url(#SVGID_10_);fill:#4586BE;}
|
|
||||||
.st262{clip-path:url(#SVGID_10_);fill:#4687BF;}
|
|
||||||
.st263{clip-path:url(#SVGID_10_);fill:#4687C0;}
|
|
||||||
.st264{clip-path:url(#SVGID_10_);fill:#4788C1;}
|
|
||||||
.st265{clip-path:url(#SVGID_10_);fill:#4789C2;}
|
|
||||||
.st266{clip-path:url(#SVGID_10_);fill:#488AC3;}
|
|
||||||
.st267{clip-path:url(#SVGID_10_);fill:#488AC4;}
|
|
||||||
.st268{clip-path:url(#SVGID_10_);fill:#498BC5;}
|
|
||||||
.st269{clip-path:url(#SVGID_10_);fill:#498CC6;}
|
|
||||||
.st270{clip-path:url(#SVGID_12_);fill:#5FBBEB;}
|
|
||||||
.st271{clip-path:url(#SVGID_12_);fill:#5EBAEB;}
|
|
||||||
.st272{clip-path:url(#SVGID_12_);fill:#5DB9EA;}
|
|
||||||
.st273{clip-path:url(#SVGID_12_);fill:#5CB8EA;}
|
|
||||||
.st274{clip-path:url(#SVGID_12_);fill:#5BB7E9;}
|
|
||||||
.st275{clip-path:url(#SVGID_12_);fill:#5AB6E9;}
|
|
||||||
.st276{clip-path:url(#SVGID_12_);fill:#59B5E8;}
|
|
||||||
.st277{clip-path:url(#SVGID_12_);fill:#58B4E8;}
|
|
||||||
.st278{clip-path:url(#SVGID_12_);fill:#57B3E7;}
|
|
||||||
.st279{clip-path:url(#SVGID_12_);fill:#56B2E7;}
|
|
||||||
.st280{clip-path:url(#SVGID_12_);fill:#55B1E7;}
|
|
||||||
.st281{clip-path:url(#SVGID_12_);fill:#54B0E6;}
|
|
||||||
.st282{clip-path:url(#SVGID_12_);fill:#53AFE6;}
|
|
||||||
.st283{clip-path:url(#SVGID_12_);fill:#52AEE5;}
|
|
||||||
.st284{clip-path:url(#SVGID_12_);fill:#51ADE5;}
|
|
||||||
.st285{clip-path:url(#SVGID_12_);fill:#50ACE4;}
|
|
||||||
.st286{clip-path:url(#SVGID_12_);fill:#4FABE4;}
|
|
||||||
.st287{clip-path:url(#SVGID_12_);fill:#4EAAE3;}
|
|
||||||
.st288{clip-path:url(#SVGID_12_);fill:#4DA9E3;}
|
|
||||||
.st289{clip-path:url(#SVGID_12_);fill:#4CA8E3;}
|
|
||||||
.st290{clip-path:url(#SVGID_12_);fill:#4BA7E2;}
|
|
||||||
.st291{clip-path:url(#SVGID_12_);fill:#4AA6E2;}
|
|
||||||
.st292{clip-path:url(#SVGID_12_);fill:#49A5E1;}
|
|
||||||
.st293{clip-path:url(#SVGID_12_);fill:#48A4E1;}
|
|
||||||
.st294{clip-path:url(#SVGID_12_);fill:#47A2E0;}
|
|
||||||
.st295{clip-path:url(#SVGID_12_);fill:#46A1E0;}
|
|
||||||
.st296{clip-path:url(#SVGID_12_);fill:#45A0DF;}
|
|
||||||
.st297{clip-path:url(#SVGID_12_);fill:#449FDF;}
|
|
||||||
.st298{clip-path:url(#SVGID_12_);fill:#439EDE;}
|
|
||||||
.st299{clip-path:url(#SVGID_12_);fill:#429DDE;}
|
|
||||||
.st300{clip-path:url(#SVGID_12_);fill:#419CDE;}
|
|
||||||
.st301{clip-path:url(#SVGID_12_);fill:#409BDD;}
|
|
||||||
.st302{clip-path:url(#SVGID_12_);fill:#3F9ADD;}
|
|
||||||
.st303{clip-path:url(#SVGID_12_);fill:#3E99DC;}
|
|
||||||
.st304{clip-path:url(#SVGID_12_);fill:#3D98DC;}
|
|
||||||
.st305{clip-path:url(#SVGID_12_);fill:#3C97DB;}
|
|
||||||
.st306{clip-path:url(#SVGID_12_);fill:#3B96DB;}
|
|
||||||
.st307{clip-path:url(#SVGID_12_);fill:#3A95DA;}
|
|
||||||
.st308{clip-path:url(#SVGID_12_);fill:#3994DA;}
|
|
||||||
.st309{clip-path:url(#SVGID_12_);fill:#3893DA;}
|
|
||||||
.st310{clip-path:url(#SVGID_12_);fill:#3792D9;}
|
|
||||||
.st311{clip-path:url(#SVGID_12_);fill:#3691D9;}
|
|
||||||
.st312{clip-path:url(#SVGID_12_);fill:#3590D8;}
|
|
||||||
.st313{clip-path:url(#SVGID_12_);fill:#348FD8;}
|
|
||||||
.st314{clip-path:url(#SVGID_12_);fill:#338ED7;}
|
|
||||||
.st315{clip-path:url(#SVGID_12_);fill:#328DD7;}
|
|
||||||
.st316{clip-path:url(#SVGID_12_);fill:#318CD6;}
|
|
||||||
.st317{clip-path:url(#SVGID_12_);fill:#308BD6;}
|
|
||||||
.st318{fill:#316490;}
|
|
||||||
</style>
|
|
||||||
<path class="st0" d="M224,81H8c-4.4,0-8-3.6-8-8V8c0-4.4,3.6-8,8-8h216c4.4,0,8,3.6,8,8v65C232,77.4,228.4,81,224,81z"/>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<polygon id="SVGID_1_" points="15.2,15 15.2,62.9 59.2,56 59.2,8.1 "/>
|
|
||||||
</defs>
|
|
||||||
<clipPath id="SVGID_2_">
|
|
||||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<polygon class="st1" points="56.7,62.9 59.2,56 59.2,62.9 "/>
|
|
||||||
<polygon class="st1" points="55.7,62.9 59.2,53.1 59.2,56 56.7,62.9 "/>
|
|
||||||
<polygon class="st2" points="54.6,62.9 59.2,50.3 59.2,53.1 55.7,62.9 "/>
|
|
||||||
<polygon class="st3" points="53.6,62.9 59.2,47.4 59.2,50.3 54.6,62.9 "/>
|
|
||||||
<polygon class="st4" points="52.6,62.9 59.2,44.6 59.2,47.4 53.6,62.9 "/>
|
|
||||||
<polygon class="st5" points="51.5,62.9 59.2,41.7 59.2,44.6 52.6,62.9 "/>
|
|
||||||
<polygon class="st6" points="50.5,62.9 59.2,38.9 59.2,41.7 51.5,62.9 "/>
|
|
||||||
<polygon class="st7" points="49.4,62.9 59.2,36 59.2,38.9 50.5,62.9 "/>
|
|
||||||
<polygon class="st8" points="48.4,62.9 59.2,33.1 59.2,36 49.4,62.9 "/>
|
|
||||||
<polygon class="st9" points="47.4,62.9 59.2,30.3 59.2,33.1 48.4,62.9 "/>
|
|
||||||
<polygon class="st10" points="46.3,62.9 59.2,27.4 59.2,30.3 47.4,62.9 "/>
|
|
||||||
<polygon class="st11" points="45.3,62.9 59.2,24.6 59.2,27.4 46.3,62.9 "/>
|
|
||||||
<polygon class="st12" points="44.2,62.9 59.2,21.7 59.2,24.6 45.3,62.9 "/>
|
|
||||||
<polygon class="st13" points="43.2,62.9 59.2,18.9 59.2,21.7 44.2,62.9 "/>
|
|
||||||
<polygon class="st14" points="42.2,62.9 59.2,16 59.2,18.9 43.2,62.9 "/>
|
|
||||||
<polygon class="st15" points="41.1,62.9 59.2,13.2 59.2,16 42.2,62.9 "/>
|
|
||||||
<polygon class="st16" points="40.1,62.9 59.2,10.3 59.2,13.2 41.1,62.9 "/>
|
|
||||||
<polygon class="st17" points="39,62.9 59,8.1 59.2,8.1 59.2,10.3 40.1,62.9 "/>
|
|
||||||
<polygon class="st18" points="38,62.9 57.9,8.1 59,8.1 39,62.9 "/>
|
|
||||||
<polygon class="st19" points="37,62.9 56.9,8.1 57.9,8.1 38,62.9 "/>
|
|
||||||
<polygon class="st20" points="35.9,62.9 55.9,8.1 56.9,8.1 37,62.9 "/>
|
|
||||||
<polygon class="st21" points="34.9,62.9 54.8,8.1 55.9,8.1 35.9,62.9 "/>
|
|
||||||
<polygon class="st22" points="33.8,62.9 53.8,8.1 54.8,8.1 34.9,62.9 "/>
|
|
||||||
<polygon class="st23" points="32.8,62.9 52.7,8.1 53.8,8.1 33.8,62.9 "/>
|
|
||||||
<polygon class="st24" points="31.8,62.9 51.7,8.1 52.7,8.1 32.8,62.9 "/>
|
|
||||||
<polygon class="st25" points="30.7,62.9 50.7,8.1 51.7,8.1 31.8,62.9 "/>
|
|
||||||
<polygon class="st26" points="29.7,62.9 49.6,8.1 50.7,8.1 30.7,62.9 "/>
|
|
||||||
<polygon class="st27" points="28.7,62.9 48.6,8.1 49.6,8.1 29.7,62.9 "/>
|
|
||||||
<polygon class="st28" points="27.6,62.9 47.5,8.1 48.6,8.1 28.7,62.9 "/>
|
|
||||||
<polygon class="st29" points="26.6,62.9 46.5,8.1 47.5,8.1 27.6,62.9 "/>
|
|
||||||
<polygon class="st30" points="25.5,62.9 45.5,8.1 46.5,8.1 26.6,62.9 "/>
|
|
||||||
<polygon class="st31" points="24.5,62.9 44.4,8.1 45.5,8.1 25.5,62.9 "/>
|
|
||||||
<polygon class="st32" points="23.5,62.9 43.4,8.1 44.4,8.1 24.5,62.9 "/>
|
|
||||||
<polygon class="st33" points="22.4,62.9 42.3,8.1 43.4,8.1 23.5,62.9 "/>
|
|
||||||
<polygon class="st34" points="21.4,62.9 41.3,8.1 42.3,8.1 22.4,62.9 "/>
|
|
||||||
<polygon class="st35" points="20.3,62.9 40.3,8.1 41.3,8.1 21.4,62.9 "/>
|
|
||||||
<polygon class="st36" points="19.3,62.9 39.2,8.1 40.3,8.1 20.3,62.9 "/>
|
|
||||||
<polygon class="st37" points="18.3,62.9 38.2,8.1 39.2,8.1 19.3,62.9 "/>
|
|
||||||
<polygon class="st38" points="17.2,62.9 37.1,8.1 38.2,8.1 18.3,62.9 "/>
|
|
||||||
<polygon class="st39" points="16.2,62.9 36.1,8.1 37.1,8.1 17.2,62.9 "/>
|
|
||||||
<polygon class="st40" points="15.2,62.7 35.1,8.1 36.1,8.1 16.2,62.9 15.2,62.9 "/>
|
|
||||||
<polygon class="st41" points="15.2,59.9 34,8.1 35.1,8.1 15.2,62.7 "/>
|
|
||||||
<polygon class="st42" points="15.2,57 33,8.1 34,8.1 15.2,59.9 "/>
|
|
||||||
<polygon class="st43" points="15.2,54.2 32,8.1 33,8.1 15.2,57 "/>
|
|
||||||
<polygon class="st44" points="15.2,51.3 30.9,8.1 32,8.1 15.2,54.2 "/>
|
|
||||||
<polygon class="st45" points="15.2,48.5 29.9,8.1 30.9,8.1 15.2,51.3 "/>
|
|
||||||
<polygon class="st46" points="15.2,45.6 28.8,8.1 29.9,8.1 15.2,48.5 "/>
|
|
||||||
<polygon class="st47" points="15.2,42.7 27.8,8.1 28.8,8.1 15.2,45.6 "/>
|
|
||||||
<polygon class="st48" points="15.2,39.9 26.8,8.1 27.8,8.1 15.2,42.7 "/>
|
|
||||||
<polygon class="st48" points="26.8,8.1 15.2,39.9 15.2,8.1 "/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<polygon id="SVGID_3_" points="83,68.7 83,20.8 59.2,8.1 59.2,56 "/>
|
|
||||||
</defs>
|
|
||||||
<clipPath id="SVGID_4_">
|
|
||||||
<use xlink:href="#SVGID_3_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<polygon class="st49" points="83,20.8 78.4,8.1 83,8.1 "/>
|
|
||||||
<polygon class="st49" points="83,22 77.9,8.1 78.4,8.1 83,20.8 "/>
|
|
||||||
<polygon class="st50" points="83,23.1 77.5,8.1 77.9,8.1 83,22 "/>
|
|
||||||
<polygon class="st51" points="83,24.3 77.1,8.1 77.5,8.1 83,23.1 "/>
|
|
||||||
<polygon class="st52" points="83,25.4 76.7,8.1 77.1,8.1 83,24.3 "/>
|
|
||||||
<polygon class="st53" points="83,26.6 76.3,8.1 76.7,8.1 83,25.4 "/>
|
|
||||||
<polygon class="st54" points="83,27.7 75.9,8.1 76.3,8.1 83,26.6 "/>
|
|
||||||
<polygon class="st55" points="83,28.8 75.4,8.1 75.9,8.1 83,27.7 "/>
|
|
||||||
<polygon class="st56" points="83,30 75,8.1 75.4,8.1 83,28.8 "/>
|
|
||||||
<polygon class="st57" points="83,31.1 74.6,8.1 75,8.1 83,30 "/>
|
|
||||||
<polygon class="st58" points="83,32.3 74.2,8.1 74.6,8.1 83,31.1 "/>
|
|
||||||
<polygon class="st59" points="83,33.4 73.8,8.1 74.2,8.1 83,32.3 "/>
|
|
||||||
<polygon class="st60" points="83,34.6 73.4,8.1 73.8,8.1 83,33.4 "/>
|
|
||||||
<polygon class="st61" points="83,35.7 72.9,8.1 73.4,8.1 83,34.6 "/>
|
|
||||||
<polygon class="st62" points="83,36.9 72.5,8.1 72.9,8.1 83,35.7 "/>
|
|
||||||
<polygon class="st63" points="83,38 72.1,8.1 72.5,8.1 83,36.9 "/>
|
|
||||||
<polygon class="st64" points="83,39.1 71.7,8.1 72.1,8.1 83,38 "/>
|
|
||||||
<polygon class="st65" points="83,40.3 71.3,8.1 71.7,8.1 83,39.1 "/>
|
|
||||||
<polygon class="st66" points="83,41.4 70.9,8.1 71.3,8.1 83,40.3 "/>
|
|
||||||
<polygon class="st67" points="83,42.6 70.4,8.1 70.9,8.1 83,41.4 "/>
|
|
||||||
<polygon class="st68" points="83,43.7 70,8.1 70.4,8.1 83,42.6 "/>
|
|
||||||
<polygon class="st69" points="83,44.9 69.6,8.1 70,8.1 83,43.7 "/>
|
|
||||||
<polygon class="st70" points="83,46 69.2,8.1 69.6,8.1 83,44.9 "/>
|
|
||||||
<polygon class="st71" points="83,47.2 68.8,8.1 69.2,8.1 83,46 "/>
|
|
||||||
<polygon class="st72" points="83,48.3 68.4,8.1 68.8,8.1 83,47.2 "/>
|
|
||||||
<polygon class="st73" points="83,49.5 67.9,8.1 68.4,8.1 83,48.3 "/>
|
|
||||||
<polygon class="st74" points="83,50.6 67.5,8.1 67.9,8.1 83,49.5 "/>
|
|
||||||
<polygon class="st75" points="83,51.7 67.1,8.1 67.5,8.1 83,50.6 "/>
|
|
||||||
<polygon class="st76" points="83,52.9 66.7,8.1 67.1,8.1 83,51.7 "/>
|
|
||||||
<polygon class="st77" points="83,54 66.3,8.1 66.7,8.1 83,52.9 "/>
|
|
||||||
<polygon class="st78" points="83,55.2 65.9,8.1 66.3,8.1 83,54 "/>
|
|
||||||
<polygon class="st79" points="83,56.3 65.4,8.1 65.9,8.1 83,55.2 "/>
|
|
||||||
<polygon class="st80" points="83,57.5 65,8.1 65.4,8.1 83,56.3 "/>
|
|
||||||
<polygon class="st81" points="83,58.6 64.6,8.1 65,8.1 83,57.5 "/>
|
|
||||||
<polygon class="st82" points="83,59.8 64.2,8.1 64.6,8.1 83,58.6 "/>
|
|
||||||
<polygon class="st83" points="83,60.9 63.8,8.1 64.2,8.1 83,59.8 "/>
|
|
||||||
<polygon class="st84" points="83,62 63.3,8.1 63.8,8.1 83,60.9 "/>
|
|
||||||
<polygon class="st85" points="83,63.2 62.9,8.1 63.3,8.1 83,62 "/>
|
|
||||||
<polygon class="st86" points="83,64.3 62.5,8.1 62.9,8.1 83,63.2 "/>
|
|
||||||
<polygon class="st87" points="83,65.5 62.1,8.1 62.5,8.1 83,64.3 "/>
|
|
||||||
<polygon class="st88" points="83,66.6 61.7,8.1 62.1,8.1 83,65.5 "/>
|
|
||||||
<polygon class="st89" points="83,67.8 61.3,8.1 61.7,8.1 83,66.6 "/>
|
|
||||||
<polygon class="st90" points="82.9,68.7 60.8,8.1 61.3,8.1 83,67.8 83,68.7 "/>
|
|
||||||
<polygon class="st91" points="82.5,68.7 60.4,8.1 60.8,8.1 82.9,68.7 "/>
|
|
||||||
<polygon class="st92" points="82.1,68.7 60,8.1 60.4,8.1 82.5,68.7 "/>
|
|
||||||
<polygon class="st93" points="81.6,68.7 59.6,8.1 60,8.1 82.1,68.7 "/>
|
|
||||||
<polygon class="st94" points="81.2,68.7 59.2,8.1 59.2,8.1 59.6,8.1 81.6,68.7 "/>
|
|
||||||
<polygon class="st95" points="80.8,68.7 59.2,9.3 59.2,8.1 81.2,68.7 "/>
|
|
||||||
<polygon class="st96" points="80.4,68.7 59.2,10.4 59.2,9.3 80.8,68.7 "/>
|
|
||||||
<polygon class="st97" points="80,68.7 59.2,11.6 59.2,10.4 80.4,68.7 "/>
|
|
||||||
<polygon class="st98" points="79.6,68.7 59.2,12.7 59.2,11.6 80,68.7 "/>
|
|
||||||
<polygon class="st99" points="79.1,68.7 59.2,13.8 59.2,12.7 79.6,68.7 "/>
|
|
||||||
<polygon class="st100" points="78.7,68.7 59.2,15 59.2,13.8 79.1,68.7 "/>
|
|
||||||
<polygon class="st101" points="78.3,68.7 59.2,16.1 59.2,15 78.7,68.7 "/>
|
|
||||||
<polygon class="st102" points="77.9,68.7 59.2,17.3 59.2,16.1 78.3,68.7 "/>
|
|
||||||
<polygon class="st103" points="77.5,68.7 59.2,18.4 59.2,17.3 77.9,68.7 "/>
|
|
||||||
<polygon class="st104" points="77.1,68.7 59.2,19.6 59.2,18.4 77.5,68.7 "/>
|
|
||||||
<polygon class="st105" points="76.6,68.7 59.2,20.7 59.2,19.6 77.1,68.7 "/>
|
|
||||||
<polygon class="st106" points="76.2,68.7 59.2,21.9 59.2,20.7 76.6,68.7 "/>
|
|
||||||
<polygon class="st107" points="75.8,68.7 59.2,23 59.2,21.9 76.2,68.7 "/>
|
|
||||||
<polygon class="st108" points="75.4,68.7 59.2,24.1 59.2,23 75.8,68.7 "/>
|
|
||||||
<polygon class="st109" points="75,68.7 59.2,25.3 59.2,24.1 75.4,68.7 "/>
|
|
||||||
<polygon class="st110" points="74.6,68.7 59.2,26.4 59.2,25.3 75,68.7 "/>
|
|
||||||
<polygon class="st111" points="74.1,68.7 59.2,27.6 59.2,26.4 74.6,68.7 "/>
|
|
||||||
<polygon class="st111" points="59.2,27.6 74.1,68.7 59.2,68.7 "/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<polygon id="SVGID_5_" points="39,75.5 83,68.7 59.2,56 15.2,62.9 "/>
|
|
||||||
</defs>
|
|
||||||
<clipPath id="SVGID_6_">
|
|
||||||
<use xlink:href="#SVGID_5_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st112" d="M83,75.5v-6.9V75.5z"/>
|
|
||||||
<rect x="82.1" y="56" class="st112" width="0.9" height="19.5"/>
|
|
||||||
<rect x="81.2" y="56" class="st113" width="0.9" height="19.5"/>
|
|
||||||
<rect x="80.3" y="56" class="st114" width="0.9" height="19.5"/>
|
|
||||||
<rect x="79.4" y="56" class="st115" width="0.9" height="19.5"/>
|
|
||||||
<rect x="78.5" y="56" class="st116" width="0.9" height="19.5"/>
|
|
||||||
<rect x="77.6" y="56" class="st117" width="0.9" height="19.5"/>
|
|
||||||
<rect x="76.7" y="56" class="st118" width="0.9" height="19.5"/>
|
|
||||||
<rect x="75.8" y="56" class="st119" width="0.9" height="19.5"/>
|
|
||||||
<rect x="74.9" y="56" class="st120" width="0.9" height="19.5"/>
|
|
||||||
<rect x="74" y="56" class="st121" width="0.9" height="19.5"/>
|
|
||||||
<rect x="73.1" y="56" class="st122" width="0.9" height="19.5"/>
|
|
||||||
<rect x="72.2" y="56" class="st123" width="0.9" height="19.5"/>
|
|
||||||
<rect x="71.3" y="56" class="st124" width="0.9" height="19.5"/>
|
|
||||||
<rect x="70.4" y="56" class="st125" width="0.9" height="19.5"/>
|
|
||||||
<rect x="69.5" y="56" class="st126" width="0.9" height="19.5"/>
|
|
||||||
<rect x="68.6" y="56" class="st127" width="0.9" height="19.5"/>
|
|
||||||
<rect x="67.7" y="56" class="st128" width="0.9" height="19.5"/>
|
|
||||||
<rect x="66.8" y="56" class="st129" width="0.9" height="19.5"/>
|
|
||||||
<rect x="65.9" y="56" class="st130" width="0.9" height="19.5"/>
|
|
||||||
<rect x="65" y="56" class="st131" width="0.9" height="19.5"/>
|
|
||||||
<rect x="64.1" y="56" class="st132" width="0.9" height="19.5"/>
|
|
||||||
<rect x="63.2" y="56" class="st133" width="0.9" height="19.5"/>
|
|
||||||
<rect x="62.3" y="56" class="st134" width="0.9" height="19.5"/>
|
|
||||||
<rect x="61.4" y="56" class="st135" width="0.9" height="19.5"/>
|
|
||||||
<rect x="60.5" y="56" class="st136" width="0.9" height="19.5"/>
|
|
||||||
<rect x="59.6" y="56" class="st137" width="0.9" height="19.5"/>
|
|
||||||
<rect x="58.7" y="56" class="st138" width="0.9" height="19.5"/>
|
|
||||||
<rect x="57.8" y="56" class="st139" width="0.9" height="19.5"/>
|
|
||||||
<rect x="56.9" y="56" class="st140" width="0.9" height="19.5"/>
|
|
||||||
<rect x="56" y="56" class="st141" width="0.9" height="19.5"/>
|
|
||||||
<rect x="55.1" y="56" class="st142" width="0.9" height="19.5"/>
|
|
||||||
<rect x="54.2" y="56" class="st143" width="0.9" height="19.5"/>
|
|
||||||
<rect x="53.3" y="56" class="st144" width="0.9" height="19.5"/>
|
|
||||||
<rect x="52.4" y="56" class="st145" width="0.9" height="19.5"/>
|
|
||||||
<rect x="51.5" y="56" class="st146" width="0.9" height="19.5"/>
|
|
||||||
<rect x="50.6" y="56" class="st147" width="0.9" height="19.5"/>
|
|
||||||
<rect x="49.7" y="56" class="st148" width="0.9" height="19.5"/>
|
|
||||||
<rect x="48.8" y="56" class="st149" width="0.9" height="19.5"/>
|
|
||||||
<rect x="47.9" y="56" class="st150" width="0.9" height="19.5"/>
|
|
||||||
<rect x="47" y="56" class="st151" width="0.9" height="19.5"/>
|
|
||||||
<rect x="46.1" y="56" class="st152" width="0.9" height="19.5"/>
|
|
||||||
<rect x="45.2" y="56" class="st153" width="0.9" height="19.5"/>
|
|
||||||
<rect x="44.3" y="56" class="st154" width="0.9" height="19.5"/>
|
|
||||||
<rect x="43.4" y="56" class="st155" width="0.9" height="19.5"/>
|
|
||||||
<rect x="42.5" y="56" class="st156" width="0.9" height="19.5"/>
|
|
||||||
<rect x="41.6" y="56" class="st157" width="0.9" height="19.5"/>
|
|
||||||
<rect x="40.7" y="56" class="st158" width="0.9" height="19.5"/>
|
|
||||||
<rect x="39.8" y="56" class="st159" width="0.9" height="19.5"/>
|
|
||||||
<rect x="38.9" y="56" class="st160" width="0.9" height="19.5"/>
|
|
||||||
<rect x="38" y="56" class="st161" width="0.9" height="19.5"/>
|
|
||||||
<rect x="37.1" y="56" class="st162" width="0.9" height="19.5"/>
|
|
||||||
<rect x="15.2" y="56" class="st162" width="21.9" height="19.5"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g class="st163">
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<polygon id="SVGID_7_" points="39,27.6 15.2,15 15.2,62.9 39,75.5 "/>
|
|
||||||
</defs>
|
|
||||||
<clipPath id="SVGID_8_">
|
|
||||||
<use xlink:href="#SVGID_7_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<polygon class="st164" points="37.7,75.5 39,73.7 39,75.5 "/>
|
|
||||||
<polygon class="st165" points="36.4,75.5 39,71.8 39,73.7 37.7,75.5 "/>
|
|
||||||
<polygon class="st166" points="35.1,75.5 39,70 39,71.8 36.4,75.5 "/>
|
|
||||||
<polygon class="st167" points="33.8,75.5 39,68.1 39,70 35.1,75.5 "/>
|
|
||||||
<polygon class="st168" points="32.5,75.5 39,66.2 39,68.1 33.8,75.5 "/>
|
|
||||||
<polygon class="st169" points="31.9,75.5 31.4,75.2 39,64.4 39,66.2 32.5,75.5 "/>
|
|
||||||
<polygon class="st170" points="31.4,75.2 30.5,74.6 39,62.5 39,64.4 "/>
|
|
||||||
<polygon class="st171" points="30.5,74.6 29.7,74 39,60.7 39,62.5 "/>
|
|
||||||
<polygon class="st172" points="29.7,74 28.8,73.4 39,58.8 39,60.7 "/>
|
|
||||||
<polygon class="st173" points="28.8,73.4 27.9,72.8 39,57 39,58.8 "/>
|
|
||||||
<polygon class="st174" points="27.9,72.8 27.1,72.1 39,55.1 39,57 "/>
|
|
||||||
<polygon class="st175" points="27.1,72.1 26.2,71.5 39,53.3 39,55.1 "/>
|
|
||||||
<polygon class="st176" points="26.2,71.5 25.3,70.9 39,51.4 39,53.3 "/>
|
|
||||||
<polygon class="st177" points="25.3,70.9 24.4,70.3 39,49.6 39,51.4 "/>
|
|
||||||
<polygon class="st178" points="24.4,70.3 23.6,69.7 39,47.7 39,49.6 "/>
|
|
||||||
<polygon class="st179" points="23.6,69.7 22.7,69.1 39,45.9 39,47.7 "/>
|
|
||||||
<polygon class="st180" points="22.7,69.1 21.8,68.5 39,44 39,45.9 "/>
|
|
||||||
<polygon class="st181" points="21.8,68.5 21,67.9 39,42.2 39,44 "/>
|
|
||||||
<polygon class="st182" points="21,67.9 20.1,67.3 39,40.3 39,42.2 "/>
|
|
||||||
<polygon class="st183" points="20.1,67.3 19.2,66.7 39,38.4 39,40.3 "/>
|
|
||||||
<polygon class="st184" points="19.2,66.7 18.4,66 39,36.6 39,38.4 "/>
|
|
||||||
<polygon class="st185" points="18.4,66 17.5,65.4 39,34.7 39,36.6 "/>
|
|
||||||
<polygon class="st186" points="17.5,65.4 16.6,64.8 39,32.9 39,34.7 "/>
|
|
||||||
<polygon class="st187" points="16.6,64.8 15.7,64.2 39,31 39,32.9 "/>
|
|
||||||
<polygon class="st188" points="15.7,64.2 15.2,63.8 15.2,63.2 39,29.2 39,31 "/>
|
|
||||||
<polygon class="st189" points="15.2,61.3 39,27.3 39,29.2 15.2,63.2 "/>
|
|
||||||
<polygon class="st190" points="15.2,59.5 38.4,26.3 39,26.7 39,27.3 15.2,61.3 "/>
|
|
||||||
<polygon class="st191" points="15.2,57.6 37.5,25.7 38.4,26.3 15.2,59.5 "/>
|
|
||||||
<polygon class="st192" points="15.2,55.7 36.7,25 37.5,25.7 15.2,57.6 "/>
|
|
||||||
<polygon class="st193" points="15.2,53.9 35.8,24.4 36.7,25 15.2,55.7 "/>
|
|
||||||
<polygon class="st194" points="15.2,52 34.9,23.8 35.8,24.4 15.2,53.9 "/>
|
|
||||||
<polygon class="st195" points="15.2,50.2 34.1,23.2 34.9,23.8 15.2,52 "/>
|
|
||||||
<polygon class="st196" points="15.2,48.3 33.2,22.6 34.1,23.2 15.2,50.2 "/>
|
|
||||||
<polygon class="st197" points="15.2,46.5 32.3,22 33.2,22.6 15.2,48.3 "/>
|
|
||||||
<polygon class="st198" points="15.2,44.6 31.5,21.4 32.3,22 15.2,46.5 "/>
|
|
||||||
<polygon class="st199" points="15.2,42.8 30.6,20.8 31.5,21.4 15.2,44.6 "/>
|
|
||||||
<polygon class="st200" points="15.2,40.9 29.7,20.2 30.6,20.8 15.2,42.8 "/>
|
|
||||||
<polygon class="st201" points="15.2,39.1 28.8,19.6 29.7,20.2 15.2,40.9 "/>
|
|
||||||
<polygon class="st202" points="15.2,37.2 28,18.9 28.8,19.6 15.2,39.1 "/>
|
|
||||||
<polygon class="st203" points="15.2,35.4 27.1,18.3 28,18.9 15.2,37.2 "/>
|
|
||||||
<polygon class="st204" points="15.2,33.5 26.2,17.7 27.1,18.3 15.2,35.4 "/>
|
|
||||||
<polygon class="st205" points="15.2,31.6 25.4,17.1 26.2,17.7 15.2,33.5 "/>
|
|
||||||
<polygon class="st206" points="15.2,29.8 24.5,16.5 25.4,17.1 15.2,31.6 "/>
|
|
||||||
<polygon class="st207" points="15.2,27.9 23.6,15.9 24.5,16.5 15.2,29.8 "/>
|
|
||||||
<polygon class="st208" points="15.2,26.1 22.7,15.3 23.6,15.9 15.2,27.9 "/>
|
|
||||||
<polygon class="st209" points="15.2,24.2 21.7,15 22.3,15 22.7,15.3 15.2,26.1 "/>
|
|
||||||
<polygon class="st210" points="15.2,22.4 20.4,15 21.7,15 15.2,24.2 "/>
|
|
||||||
<polygon class="st211" points="15.2,20.5 19.1,15 20.4,15 15.2,22.4 "/>
|
|
||||||
<polygon class="st212" points="15.2,18.7 17.8,15 19.1,15 15.2,20.5 "/>
|
|
||||||
<polygon class="st213" points="15.2,16.8 16.5,15 17.8,15 15.2,18.7 "/>
|
|
||||||
<polygon class="st214" points="15.2,15 15.2,15 16.5,15 15.2,16.8 "/>
|
|
||||||
<polygon class="st214" points="15.2,15 15.2,15 15.2,15 "/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g class="st215">
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<polygon id="SVGID_9_" points="83,20.8 59.2,8.1 15.2,15 39,27.6 "/>
|
|
||||||
</defs>
|
|
||||||
<clipPath id="SVGID_10_">
|
|
||||||
<use xlink:href="#SVGID_9_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st216" d="M83,27.6v-6.9V27.6z"/>
|
|
||||||
<rect x="81.7" y="8.1" class="st216" width="1.3" height="19.5"/>
|
|
||||||
<rect x="80.4" y="8.1" class="st217" width="1.3" height="19.5"/>
|
|
||||||
<rect x="79.2" y="8.1" class="st218" width="1.3" height="19.5"/>
|
|
||||||
<rect x="77.9" y="8.1" class="st219" width="1.3" height="19.5"/>
|
|
||||||
<rect x="76.7" y="8.1" class="st220" width="1.3" height="19.5"/>
|
|
||||||
<rect x="75.4" y="8.1" class="st221" width="1.3" height="19.5"/>
|
|
||||||
<rect x="74.2" y="8.1" class="st222" width="1.3" height="19.5"/>
|
|
||||||
<rect x="72.9" y="8.1" class="st223" width="1.3" height="19.5"/>
|
|
||||||
<rect x="71.7" y="8.1" class="st224" width="1.3" height="19.5"/>
|
|
||||||
<rect x="70.4" y="8.1" class="st225" width="1.3" height="19.5"/>
|
|
||||||
<rect x="69.2" y="8.1" class="st226" width="1.3" height="19.5"/>
|
|
||||||
<rect x="67.9" y="8.1" class="st227" width="1.3" height="19.5"/>
|
|
||||||
<rect x="66.6" y="8.1" class="st228" width="1.3" height="19.5"/>
|
|
||||||
<rect x="65.4" y="8.1" class="st229" width="1.3" height="19.5"/>
|
|
||||||
<rect x="64.1" y="8.1" class="st230" width="1.3" height="19.5"/>
|
|
||||||
<rect x="62.9" y="8.1" class="st231" width="1.3" height="19.5"/>
|
|
||||||
<rect x="61.6" y="8.1" class="st232" width="1.3" height="19.5"/>
|
|
||||||
<rect x="60.4" y="8.1" class="st233" width="1.3" height="19.5"/>
|
|
||||||
<rect x="59.1" y="8.1" class="st234" width="1.3" height="19.5"/>
|
|
||||||
<rect x="57.9" y="8.1" class="st235" width="1.3" height="19.5"/>
|
|
||||||
<rect x="56.6" y="8.1" class="st236" width="1.3" height="19.5"/>
|
|
||||||
<rect x="55.3" y="8.1" class="st237" width="1.3" height="19.5"/>
|
|
||||||
<rect x="54.1" y="8.1" class="st238" width="1.3" height="19.5"/>
|
|
||||||
<rect x="52.8" y="8.1" class="st239" width="1.3" height="19.5"/>
|
|
||||||
<rect x="51.6" y="8.1" class="st240" width="1.3" height="19.5"/>
|
|
||||||
<rect x="50.3" y="8.1" class="st241" width="1.3" height="19.5"/>
|
|
||||||
<rect x="49.1" y="8.1" class="st242" width="1.3" height="19.5"/>
|
|
||||||
<rect x="47.8" y="8.1" class="st243" width="1.3" height="19.5"/>
|
|
||||||
<rect x="46.6" y="8.1" class="st244" width="1.3" height="19.5"/>
|
|
||||||
<rect x="45.3" y="8.1" class="st245" width="1.3" height="19.5"/>
|
|
||||||
<rect x="44.1" y="8.1" class="st246" width="1.3" height="19.5"/>
|
|
||||||
<rect x="42.8" y="8.1" class="st247" width="1.3" height="19.5"/>
|
|
||||||
<rect x="41.5" y="8.1" class="st248" width="1.3" height="19.5"/>
|
|
||||||
<rect x="40.3" y="8.1" class="st249" width="1.3" height="19.5"/>
|
|
||||||
<rect x="39" y="8.1" class="st250" width="1.3" height="19.5"/>
|
|
||||||
<rect x="37.8" y="8.1" class="st251" width="1.3" height="19.5"/>
|
|
||||||
<rect x="36.5" y="8.1" class="st252" width="1.3" height="19.5"/>
|
|
||||||
<rect x="35.3" y="8.1" class="st253" width="1.3" height="19.5"/>
|
|
||||||
<rect x="34" y="8.1" class="st254" width="1.3" height="19.5"/>
|
|
||||||
<rect x="32.8" y="8.1" class="st255" width="1.3" height="19.5"/>
|
|
||||||
<rect x="31.5" y="8.1" class="st256" width="1.3" height="19.5"/>
|
|
||||||
<rect x="30.2" y="8.1" class="st257" width="1.3" height="19.5"/>
|
|
||||||
<rect x="29" y="8.1" class="st258" width="1.3" height="19.5"/>
|
|
||||||
<rect x="27.7" y="8.1" class="st259" width="1.3" height="19.5"/>
|
|
||||||
<rect x="26.5" y="8.1" class="st260" width="1.3" height="19.5"/>
|
|
||||||
<rect x="25.2" y="8.1" class="st261" width="1.3" height="19.5"/>
|
|
||||||
<rect x="24" y="8.1" class="st262" width="1.3" height="19.5"/>
|
|
||||||
<rect x="22.7" y="8.1" class="st263" width="1.3" height="19.5"/>
|
|
||||||
<rect x="21.5" y="8.1" class="st264" width="1.3" height="19.5"/>
|
|
||||||
<rect x="20.2" y="8.1" class="st265" width="1.3" height="19.5"/>
|
|
||||||
<rect x="18.9" y="8.1" class="st266" width="1.3" height="19.5"/>
|
|
||||||
<rect x="17.7" y="8.1" class="st267" width="1.3" height="19.5"/>
|
|
||||||
<rect x="16.4" y="8.1" class="st268" width="1.3" height="19.5"/>
|
|
||||||
<polygon class="st269" points="15.2,15 15.2,8.1 16.4,8.1 16.4,27.6 15.2,27.6 "/>
|
|
||||||
<path class="st269" d="M15.2,8.1V15V8.1z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g class="st215">
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<polygon id="SVGID_11_" points="39,27.6 39,75.5 83,68.7 83,20.8 "/>
|
|
||||||
</defs>
|
|
||||||
<clipPath id="SVGID_12_">
|
|
||||||
<use xlink:href="#SVGID_11_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<polygon class="st270" points="77.2,75.5 83,68.7 83,75.5 "/>
|
|
||||||
<polygon class="st270" points="76.2,75.5 83,67.5 83,68.7 77.2,75.5 "/>
|
|
||||||
<polygon class="st271" points="75.3,75.5 83,66.3 83,67.5 76.2,75.5 "/>
|
|
||||||
<polygon class="st272" points="74.3,75.5 83,65.1 83,66.3 75.3,75.5 "/>
|
|
||||||
<polygon class="st273" points="73.3,75.5 83,64 83,65.1 74.3,75.5 "/>
|
|
||||||
<polygon class="st274" points="72.3,75.5 83,62.8 83,64 73.3,75.5 "/>
|
|
||||||
<polygon class="st275" points="71.3,75.5 83,61.6 83,62.8 72.3,75.5 "/>
|
|
||||||
<polygon class="st276" points="70.3,75.5 83,60.4 83,61.6 71.3,75.5 "/>
|
|
||||||
<polygon class="st277" points="69.3,75.5 83,59.3 83,60.4 70.3,75.5 "/>
|
|
||||||
<polygon class="st278" points="68.4,75.5 83,58.1 83,59.3 69.3,75.5 "/>
|
|
||||||
<polygon class="st279" points="67.4,75.5 83,56.9 83,58.1 68.4,75.5 "/>
|
|
||||||
<polygon class="st280" points="66.4,75.5 83,55.7 83,56.9 67.4,75.5 "/>
|
|
||||||
<polygon class="st281" points="65.4,75.5 83,54.6 83,55.7 66.4,75.5 "/>
|
|
||||||
<polygon class="st282" points="64.4,75.5 83,53.4 83,54.6 65.4,75.5 "/>
|
|
||||||
<polygon class="st283" points="63.4,75.5 83,52.2 83,53.4 64.4,75.5 "/>
|
|
||||||
<polygon class="st284" points="62.4,75.5 83,51 83,52.2 63.4,75.5 "/>
|
|
||||||
<polygon class="st285" points="61.5,75.5 83,49.9 83,51 62.4,75.5 "/>
|
|
||||||
<polygon class="st286" points="60.5,75.5 83,48.7 83,49.9 61.5,75.5 "/>
|
|
||||||
<polygon class="st287" points="59.5,75.5 83,47.5 83,48.7 60.5,75.5 "/>
|
|
||||||
<polygon class="st288" points="58.5,75.5 83,46.3 83,47.5 59.5,75.5 "/>
|
|
||||||
<polygon class="st289" points="57.5,75.5 83,45.2 83,46.3 58.5,75.5 "/>
|
|
||||||
<polygon class="st290" points="56.5,75.5 83,44 83,45.2 57.5,75.5 "/>
|
|
||||||
<polygon class="st291" points="55.6,75.5 83,42.8 83,44 56.5,75.5 "/>
|
|
||||||
<polygon class="st292" points="54.6,75.5 83,41.7 83,42.8 55.6,75.5 "/>
|
|
||||||
<polygon class="st293" points="53.6,75.5 83,40.5 83,41.7 54.6,75.5 "/>
|
|
||||||
<polygon class="st294" points="52.6,75.5 83,39.3 83,40.5 53.6,75.5 "/>
|
|
||||||
<polygon class="st295" points="51.6,75.5 83,38.1 83,39.3 52.6,75.5 "/>
|
|
||||||
<polygon class="st296" points="50.6,75.5 83,37 83,38.1 51.6,75.5 "/>
|
|
||||||
<polygon class="st297" points="49.6,75.5 83,35.8 83,37 50.6,75.5 "/>
|
|
||||||
<polygon class="st298" points="48.7,75.5 83,34.6 83,35.8 49.6,75.5 "/>
|
|
||||||
<polygon class="st299" points="47.7,75.5 83,33.4 83,34.6 48.7,75.5 "/>
|
|
||||||
<polygon class="st300" points="46.7,75.5 83,32.3 83,33.4 47.7,75.5 "/>
|
|
||||||
<polygon class="st301" points="45.7,75.5 83,31.1 83,32.3 46.7,75.5 "/>
|
|
||||||
<polygon class="st302" points="44.7,75.5 83,29.9 83,31.1 45.7,75.5 "/>
|
|
||||||
<polygon class="st303" points="43.7,75.5 83,28.7 83,29.9 44.7,75.5 "/>
|
|
||||||
<polygon class="st304" points="42.8,75.5 83,27.6 83,28.7 43.7,75.5 "/>
|
|
||||||
<polygon class="st305" points="41.8,75.5 83,26.4 83,27.6 42.8,75.5 "/>
|
|
||||||
<polygon class="st306" points="40.8,75.5 83,25.2 83,26.4 41.8,75.5 "/>
|
|
||||||
<polygon class="st307" points="39.8,75.5 83,24 83,25.2 40.8,75.5 "/>
|
|
||||||
<polygon class="st308" points="39,75.4 83,22.9 83,24 39.8,75.5 39,75.5 "/>
|
|
||||||
<polygon class="st309" points="39,74.2 83,21.7 83,22.9 39,75.4 "/>
|
|
||||||
<polygon class="st310" points="39,73 82.8,20.8 83,20.8 83,21.7 39,74.2 "/>
|
|
||||||
<polygon class="st311" points="39,71.8 81.8,20.8 82.8,20.8 39,73 "/>
|
|
||||||
<polygon class="st312" points="39,70.7 80.8,20.8 81.8,20.8 39,71.8 "/>
|
|
||||||
<polygon class="st313" points="39,69.5 79.8,20.8 80.8,20.8 39,70.7 "/>
|
|
||||||
<polygon class="st314" points="39,68.3 78.9,20.8 79.8,20.8 39,69.5 "/>
|
|
||||||
<polygon class="st315" points="39,67.1 77.9,20.8 78.9,20.8 39,68.3 "/>
|
|
||||||
<polygon class="st316" points="39,66 76.9,20.8 77.9,20.8 39,67.1 "/>
|
|
||||||
<polygon class="st317" points="39,64.8 75.9,20.8 76.9,20.8 39,66 "/>
|
|
||||||
<polygon class="st317" points="75.9,20.8 39,64.8 39,20.8 "/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st0" d="M36.6,28.1c0-1.4,1.1-2.7,2.5-2.9l22.5-3.6v31.9c0,2.6-1.9,4.7-4.4,5.1L36.5,62L36.6,28.1z M56.7,27.3
|
|
||||||
l-15.3,2.4l0,26.6l15.4-2.5V27.3z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<rect x="36.6" y="48.3" class="st0" width="4.8" height="28.2"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<rect x="59.2" y="3.9" class="st0" width="2.4" height="36.7"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st0" d="M83,23.4v42.4c0,1.5-1.1,2.9-2.6,3.1l-35.3,5.7c-1.9,0.3-3.6-1.2-3.6-3.1v-7.6c0-1.5,1.1-2.9,2.6-3.1l14-2.2
|
|
||||||
c2-0.3,3.5-2.1,3.5-4.1l0.2-39.7c0-2.4,2.5-3.9,4.6-2.8l14.3,7.7C82.1,20.4,83,21.8,83,23.4z M86.5,16L62.3,3
|
|
||||||
c-0.8-0.6-1.9-0.1-1.9,0.9l-1.1,51c0,0.6-0.4,1.1-1,1.2L40,59c-0.6,0.1-1,0.6-1,1.2l0,18.7c0,0.7,0.7,1.3,1.4,1.2L86,71.8
|
|
||||||
c0.6-0.1,1-0.6,1-1.2V17C87,16.6,86.8,16.3,86.5,16z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st0" d="M59.2,11.7l0,7.5c0,1.6-1.2,3-2.7,3.2l-17.1,2.8c-1.6,0.3-2.7,1.6-2.7,3.2l0,40.3c0,2.5-2.6,4-4.8,2.9
|
|
||||||
l-14.8-7.9c-1.1-0.6-1.7-1.7-1.7-2.9V17.6c0-1.6,1.2-3,2.8-3.2l37.5-5.8C57.4,8.2,59.2,9.7,59.2,11.7z M58.8,2.6l-45.5,7.9
|
|
||||||
c-0.8,0.1-1.4,0.8-1.4,1.6l-0.2,49.6c-0.1,0.7,0.3,1.3,0.9,1.6l25.2,15.4c1.2,0.6,2.6-0.2,2.5-1.6L39,29.3c0-0.9,0.6-1.7,1.5-1.8
|
|
||||||
l18.5-2.1c0.9-0.1,1.5-0.8,1.5-1.7l0.2-19.4C60.8,3.3,59.8,2.4,58.8,2.6z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st0" d="M47.5,43.8c-0.6,0-1.1-0.4-1.2-1c-0.1-0.7,0.3-1.3,1-1.4l10.1-1.6c0.7-0.1,1.3,0.3,1.4,1
|
|
||||||
c0.1,0.7-0.3,1.3-1,1.4l-10.1,1.6C47.6,43.8,47.6,43.8,47.5,43.8z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st0" d="M55.2,42.6L55.2,42.6c0.8-0.1,1.6,0.5,1.6,1.3v8.7l4.5,0V30.1l-4.5,0.2V38c0,1.1-0.8,2-1.8,2.2l-1.7,0.3
|
|
||||||
L55.2,42.6z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<polygon class="st318" points="112.5,28.8 112.5,37.1 125.6,37.1 125.6,41.2 112.5,41.2 112.5,49.5 125.6,49.5 125.6,53.6
|
|
||||||
108,53.6 108,24.7 125.6,24.7 125.6,28.8 "/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st318" d="M147.2,38.3v14.2l-3.8,1.8h-0.6v-16c0-1.7-0.8-1.9-1.5-1.9h-4.3c-0.7,0-1.5,0.2-1.5,1.9v14.2l-3.8,1.8H131
|
|
||||||
v-16c0-4,2-6,6-6h4.3C145.2,32.3,147.2,34.3,147.2,38.3z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<polygon class="st318" points="161.5,32.3 161.5,32.9 159.8,36.4 156.7,36.4 156.7,52.5 152.8,54.3 152.2,54.3 152.2,27.7
|
|
||||||
156,25.9 156.7,25.9 156.7,32.3 "/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st318" d="M174.6,32.3h-4.3c-4,0-6,2-6,6v9.3c0,4,2,6,6,6h4.3c0.6,0,1.1-0.1,1.5-0.3v2c0,1.7-0.8,1.9-1.5,1.9h-10.3
|
|
||||||
v4.1h10.3c4,0,6-2,6-6v-17C180.5,34.3,178.5,32.3,174.6,32.3z M176.1,47.6c0,1.7-0.8,1.9-1.5,1.9h-4.3c-0.7,0-1.5-0.2-1.5-1.9
|
|
||||||
v-9.3c0-1.7,0.8-1.9,1.5-1.9h4.3c0.7,0,1.5,0.2,1.5,1.9V47.6z"/>
|
|
||||||
<path class="st318" d="M197,32.3v0.6l-1.6,3.5H192c-0.7,0-1.5,0.2-1.5,1.9v14.2l-3.8,1.8H186v-16c0-4,2-6,6-6H197z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st318" d="M208,32.3h-7v4.1h7c0.7,0,1.5,0.2,1.5,1.9v1.1c-0.5-0.2-1-0.3-1.5-0.3h-3.9c-4,0-6,2-6,6v2.6c0,4,2,6,6,6
|
|
||||||
h3.9c0.6,0,1.1-0.1,1.5-0.3v1.4h0.6l3.8-1.8V38.3C214,34.3,212,32.3,208,32.3z M208,49.5h-3.9c-0.7,0-1.5-0.2-1.5-1.9V45
|
|
||||||
c0-1.7,0.8-1.9,1.5-1.9h3.9c0.7,0,1.5,0.2,1.5,1.9v2.6C209.5,49.3,208.7,49.5,208,49.5z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 804 KiB |
|
Before Width: | Height: | Size: 798 KiB |
|
Before Width: | Height: | Size: 794 KiB |
@ -1,67 +0,0 @@
|
|||||||
{
|
|
||||||
"Title" : "Title",
|
|
||||||
"Description" : "Description",
|
|
||||||
"ShortDescription" : "Short Description",
|
|
||||||
"Category" : "Category",
|
|
||||||
"Visibility" : "Visibility",
|
|
||||||
"Devices" : "Devices",
|
|
||||||
"Roles" : "Roles",
|
|
||||||
"Groups" : "Groups",
|
|
||||||
"Tags" : "Tags",
|
|
||||||
"Platform" : "Platform",
|
|
||||||
"Platforms" : "Platforms",
|
|
||||||
"Applications": "Applications",
|
|
||||||
"No.Platform" : "No Platforms",
|
|
||||||
"Screenshots" : "Screenshots",
|
|
||||||
"Icon" : "Icon",
|
|
||||||
"Info" : "Info",
|
|
||||||
"Banner" : "Banner",
|
|
||||||
"Create.Application" : "Create Application",
|
|
||||||
"Back" : "Back",
|
|
||||||
"Cancel" : "Cancel",
|
|
||||||
"Finish" : "Finish",
|
|
||||||
"Continue" : "Continue",
|
|
||||||
"Name" : "Name",
|
|
||||||
"Application.Name" : "Application Name",
|
|
||||||
"General" : "General",
|
|
||||||
"App.Releases" : "Application Releases",
|
|
||||||
"Package.Manager" : "Package Manager",
|
|
||||||
"Save" : "Save",
|
|
||||||
"Create.Release" : "Create Release",
|
|
||||||
"Release.Channel" : "Release Channel",
|
|
||||||
"Release" : "Release",
|
|
||||||
"New.Release.For" : "New Release for",
|
|
||||||
"Upload.Package.File" : "Upload Package File",
|
|
||||||
"Upload" : "Upload",
|
|
||||||
"Select.from.package.library" : "Select from package library",
|
|
||||||
"Release.Name" : "Release Name",
|
|
||||||
"Release.Notes" : "Release Notes",
|
|
||||||
"Send.for.Review" : "Send for Review",
|
|
||||||
"Production.Releases" : "Production Releases",
|
|
||||||
"Beta.Releases" : "Beta Releases",
|
|
||||||
"Alpha.Releases" : "Alpha Releases",
|
|
||||||
"Version" : "Version",
|
|
||||||
"Status" : "Status",
|
|
||||||
"App.Publisher" : "Application Publisher",
|
|
||||||
"Search.Apps" : "Search for Applications",
|
|
||||||
"View.In.Store" : "View in Store",
|
|
||||||
"Last.Updated" : "Last updated on",
|
|
||||||
"Installs" : "Installs",
|
|
||||||
"General.Info" : "General Info",
|
|
||||||
"Select.Platform": "Select Platform",
|
|
||||||
"Add.Release" : "Add Release to Application",
|
|
||||||
"Share.With.Tenants" : "Share with Tenants",
|
|
||||||
"Disable" : "Disable",
|
|
||||||
"File.Based" : "File Based",
|
|
||||||
"Activate" : "Activate",
|
|
||||||
"Yes" : "Yes",
|
|
||||||
"No" : "No",
|
|
||||||
"No.Platform.Tags" : "No Platform Tags",
|
|
||||||
"Create.Platform" : "Create Platform",
|
|
||||||
"Optional": "Optional",
|
|
||||||
"Identifier": "Identifier",
|
|
||||||
"Next": "Next",
|
|
||||||
"Platform.Enable": "Enable Platform",
|
|
||||||
"Share.with.Tenants": "Share between all tenants",
|
|
||||||
"Platform.Properties": "Platform Properties"
|
|
||||||
}
|
|
||||||
@ -1,903 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Roboto-Medium";
|
|
||||||
src: url('../../fonts/Roboto-Medium.woff');
|
|
||||||
src: local("Roboto-Medium"), url("../../fonts/Roboto-Medium.ttf") format("ttf");
|
|
||||||
src: local("Roboto-Medium"), url("../../fonts/Roboto-Medium.woff") format("woff");
|
|
||||||
src: local("Roboto-Medium"), url("../../fonts/Roboto-Medium.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Roboto-Regular";
|
|
||||||
src: url("../../fonts/Roboto-Regular.woff");
|
|
||||||
src: local("Roboto-Regular"), url("../../fonts/Roboto-Regular.ttf") format("ttf");
|
|
||||||
src: local("Roboto-Regular"), url("../../fonts/Roboto-Regular.woff") format("woff");
|
|
||||||
src: local("Roboto-Regular"), url("../../fonts/Roboto-Regular.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Colors*/
|
|
||||||
.primary {
|
|
||||||
color: white;
|
|
||||||
background-color: #2196f3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary-flat {
|
|
||||||
color: #2196F3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.danger {
|
|
||||||
color: white;
|
|
||||||
background-color: #e91e63 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.danger-flat {
|
|
||||||
color: #e91e63 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grey {
|
|
||||||
color: #b3b3b3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==================================================================== */
|
|
||||||
/* Custom button styles based on material design specs. */
|
|
||||||
|
|
||||||
.custom-raised {
|
|
||||||
font-family: Roboto-Medium;
|
|
||||||
text-transform: uppercase !important;
|
|
||||||
font-size: 14px !important;
|
|
||||||
padding-left: 16px !important;
|
|
||||||
border-radius: 2px !important;
|
|
||||||
padding-right: 16px !important;
|
|
||||||
height: 36px !important;
|
|
||||||
border: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-raised:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08) !important;
|
|
||||||
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08) !important;
|
|
||||||
background-color: #1976D2 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-raised:focus {
|
|
||||||
box-shadow: none !important;
|
|
||||||
-webkit-box-shadow: none !important;
|
|
||||||
background-color: #1976D2 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-flat {
|
|
||||||
font-family: Roboto-Medium;
|
|
||||||
height: 36px !important;
|
|
||||||
border-radius: 2px !important;
|
|
||||||
margin-left: 8px !important;
|
|
||||||
margin-right: 8px !important;
|
|
||||||
padding-left: 8px !important;
|
|
||||||
padding-right: 8px !important;
|
|
||||||
background-color: transparent !important;
|
|
||||||
text-transform: uppercase;
|
|
||||||
outline: none !important;
|
|
||||||
border: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-flat:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: rgba(0, 0, 0, 0.12) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-flat:focus {
|
|
||||||
outline: none !important;
|
|
||||||
border: none !important;
|
|
||||||
-webkit-box-shadow: none !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
background-color: rgba(0, 0, 0, 0.40) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle-button {
|
|
||||||
border-radius: 100% !important;
|
|
||||||
height: 36px !important;
|
|
||||||
width: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==================================================================== */
|
|
||||||
|
|
||||||
/* Body Styling */
|
|
||||||
body {
|
|
||||||
width: 100%;
|
|
||||||
font-family: "Roboto-Regular" !important;
|
|
||||||
font-size: 14px !important;
|
|
||||||
background-color: #e8e8e8 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-manager-title {
|
|
||||||
font-family: "Roboto-Medium";
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-manager-sub-title {
|
|
||||||
font-family: "Roboto-Regular";
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-mgt-footer {
|
|
||||||
clear: both;
|
|
||||||
position: relative;
|
|
||||||
height: 50px;
|
|
||||||
width: 100%;
|
|
||||||
color: white;
|
|
||||||
background-color: #334d88;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Login page styles*/
|
|
||||||
#userName {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#password {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-btn {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-header {
|
|
||||||
background-color: #3f50b5;
|
|
||||||
color: white;
|
|
||||||
height: 128px;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 !important;
|
|
||||||
padding: 20px;
|
|
||||||
box-shadow: -2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
||||||
}
|
|
||||||
|
|
||||||
#login-card {
|
|
||||||
width: 25%;
|
|
||||||
height: 50%;
|
|
||||||
margin: 10% auto;
|
|
||||||
font-family: Roboto-Regular;
|
|
||||||
font-size: 14px;
|
|
||||||
border-radius: 0;
|
|
||||||
background-color: #ffffff;
|
|
||||||
box-shadow: -2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-header-title {
|
|
||||||
font-family: Roboto-Medium;
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-header-logo {
|
|
||||||
height: 70px;
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-form {
|
|
||||||
margin: 0 !important;
|
|
||||||
padding: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Base layout container */
|
|
||||||
|
|
||||||
/* Base layout header content*/
|
|
||||||
.header-content {
|
|
||||||
height: 128px !important;
|
|
||||||
width: 100% !important;
|
|
||||||
margin: 0 10px 0 0;
|
|
||||||
background-color: #3f50b5 !important;
|
|
||||||
position: fixed; /* Set the navbar to fixed position */
|
|
||||||
top: 0; /* Position the navbar at the top of the page */
|
|
||||||
z-index: 2;
|
|
||||||
box-shadow: -2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Contains the header styles.*/
|
|
||||||
.header {
|
|
||||||
padding: 24px 24px 10px 24px;
|
|
||||||
/*margin: 16px 16px 20px 16px;*/
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header-text {
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 20px;
|
|
||||||
font-family: Roboto-Medium;
|
|
||||||
top: 10px;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The buttons in the header (User and Notification)*/
|
|
||||||
.header-button-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-user-name {
|
|
||||||
font-family: Roboto-Medium;
|
|
||||||
font-size: 14px;
|
|
||||||
padding-top: 15px;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-image {
|
|
||||||
height: 43px;
|
|
||||||
width: 100px;
|
|
||||||
margin-right: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header-button {
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
height: 50px;
|
|
||||||
width: 50px;
|
|
||||||
margin-right: 10px;
|
|
||||||
position: relative;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header-button:hover {
|
|
||||||
background-color: #4353bd;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header-button i {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 19px;
|
|
||||||
left: 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-header {
|
|
||||||
margin-top: 15px;
|
|
||||||
margin-right: 20px;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sub-title {
|
|
||||||
font-family: Roboto-Regular;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-left: 18px;
|
|
||||||
color: RGBA(0, 0, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Search box styles */
|
|
||||||
.search-box {
|
|
||||||
display: flex;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-box i {
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
color: #BaBaBa;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search {
|
|
||||||
position: relative;
|
|
||||||
color: white;
|
|
||||||
background-color: transparent;
|
|
||||||
left: 15px;
|
|
||||||
top: 0px;
|
|
||||||
height: 25px;
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Application Add button */
|
|
||||||
#add-btn-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 98px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-btn {
|
|
||||||
background-color: #ff5722;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-btn:hover {
|
|
||||||
background-color: #E64A19;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sub-title-container {
|
|
||||||
height: 100px;
|
|
||||||
padding: 50px 0 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-container {
|
|
||||||
padding: 0 !important;
|
|
||||||
min-height: 100% !important;
|
|
||||||
margin-top: 128px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Holds the app pages. */
|
|
||||||
.store-card {
|
|
||||||
height: auto;
|
|
||||||
background-color: white;
|
|
||||||
box-shadow: 2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
||||||
padding: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-link-placeholder {
|
|
||||||
color: #888888;
|
|
||||||
float: right;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-link-placeholder i {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-list {
|
|
||||||
transition: margin-right .5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
#batch-content {
|
|
||||||
display: flex;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-list-icon {
|
|
||||||
border-radius: 50%;
|
|
||||||
height: 50px;
|
|
||||||
width: 50px
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-table-row {
|
|
||||||
height: 62px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding-top: 6px;
|
|
||||||
font-family: "Roboto-Regular";
|
|
||||||
font-size: medium;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-table-row:hover {
|
|
||||||
color: white;
|
|
||||||
background-color: #3f50b5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-list-table-header {
|
|
||||||
margin-top: 30px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-family: "Roboto-Medium";
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-view-image {
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-visibility-default {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-image-screenshot {
|
|
||||||
width: 300px;
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-image-icon {
|
|
||||||
width: 300px;
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-image-banner {
|
|
||||||
width: 400px;
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#form-error {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-create-banner-dropzone {
|
|
||||||
width: 300px;
|
|
||||||
height: 150px;
|
|
||||||
border-radius: 5%;
|
|
||||||
position: relative;
|
|
||||||
border: dashed #888888 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-create-banner-dropzone i {
|
|
||||||
position: absolute;
|
|
||||||
top: 65px;
|
|
||||||
left: 145px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-create-screenshot-dropzone {
|
|
||||||
width: 150px;
|
|
||||||
height: 150px;
|
|
||||||
margin: 0 5px 0 5px;
|
|
||||||
border-radius: 10%;
|
|
||||||
position: relative;
|
|
||||||
border: dashed #888888 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-create-screenshot-dropzone i {
|
|
||||||
position: absolute;
|
|
||||||
top: 65px;
|
|
||||||
left: 65px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-create-icon-dropzone {
|
|
||||||
width: 150px;
|
|
||||||
height: 150px;
|
|
||||||
border-radius: 10%;
|
|
||||||
position: relative;
|
|
||||||
border: dashed #888888 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-create-icon-dropzone i {
|
|
||||||
position: absolute;
|
|
||||||
top: 65px;
|
|
||||||
left: 65px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#screenshot-container {
|
|
||||||
max-width: 600px;
|
|
||||||
display: flex;
|
|
||||||
overflow-x: auto;
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-icon-container {
|
|
||||||
height: 300px;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#modal-body-content {
|
|
||||||
max-height: 700px;
|
|
||||||
padding-left: 24px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-footer {
|
|
||||||
justify-content: inherit !important;
|
|
||||||
margin: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-main-btn {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
#img-btn-screenshot {
|
|
||||||
margin: 0 5px 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-create-modal {
|
|
||||||
max-width: 850px;
|
|
||||||
border-radius: 0% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-create-modal-header {
|
|
||||||
background-color: #4353bd;
|
|
||||||
color: white;
|
|
||||||
padding: 24px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-create-modal-content {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#store {
|
|
||||||
border: none;
|
|
||||||
border-bottom: solid #BDBDBD 1px;
|
|
||||||
border-radius: 0px;
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#version {
|
|
||||||
border: none;
|
|
||||||
border-bottom: solid #BDBDBD 1px;
|
|
||||||
border-radius: 0px;
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-release-switch-content {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-release-switch-label {
|
|
||||||
position: absolute;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-release-switch {
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-sub-title {
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #818181;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Application View */
|
|
||||||
|
|
||||||
#application-view-content {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#application-view-row {
|
|
||||||
margin: 10px 10px 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-icon {
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
border: solid 1px black;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-updated-date {
|
|
||||||
color: #888888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-install-count {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-details-tbl {
|
|
||||||
outline: none;
|
|
||||||
border-color: #2196F3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-details-tbl tr {
|
|
||||||
margin: 20px 0 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-details-tbl td {
|
|
||||||
margin-left: 10px;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Application Edit Base Layout */
|
|
||||||
|
|
||||||
#application-edit-header {
|
|
||||||
height: 40px;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
font-size: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.application-header-text {
|
|
||||||
margin: 10px 0px 0px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#save-btn-content {
|
|
||||||
float: right;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-save-btn {
|
|
||||||
border-radius: 0%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn {
|
|
||||||
margin: 5px 5px 5px 0px;
|
|
||||||
height: 70%;
|
|
||||||
width: 50%;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Tab styling*/
|
|
||||||
|
|
||||||
div.tab {
|
|
||||||
float: left;
|
|
||||||
border-right: 1px solid #d8d8d8;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style the tab buttons */
|
|
||||||
|
|
||||||
div.tab button {
|
|
||||||
display: block;
|
|
||||||
background-color: inherit;
|
|
||||||
color: black;
|
|
||||||
padding: 15px 16px;
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
text-align: left;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Change background color of buttons on hover */
|
|
||||||
|
|
||||||
div.tab button:hover {
|
|
||||||
background-color: #ddd6d7;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create an active/current "tab button" class */
|
|
||||||
|
|
||||||
div.tab button.active {
|
|
||||||
background-color: #1b3bcc;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#application-edit-main-container {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#application-edit-outer-content {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app-edit-content {
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-to-app {
|
|
||||||
position: absolute;
|
|
||||||
height: 50px;
|
|
||||||
width: 50px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-to-app i {
|
|
||||||
padding: 12px 10px 10px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-to-app:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #dedede;
|
|
||||||
transition: .5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create Release and Release management */
|
|
||||||
|
|
||||||
.release-header {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-create {
|
|
||||||
height: 150px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-detail-content {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20%;
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-btn {
|
|
||||||
float: right;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-content {
|
|
||||||
height: 180px;
|
|
||||||
width: 95%;
|
|
||||||
border: dashed 1px #626262;
|
|
||||||
border-radius: 2%;
|
|
||||||
position: relative;
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-content:after {
|
|
||||||
content: "";
|
|
||||||
letter-spacing: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release {
|
|
||||||
margin: 30px 10px 20px 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-release-content {
|
|
||||||
position: absolute;
|
|
||||||
margin-top: 10px;
|
|
||||||
left: 40%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-add:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-inner {
|
|
||||||
margin-top: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Application Edit General Info */
|
|
||||||
|
|
||||||
.app-edit-general-info {
|
|
||||||
margin-top: 20px;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-info {
|
|
||||||
float: right;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-view-field {
|
|
||||||
font-family: Roboto-Medium;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-view-text {
|
|
||||||
font-family: Roboto-Regular;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Platform Specific Styles. */
|
|
||||||
#platform-listing {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.create-platform i {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#platform-list {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-content {
|
|
||||||
margin: 10px;
|
|
||||||
padding-top: 16px;
|
|
||||||
box-shadow: 2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-content .row {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-content .col {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-content-basic {
|
|
||||||
padding: 0 16px 0 16px;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-content-more-outer {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-content-more {
|
|
||||||
padding: 16px 16px 24px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-content-footer {
|
|
||||||
display: flex;
|
|
||||||
padding: 8px 8px 8px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-text-container {
|
|
||||||
padding: 8px 16px 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle-button {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-icon-letter {
|
|
||||||
text-align: center;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-family: Roboto-Medium;
|
|
||||||
font-size: 70px;
|
|
||||||
color: white;
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-icon-container {
|
|
||||||
height: 120px;
|
|
||||||
width: 120px;
|
|
||||||
background-color: #01579B;
|
|
||||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08) !important;
|
|
||||||
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-property-container {
|
|
||||||
padding-top: 20px;
|
|
||||||
font-family: Roboto-Regular;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-property-row {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle-btn-clear {
|
|
||||||
background-color: white !important;
|
|
||||||
color: rgba(0, 0, 0, 0.50) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle-btn-clear:hover {
|
|
||||||
background-color: white !important;
|
|
||||||
color: rgba(0, 0, 0, 0.38) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle-btn-clear:focus {
|
|
||||||
background-color: white !important;
|
|
||||||
color: rgba(0, 0, 0, 0.60) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.data-table-row-cell {
|
|
||||||
padding-top: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-code {
|
|
||||||
text-align: center;
|
|
||||||
font-family: Roboto-Medium;
|
|
||||||
font-weight: 800;
|
|
||||||
font-size: 15em;
|
|
||||||
color: #BaBaBa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-code p {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-text {
|
|
||||||
text-align: center;
|
|
||||||
font-family: Roboto-Regular;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #9e9e9e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle-btn-add {
|
|
||||||
background-color: #bababa !important;
|
|
||||||
border-radius: 50% !important;
|
|
||||||
height: 30px !important;
|
|
||||||
width: 30px;
|
|
||||||
text-align: -webkit-center;
|
|
||||||
font-size: 18px;
|
|
||||||
padding: 6px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle-btn-add:hover {
|
|
||||||
background-color: #828282 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
If you need to change the color of active steps in stepper,
|
|
||||||
uncomment the following and set the background color and font color as needed.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
.stepper-active-index {
|
|
||||||
background-color: #0a6eff !important;
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stepper-passed-index {
|
|
||||||
background-color: #0a6eff !important;
|
|
||||||
color: green !important;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.ant-upload.ant-upload-drag {
|
|
||||||
height: 170px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release .release-icon {
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release .release-icon img {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 28%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release .release-title {
|
|
||||||
margin-left: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release .release-screenshot img {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 15px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-container {
|
|
||||||
background: #f0f2f5;
|
|
||||||
min-height: 780px
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 768px) {
|
|
||||||
.main-container {
|
|
||||||
padding: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,173 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import 'antd/dist/antd.less';
|
|
||||||
import RouteWithSubRoutes from './components/RouteWithSubRoutes';
|
|
||||||
import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Layout, Spin, Result, notification } from 'antd';
|
|
||||||
import ConfigContext from './components/ConfigContext';
|
|
||||||
|
|
||||||
const { Content } = Layout;
|
|
||||||
const loadingView = (
|
|
||||||
<Layout>
|
|
||||||
<Content
|
|
||||||
style={{
|
|
||||||
padding: '0 0',
|
|
||||||
paddingTop: 300,
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
textAlign: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Spin tip="Loading..." />
|
|
||||||
</Content>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
|
|
||||||
const errorView = (
|
|
||||||
<Result
|
|
||||||
style={{
|
|
||||||
paddingTop: 200,
|
|
||||||
}}
|
|
||||||
status="500"
|
|
||||||
title="Error occurred while loading the configuration"
|
|
||||||
subTitle="Please refresh your browser window"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
class App extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
loading: true,
|
|
||||||
error: false,
|
|
||||||
config: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
axios
|
|
||||||
.get(window.location.origin + '/entgra/public/conf/config.json')
|
|
||||||
.then(res => {
|
|
||||||
const config = res.data;
|
|
||||||
this.checkUserLoggedIn(config);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
error: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
checkUserLoggedIn = config => {
|
|
||||||
axios
|
|
||||||
.post(
|
|
||||||
window.location.origin + '/entgra-ui-request-handler/user',
|
|
||||||
'platform=entgra',
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
config.user = res.data.data;
|
|
||||||
const pageURL = window.location.pathname;
|
|
||||||
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
|
||||||
if (lastURLSegment === 'login') {
|
|
||||||
window.location.href = window.location.origin + '/entgra/';
|
|
||||||
} else {
|
|
||||||
this.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);
|
|
||||||
config.supportedOStypes = [];
|
|
||||||
config.deviceTypes.forEach(type => {
|
|
||||||
if (['ios', 'android'].includes(type.name)) {
|
|
||||||
config.supportedOStypes.push(type);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
config: config,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load device types.',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { loading, error } = this.state;
|
|
||||||
const applicationView = (
|
|
||||||
<Router>
|
|
||||||
<ConfigContext.Provider value={this.state.config}>
|
|
||||||
<div>
|
|
||||||
<Switch>
|
|
||||||
<Redirect exact from="/entgra" to="/entgra/devices" />
|
|
||||||
{this.props.routes.map(route => (
|
|
||||||
<RouteWithSubRoutes key={route.path} {...route} />
|
|
||||||
))}
|
|
||||||
</Switch>
|
|
||||||
</div>
|
|
||||||
</ConfigContext.Provider>
|
|
||||||
</Router>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{loading && loadingView}
|
|
||||||
{!loading && !error && applicationView}
|
|
||||||
{error && errorView}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import App from './App';
|
|
||||||
|
|
||||||
it('renders without crashing', () => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
ReactDOM.render(<App />, div);
|
|
||||||
ReactDOM.unmountComponentAtNode(div);
|
|
||||||
});
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const ConfigContext = React.createContext();
|
|
||||||
|
|
||||||
export const withConfigContext = Component => {
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
return props => (
|
|
||||||
<ConfigContext.Consumer>
|
|
||||||
{context => {
|
|
||||||
return <Component {...props} context={context} />;
|
|
||||||
}}
|
|
||||||
</ConfigContext.Consumer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ConfigContext;
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Route } from 'react-router-dom';
|
|
||||||
class RouteWithSubRoutes extends React.Component {
|
|
||||||
props;
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.props = props;
|
|
||||||
}
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Route
|
|
||||||
path={this.props.path}
|
|
||||||
exact={this.props.exact}
|
|
||||||
render={props => (
|
|
||||||
<this.props.component
|
|
||||||
{...props}
|
|
||||||
{...this.props}
|
|
||||||
routes={this.props.routes}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RouteWithSubRoutes;
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.App {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-layout-header{
|
|
||||||
padding: 0;
|
|
||||||
height: auto;
|
|
||||||
box-shadow: 0 2px 8px #f0f1f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.steps-content {
|
|
||||||
margin-top: 16px;
|
|
||||||
border: 1px dashed #e9e9e9;
|
|
||||||
border-radius: 6px;
|
|
||||||
background-color: #fafafa;
|
|
||||||
min-height: 200px;
|
|
||||||
text-align: center;
|
|
||||||
padding-top: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.steps-action {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-input-affix-wrapper .ant-input{
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
~
|
|
||||||
~ Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
~ Version 2.0 (the "License"); you may not use this file except
|
|
||||||
~ in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing,
|
|
||||||
~ software distributed under the License is distributed on an
|
|
||||||
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
~ KIND, either express or implied. See the License for the
|
|
||||||
~ specific language governing permissions and limitations
|
|
||||||
~ under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/>
|
|
||||||
<meta charset="UTF-8"/>
|
|
||||||
<title>Entgra Device Management</title>
|
|
||||||
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.3/leaflet.css'>
|
|
||||||
</head>
|
|
||||||
<div id="root"></div>
|
|
||||||
</html>
|
|
||||||
@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import * as serviceWorker from './services/serviceWorkers/serviceWorker';
|
|
||||||
import App from './App';
|
|
||||||
import Login from './scenes/Login';
|
|
||||||
import Home from './scenes/Home';
|
|
||||||
import './index.css';
|
|
||||||
import Geo from './scenes/Home/scenes/Geo';
|
|
||||||
import Notifications from './scenes/Home/scenes/Notifications';
|
|
||||||
import DeviceEnroll from './scenes/Home/scenes/Devices/scenes/Enroll';
|
|
||||||
import Groups from './scenes/Home/scenes/Groups';
|
|
||||||
import Users from './scenes/Home/scenes/Users';
|
|
||||||
import Policies from './scenes/Home/scenes/Policies';
|
|
||||||
import AddNewPolicy from './scenes/Home/scenes/Policies/scenes/AddNewPolicy';
|
|
||||||
import Roles from './scenes/Home/scenes/Roles';
|
|
||||||
import DeviceTypes from './scenes/Home/scenes/DeviceTypes';
|
|
||||||
import Certificates from './scenes/Home/scenes/Configurations/scenes/Certificates';
|
|
||||||
import Devices from './scenes/Home/scenes/Devices';
|
|
||||||
import ViewPolicy from './scenes/Home/scenes/Policies/scenes/ViewPolicy';
|
|
||||||
import EditSelectedPolicy from './scenes/Home/scenes/Policies/scenes/EditSelectedPolicy';
|
|
||||||
import DeviceLocations from './scenes/Home/scenes/DeviceLocations';
|
|
||||||
|
|
||||||
const routes = [
|
|
||||||
{
|
|
||||||
path: '/entgra/login',
|
|
||||||
exact: true,
|
|
||||||
component: Login,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra',
|
|
||||||
exact: false,
|
|
||||||
component: Home,
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
path: '/entgra/devices',
|
|
||||||
component: Devices,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/devices/enroll',
|
|
||||||
component: DeviceEnroll,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/geo/history/:deviceType/:deviceIdentifier',
|
|
||||||
component: Geo,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/groups',
|
|
||||||
component: Groups,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/users',
|
|
||||||
component: Users,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/policies',
|
|
||||||
component: Policies,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/policy/add',
|
|
||||||
component: AddNewPolicy,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/policy/view/:policyId',
|
|
||||||
component: ViewPolicy,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/policy/edit/:policyId',
|
|
||||||
component: EditSelectedPolicy,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/roles',
|
|
||||||
component: Roles,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/devicetypes',
|
|
||||||
component: DeviceTypes,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/configurations/certificates',
|
|
||||||
component: Certificates,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/notifications',
|
|
||||||
component: Notifications,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/entgra/device-locations',
|
|
||||||
component: DeviceLocations,
|
|
||||||
exact: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
ReactDOM.render(<App routes={routes} />, document.getElementById('root'));
|
|
||||||
|
|
||||||
// If you want your app e and load faster, you can change
|
|
||||||
// unregister() to register() below. Note this comes with some pitfalls.
|
|
||||||
// Learn more about service workers: https://bit.ly/CRA-PWA
|
|
||||||
serviceWorker.unregister();
|
|
||||||
@ -1,260 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Icon, message, notification, Table, Tag, Tooltip } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
title: 'Device',
|
|
||||||
dataIndex: 'name',
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Type',
|
|
||||||
dataIndex: 'type',
|
|
||||||
key: 'type',
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
render: type => {
|
|
||||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
|
||||||
let icon = defaultPlatformIcons.default.icon;
|
|
||||||
let color = defaultPlatformIcons.default.color;
|
|
||||||
let theme = defaultPlatformIcons.default.theme;
|
|
||||||
|
|
||||||
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
|
||||||
icon = defaultPlatformIcons[type].icon;
|
|
||||||
color = defaultPlatformIcons[type].color;
|
|
||||||
theme = defaultPlatformIcons[type].theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
|
|
||||||
<Icon type={icon} theme={theme} />
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Owner',
|
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'owner',
|
|
||||||
render: enrolmentInfo => enrolmentInfo.owner,
|
|
||||||
// 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: 'Last Updated',
|
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'dateOfLastUpdate',
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
render: data => {
|
|
||||||
const { dateOfLastUpdate } = data;
|
|
||||||
const timeAgoString = getTimeAgo(dateOfLastUpdate);
|
|
||||||
return (
|
|
||||||
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
|
|
||||||
{timeAgoString}
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getTimeAgo = time => {
|
|
||||||
const timeAgo = new TimeAgo('en-US');
|
|
||||||
return timeAgo.format(time);
|
|
||||||
};
|
|
||||||
|
|
||||||
class deviceTable extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
config = this.props.context;
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
paramsObj: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
rowSelection = {
|
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
|
||||||
this.setState({
|
|
||||||
selectedRows: selectedRows,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (this.props.apiUrl) {
|
|
||||||
this.fetch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rerender component when parameters change
|
|
||||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
|
||||||
if (prevProps.apiUrl !== this.props.apiUrl) {
|
|
||||||
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 invokerss
|
|
||||||
axios
|
|
||||||
.get(this.props.apiUrl + encodedExtraParams)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
const pagination = { ...this.state.pagination };
|
|
||||||
if (
|
|
||||||
res.data.data.devices.length &&
|
|
||||||
res.data.data.devices[0].hasOwnProperty('deviceInfo')
|
|
||||||
) {
|
|
||||||
columns.push({
|
|
||||||
title: 'OS Version',
|
|
||||||
dataIndex: 'deviceInfo',
|
|
||||||
key: 'osVersion',
|
|
||||||
render: deviceInfo => deviceInfo.osVersion,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
data: res.data.data,
|
|
||||||
pagination,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load 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 } = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
rowKey={record =>
|
|
||||||
record.deviceIdentifier +
|
|
||||||
record.enrolmentInfo.owner +
|
|
||||||
record.enrolmentInfo.ownership
|
|
||||||
}
|
|
||||||
dataSource={data.devices}
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: 'small',
|
|
||||||
total: data.count,
|
|
||||||
showTotal: (total, range) =>
|
|
||||||
`showing ${range[0]}-${range[1]} of ${total} devices`,
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={this.rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(deviceTable);
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { Form, Input, Button } from 'antd';
|
|
||||||
|
|
||||||
class Filter extends React.Component {
|
|
||||||
handleSubmit = e => {
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
Object.keys(values).forEach(
|
|
||||||
key => values[key] === undefined && delete values[key],
|
|
||||||
);
|
|
||||||
this.props.callback({}, values);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form layout="inline" onSubmit={this.handleSubmit}>
|
|
||||||
{this.props.fields.map(field => (
|
|
||||||
<Form.Item key={field.name}>
|
|
||||||
{getFieldDecorator(field.name)(
|
|
||||||
<Input placeholder={field.placeholder} />,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
))}
|
|
||||||
<Form.Item>
|
|
||||||
<Button htmlType="submit" shape="circle" icon="search" />
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Form.create({ name: 'horizontal_login' })(Filter);
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { notification, Menu, Icon } from 'antd';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { withConfigContext } from '../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
/*
|
|
||||||
This class for call the logout api by sending request
|
|
||||||
*/
|
|
||||||
class Logout extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
inValid: false,
|
|
||||||
loading: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
This function call the logout api when the request is success
|
|
||||||
*/
|
|
||||||
handleSubmit = () => {
|
|
||||||
const thisForm = this;
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
thisForm.setState({
|
|
||||||
inValid: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
axios
|
|
||||||
.post(window.location.origin + config.serverConfig.logoutUri)
|
|
||||||
.then(res => {
|
|
||||||
// if the api call status is correct then user will logout and then it goes to login page
|
|
||||||
if (res.status === 200) {
|
|
||||||
window.location = window.location.origin + '/entgra/login';
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(function(error) {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 400) {
|
|
||||||
thisForm.setState({
|
|
||||||
inValid: true,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to logout.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item key="1" onClick={this.handleSubmit}>
|
|
||||||
<Icon type="logout" />
|
|
||||||
Logout
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Logout);
|
|
||||||
@ -1,194 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Layout, Menu, Icon } from 'antd';
|
|
||||||
import { Switch, Link } from 'react-router-dom';
|
|
||||||
import RouteWithSubRoutes from '../../components/RouteWithSubRoutes';
|
|
||||||
import './styles.css';
|
|
||||||
import { withConfigContext } from '../../components/ConfigContext';
|
|
||||||
import Logout from './components/Logout';
|
|
||||||
|
|
||||||
const { Header, Content, Footer } = Layout;
|
|
||||||
const { SubMenu } = Menu;
|
|
||||||
|
|
||||||
class Home extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
const mobileWidth = window.innerWidth <= 768 ? '0' : '80';
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
routes: props.routes,
|
|
||||||
selectedKeys: [],
|
|
||||||
deviceTypes: [],
|
|
||||||
isNavBarCollapsed: false,
|
|
||||||
mobileWidth,
|
|
||||||
};
|
|
||||||
this.logo = this.props.context.theme.logo;
|
|
||||||
this.config = this.props.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle = () => {
|
|
||||||
console.log(this.config);
|
|
||||||
this.setState({
|
|
||||||
isNavBarCollapsed: !this.state.isNavBarCollapsed,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Layout className="layout">
|
|
||||||
<Layout>
|
|
||||||
<Header style={{ background: '#fff', padding: 0 }}>
|
|
||||||
<div className="logo-image">
|
|
||||||
<Link to="/entgra">
|
|
||||||
<img alt="logo" src={this.logo} />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Menu
|
|
||||||
theme="light"
|
|
||||||
mode="horizontal"
|
|
||||||
style={{
|
|
||||||
lineHeight: '64px',
|
|
||||||
marginRight: 110,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SubMenu
|
|
||||||
key="devices"
|
|
||||||
title={
|
|
||||||
<span>
|
|
||||||
<Icon type="appstore" />
|
|
||||||
<span>Devices</span>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Menu.Item key="devices">
|
|
||||||
<Link to="/entgra/devices">
|
|
||||||
<span>View</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="deviceEnroll">
|
|
||||||
<Link to="/entgra/devices/enroll">
|
|
||||||
<span>Enroll</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</SubMenu>
|
|
||||||
<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/configurations/certificates">
|
|
||||||
<span>Certificates</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
</SubMenu>
|
|
||||||
<Menu.Item key="deviceLocations">
|
|
||||||
<Link to="/entgra/device-locations">
|
|
||||||
<Icon type="environment" />
|
|
||||||
<span>Device Location</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item className="profile" key="Notifications">
|
|
||||||
<Link to="/entgra/notifications">
|
|
||||||
<span>Notifications</span>
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<SubMenu
|
|
||||||
className="profile"
|
|
||||||
title={
|
|
||||||
<span className="submenu-title-wrapper">
|
|
||||||
<Icon type="user" />
|
|
||||||
{this.config.user}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Logout />
|
|
||||||
</SubMenu>
|
|
||||||
</Menu>
|
|
||||||
</Header>
|
|
||||||
|
|
||||||
<Content>
|
|
||||||
<Switch>
|
|
||||||
{this.state.routes.map(route => (
|
|
||||||
<RouteWithSubRoutes key={route.path} {...route} />
|
|
||||||
))}
|
|
||||||
</Switch>
|
|
||||||
</Content>
|
|
||||||
|
|
||||||
<Footer style={{ textAlign: 'center' }}>©2019 entgra.io</Footer>
|
|
||||||
</Layout>
|
|
||||||
</Layout>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Home);
|
|
||||||
@ -1,262 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import {
|
|
||||||
Icon,
|
|
||||||
message,
|
|
||||||
notification,
|
|
||||||
Popconfirm,
|
|
||||||
Table,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
} from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import Moment from 'react-moment';
|
|
||||||
|
|
||||||
const { Paragraph, Text } = Typography;
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
|
|
||||||
class CertificateTable extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
config = this.props.context;
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
pagination: {},
|
|
||||||
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,
|
|
||||||
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() {
|
|
||||||
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);
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import CertificateTable from './components/CertificateTable';
|
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
|
||||||
|
|
||||||
class Certificates extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra/devices">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Configurations</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Certificates</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Certificates</h3>
|
|
||||||
<Paragraph>Certificate configurations</Paragraph>
|
|
||||||
</div>
|
|
||||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
|
||||||
<CertificateTable />
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Certificates;
|
|
||||||
@ -1,254 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { Map, TileLayer, Marker, Popup, CircleMarker } from 'react-leaflet';
|
|
||||||
import L from 'leaflet';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { message, notification } from 'antd';
|
|
||||||
|
|
||||||
// const { Title, Text } = Typography;
|
|
||||||
|
|
||||||
// Icons for the location markers
|
|
||||||
const pinStart = new L.Icon({
|
|
||||||
iconUrl: require('./pin_start.svg'),
|
|
||||||
iconRetinaUrl: require('./pin_start.svg'),
|
|
||||||
shadowUrl: require('./pin_shadow.svg'),
|
|
||||||
shadowSize: new L.Point(51, 51),
|
|
||||||
shadowAnchor: [22, 22],
|
|
||||||
popupAnchor: [0, -22],
|
|
||||||
iconSize: new L.Point(50, 50),
|
|
||||||
tooltipAnchor: [0, -22],
|
|
||||||
});
|
|
||||||
|
|
||||||
class DeviceLocationMap extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.customMap = React.createRef();
|
|
||||||
this.state = {
|
|
||||||
defaultZoomLevel: 3,
|
|
||||||
locations: [],
|
|
||||||
deviceData: {},
|
|
||||||
minLatitute: -37.43997405227057,
|
|
||||||
maxLatitute: 37.43997405227057,
|
|
||||||
minLongtitute: -151.171875,
|
|
||||||
maxLongtitute: 151.34765625,
|
|
||||||
zoomLevel: 3,
|
|
||||||
deviceName: null,
|
|
||||||
isPopup: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.getDeviceLocations(
|
|
||||||
-37.43997405227057,
|
|
||||||
37.43997405227057,
|
|
||||||
-151.171875,
|
|
||||||
151.34765625,
|
|
||||||
3,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getDeviceLocations = (
|
|
||||||
minLatitute,
|
|
||||||
maxLatitute,
|
|
||||||
minLongtitute,
|
|
||||||
maxLongtitute,
|
|
||||||
zoomLevel,
|
|
||||||
) => {
|
|
||||||
axios
|
|
||||||
.get(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/geo-services/1.0.0/stats' +
|
|
||||||
'/device-locations?' +
|
|
||||||
'minLat=' +
|
|
||||||
minLatitute +
|
|
||||||
'&maxLat=' +
|
|
||||||
maxLatitute +
|
|
||||||
'&minLong=' +
|
|
||||||
minLongtitute +
|
|
||||||
'&maxLong=' +
|
|
||||||
maxLongtitute +
|
|
||||||
'&zoom=' +
|
|
||||||
zoomLevel,
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
// console.log(JSON.parse(res.data.data));
|
|
||||||
this.setState({
|
|
||||||
locations: JSON.parse(res.data.data),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to fetch locations......',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
setMarkers = positions => {
|
|
||||||
let markers = [];
|
|
||||||
positions.map(location => {
|
|
||||||
if (location.count > 1) {
|
|
||||||
markers.push(
|
|
||||||
<CircleMarker
|
|
||||||
key={location.deviceIdentification}
|
|
||||||
center={[
|
|
||||||
location.coordinates.latitude,
|
|
||||||
location.coordinates.longitude,
|
|
||||||
]}
|
|
||||||
radius={10}
|
|
||||||
fillOpacity={1}
|
|
||||||
color={'#c0392b'}
|
|
||||||
stroke={false}
|
|
||||||
>
|
|
||||||
<Popup>{location.count}</Popup>
|
|
||||||
</CircleMarker>,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
markers.push(
|
|
||||||
<Marker
|
|
||||||
key={location.deviceIdentification}
|
|
||||||
icon={pinStart}
|
|
||||||
position={[
|
|
||||||
location.coordinates.latitude,
|
|
||||||
location.coordinates.longitude,
|
|
||||||
]}
|
|
||||||
onMouseOver={this
|
|
||||||
.mouseOver
|
|
||||||
// location.deviceType,
|
|
||||||
// location.deviceIdentification,
|
|
||||||
()}
|
|
||||||
onMouseOut={this.mouseOut}
|
|
||||||
>
|
|
||||||
<Popup
|
|
||||||
autoClose={true}
|
|
||||||
style={{ display: this.state.isPopup ? 'block' : 'none' }}
|
|
||||||
>
|
|
||||||
{/* {this.getPopupData(*/}
|
|
||||||
{/* // location.deviceType, // location.deviceIdentification, // )}*/}
|
|
||||||
{/* {this.state.deviceData.name}*/}
|
|
||||||
{this.state.deviceName}
|
|
||||||
</Popup>
|
|
||||||
</Marker>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{markers.map(markker => {
|
|
||||||
return markker;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
mouseOut = () => {
|
|
||||||
this.setState({
|
|
||||||
isPopup: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// todo get device details when mouse over the maker
|
|
||||||
mouseOver = (deviceType, deviceIdentification) => {
|
|
||||||
// let aaa = null;
|
|
||||||
// axios
|
|
||||||
// .get(
|
|
||||||
// window.location.origin +
|
|
||||||
// this.config.serverConfig.invoker.uri +
|
|
||||||
// this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
// `/devices/1.0.0/${deviceType}/${deviceIdentification}`,
|
|
||||||
// )
|
|
||||||
// .then(res => {
|
|
||||||
// if (res.status === 200) {
|
|
||||||
// // console.log(res.data.data);
|
|
||||||
// this.setState({
|
|
||||||
// deviceData: res.data.data,
|
|
||||||
// isPopup: true,
|
|
||||||
// });
|
|
||||||
// // aaa = res.data.data;
|
|
||||||
// // return (
|
|
||||||
// // <div>
|
|
||||||
// // <Title>{aaa.name}</Title>
|
|
||||||
// // <Row>
|
|
||||||
// // <Text> Type : {aaa.type}</Text>
|
|
||||||
// // </Row>
|
|
||||||
// // <Row>
|
|
||||||
// // <Text> Status : {aaa.enrolmentInfo.status}</Text>
|
|
||||||
// // </Row>
|
|
||||||
// // <Row>
|
|
||||||
// // <Text> Owner : {aaa.enrolmentInfo.owner}</Text>
|
|
||||||
// // </Row>
|
|
||||||
// // </div>
|
|
||||||
// // );
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .catch(error => {
|
|
||||||
// if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// message.error('You are not logged in');
|
|
||||||
// window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
// } else {
|
|
||||||
// notification.error({
|
|
||||||
// message: 'There was a problem',
|
|
||||||
// duration: 0,
|
|
||||||
// description: 'Error occurred while trying to fetch locations......',
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
|
|
||||||
// Todo : get bound and zoom level when doing movement and pass id to getDeviceLocations function
|
|
||||||
handleMovements = event => {
|
|
||||||
console.log(this.customMap.current.leafletElement.getZoom());
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const position = [this.state.lat, this.state.lng];
|
|
||||||
const attribution = this.config.geoMap.attribution;
|
|
||||||
const url = this.config.geoMap.url;
|
|
||||||
return (
|
|
||||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5, padding: 5 }}>
|
|
||||||
<Map
|
|
||||||
ref={this.customMap}
|
|
||||||
center={position}
|
|
||||||
zoom={this.state.defaultZoomLevel}
|
|
||||||
resize={this.onResize}
|
|
||||||
onMoveEnd={this.handleMovements}
|
|
||||||
>
|
|
||||||
<TileLayer url={url} attribution={attribution} />
|
|
||||||
{this.setMarkers(this.state.locations)}
|
|
||||||
</Map>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(DeviceLocationMap);
|
|
||||||
|
Before Width: | Height: | Size: 69 KiB |
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><style>.a{fill:#414042;}.b{fill:#fff;}</style></defs><title>map</title><circle class="a" cx="50" cy="50" r="40.2134"/><circle class="b" cx="50" cy="50" r="18.64704"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 240 B |
@ -1,39 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Breadcrumb, PageHeader } from 'antd';
|
|
||||||
import DeviceLocationMap from './Component/DeviceLocationMap';
|
|
||||||
|
|
||||||
class DeviceLocations extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>Devices Location</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Devices Location </h3>
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: '#f0f2f5',
|
|
||||||
padding: 24,
|
|
||||||
minHeight: 720,
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DeviceLocationMap />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DeviceLocations;
|
|
||||||
@ -1,130 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Card, Col, Icon, message, notification, Row } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
let apiUrl;
|
|
||||||
|
|
||||||
class Index extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetchUsers();
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
fetchUsers = (params = {}) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/device-types';
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
const pagination = { ...this.state.pagination };
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
data: JSON.parse(res.data.data),
|
|
||||||
pagination,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load device types.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = { ...this.state.pagination };
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetch({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { data } = 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(Index);
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import DeviceTypesTable from './components/DeviceTypesTable';
|
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
|
||||||
|
|
||||||
class DeviceTypes extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Device Types</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Device Types</h3>
|
|
||||||
<Paragraph>All device types for device management.</Paragraph>
|
|
||||||
</div>
|
|
||||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
|
||||||
<DeviceTypesTable />
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DeviceTypes;
|
|
||||||
@ -1,133 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Button, Tooltip, Popconfirm, Divider } from 'antd';
|
|
||||||
|
|
||||||
class BulkActionBar extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
selectedMultiple: false,
|
|
||||||
selectedSingle: false,
|
|
||||||
canDelete: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method checks whether NON-REMOVED devices are selected
|
|
||||||
onDeleteDeviceCall = () => {
|
|
||||||
let tempDeleteState;
|
|
||||||
for (let i = 0; i < this.props.selectedRows.length; i++) {
|
|
||||||
if (this.props.selectedRows[i].enrolmentInfo.status != 'REMOVED') {
|
|
||||||
tempDeleteState = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tempDeleteState = true;
|
|
||||||
}
|
|
||||||
this.setState({ canDelete: tempDeleteState });
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmDelete = () => {
|
|
||||||
if (this.state.canDelete) {
|
|
||||||
this.props.deleteDevice();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmDisenroll = () => {
|
|
||||||
this.props.disenrollDevice();
|
|
||||||
};
|
|
||||||
|
|
||||||
onDeviceGroupCall = () => {
|
|
||||||
this.props.getGroups();
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const isSelected = this.props.selectedRows.length > 0;
|
|
||||||
const isSelectedSingle = this.props.selectedRows.length == 1;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ display: isSelected ? 'inline' : 'none', padding: '11px' }}>
|
|
||||||
<Tooltip
|
|
||||||
placement="bottom"
|
|
||||||
title={'Delete Device'}
|
|
||||||
autoAdjustOverflow={true}
|
|
||||||
>
|
|
||||||
<Popconfirm
|
|
||||||
placement="topLeft"
|
|
||||||
title={
|
|
||||||
this.state.canDelete
|
|
||||||
? 'Are you sure you want to delete?'
|
|
||||||
: 'You can only delete disenrolled devices'
|
|
||||||
}
|
|
||||||
onConfirm={this.onConfirmDelete}
|
|
||||||
okText="Ok"
|
|
||||||
cancelText="Cancel"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="delete"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.onDeleteDeviceCall}
|
|
||||||
disabled={!isSelected}
|
|
||||||
style={{ margin: '2px' }}
|
|
||||||
/>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="bottom" title={'Disenroll Device'}>
|
|
||||||
<Popconfirm
|
|
||||||
placement="topLeft"
|
|
||||||
title={'Are you sure?'}
|
|
||||||
onConfirm={this.onConfirmDisenroll}
|
|
||||||
okText="Ok"
|
|
||||||
disabled={!isSelectedSingle}
|
|
||||||
cancelText="Cancel"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="close"
|
|
||||||
size={'default'}
|
|
||||||
style={{
|
|
||||||
display: isSelectedSingle ? 'inline' : 'none',
|
|
||||||
margin: '2px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider
|
|
||||||
type="vertical"
|
|
||||||
style={{ display: isSelectedSingle ? 'inline-block' : 'none' }}
|
|
||||||
/>
|
|
||||||
<Tooltip placement="bottom" title={'Add to group'}>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="deployment-unit"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.onDeviceGroupCall}
|
|
||||||
style={{ margin: '2px' }}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BulkActionBar;
|
|
||||||
@ -1,553 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import {
|
|
||||||
Icon,
|
|
||||||
message,
|
|
||||||
Modal,
|
|
||||||
notification,
|
|
||||||
Select,
|
|
||||||
Table,
|
|
||||||
Tag,
|
|
||||||
Tooltip,
|
|
||||||
} from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import BulkActionBar from './components/BulkActionBar';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
title: 'Device',
|
|
||||||
dataIndex: 'name',
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Type',
|
|
||||||
dataIndex: 'type',
|
|
||||||
key: 'type',
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
render: type => {
|
|
||||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
|
||||||
let icon = defaultPlatformIcons.default.icon;
|
|
||||||
let color = defaultPlatformIcons.default.color;
|
|
||||||
let theme = defaultPlatformIcons.default.theme;
|
|
||||||
|
|
||||||
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
|
||||||
icon = defaultPlatformIcons[type].icon;
|
|
||||||
color = defaultPlatformIcons[type].color;
|
|
||||||
theme = defaultPlatformIcons[type].theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
|
|
||||||
<Icon type={icon} theme={theme} />
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Owner',
|
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'owner',
|
|
||||||
render: enrolmentInfo => enrolmentInfo.owner,
|
|
||||||
// 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: 'Last Updated',
|
|
||||||
dataIndex: 'enrolmentInfo',
|
|
||||||
key: 'dateOfLastUpdate',
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
render: data => {
|
|
||||||
const { dateOfLastUpdate } = data;
|
|
||||||
const timeAgoString = getTimeAgo(dateOfLastUpdate);
|
|
||||||
return (
|
|
||||||
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
|
|
||||||
{timeAgoString}
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
dataIndex: 'deviceIdentifier',
|
|
||||||
key: 'actions',
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
render: (data, row) => {
|
|
||||||
const { type, deviceIdentifier } = row;
|
|
||||||
return (
|
|
||||||
<Link to={`/entgra/geo/history/${type}/${deviceIdentifier}`}>
|
|
||||||
<Icon type="environment" /> Location History
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getTimeAgo = time => {
|
|
||||||
const timeAgo = new TimeAgo('en-US');
|
|
||||||
return timeAgo.format(time);
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeviceTable extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
config = this.props.context;
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
deviceGroups: [],
|
|
||||||
groupModalVisible: false,
|
|
||||||
selectedGroupId: [],
|
|
||||||
selectedRowKeys: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetch();
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
fetch = (params = {}) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
// get current page
|
|
||||||
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
|
||||||
|
|
||||||
const extraParams = {
|
|
||||||
offset: 10 * (currentPage - 1), // calculate the offset
|
|
||||||
limit: 10,
|
|
||||||
requireDeviceInfo: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
|
||||||
.map(key => key + '=' + extraParams[key])
|
|
||||||
.join('&');
|
|
||||||
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.get(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/devices?' +
|
|
||||||
encodedExtraParams,
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
const pagination = { ...this.state.pagination };
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
data: res.data.data.devices,
|
|
||||||
pagination,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load devices.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
deleteDevice = () => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
const deviceData = this.state.selectedRows.map(obj => obj.deviceIdentifier);
|
|
||||||
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.put(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/admin/devices/permanent-delete',
|
|
||||||
deviceData,
|
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetch();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to delete devices.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
disenrollDevice = () => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
const deviceData = this.state.selectedRows[0];
|
|
||||||
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.delete(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/devices/type/' +
|
|
||||||
deviceData.type +
|
|
||||||
'/id/' +
|
|
||||||
deviceData.deviceIdentifier,
|
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetch();
|
|
||||||
this.setState({
|
|
||||||
selectedRowKeys: [],
|
|
||||||
});
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully dis-enrolled the device.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to dis-enroll devices.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
addDevicesToGroup = groupId => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
let apiUrl;
|
|
||||||
let deviceData;
|
|
||||||
if (this.state.selectedRows.length === 1) {
|
|
||||||
apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/groups/device/assign';
|
|
||||||
deviceData = {
|
|
||||||
deviceIdentifier: {
|
|
||||||
id: this.state.selectedRows[0].deviceIdentifier,
|
|
||||||
type: this.state.selectedRows[0].type,
|
|
||||||
},
|
|
||||||
deviceGroupIds: groupId,
|
|
||||||
};
|
|
||||||
} else if (!groupId[0]) {
|
|
||||||
apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/groups/id/' +
|
|
||||||
groupId +
|
|
||||||
'/devices/add';
|
|
||||||
deviceData = this.state.selectedRows.map(obj => ({
|
|
||||||
id: obj.deviceIdentifier,
|
|
||||||
type: obj.type,
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/groups/id/' +
|
|
||||||
groupId[0] +
|
|
||||||
'/devices/add';
|
|
||||||
deviceData = this.state.selectedRows.map(obj => ({
|
|
||||||
id: obj.deviceIdentifier,
|
|
||||||
type: obj.type,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import DeviceTable from './components/DevicesTable';
|
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
|
||||||
|
|
||||||
class Devices extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra/devices">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Devices</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Devices</h3>
|
|
||||||
<Paragraph>All enrolled devices</Paragraph>
|
|
||||||
</div>
|
|
||||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
|
||||||
<DeviceTable />
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Devices;
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Card, Col, Icon, Row } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
class DeviceType extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
data: this.config.deviceTypes,
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickCard = (e, deviceType) => {
|
|
||||||
this.props.getDeviceType(deviceType);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { data } = this.state;
|
|
||||||
const { Meta } = Card;
|
|
||||||
const itemCard = data.map(data => (
|
|
||||||
<Col span={5} key={data.id}>
|
|
||||||
<Card
|
|
||||||
size="default"
|
|
||||||
style={{ width: 150 }}
|
|
||||||
bordered={true}
|
|
||||||
onClick={e => this.onClickCard(e, data.name)}
|
|
||||||
cover={
|
|
||||||
<Icon
|
|
||||||
type="android"
|
|
||||||
key="device-types"
|
|
||||||
style={{
|
|
||||||
color: '#ffffff',
|
|
||||||
backgroundColor: '#4b92db',
|
|
||||||
fontSize: '100px',
|
|
||||||
padding: '20px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Meta title={data.name} />
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
));
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row gutter={16}>{itemCard}</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(DeviceType);
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Form, Row, Col, Card, Steps } from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import DeviceType from './components/DeviceType';
|
|
||||||
import SelectEnrollmentType from '../SelectEnrolmentType';
|
|
||||||
import EnrollDevice from '../EnrollDevice';
|
|
||||||
import DownloadAgent from '../DownloadAgent';
|
|
||||||
const { Step } = Steps;
|
|
||||||
|
|
||||||
class AddDevice extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
isAddDeviceModalVisible: false,
|
|
||||||
current: 0,
|
|
||||||
deviceType: 'android',
|
|
||||||
enrollmentType: 'qr',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getDeviceType = deviceType => {
|
|
||||||
this.setState({
|
|
||||||
current: 1,
|
|
||||||
deviceType: deviceType,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
goNext = () => {
|
|
||||||
this.setState({
|
|
||||||
current: 2,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
goBackToDeviceType = () => {
|
|
||||||
this.setState({
|
|
||||||
current: 0,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
goBackToDownloadAgent = () => {
|
|
||||||
this.setState({
|
|
||||||
current: 1,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
goBackToEnrollmentType = () => {
|
|
||||||
this.setState({
|
|
||||||
current: 2,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getEnrollmentData = enrollmentType => {
|
|
||||||
this.setState({
|
|
||||||
current: 3,
|
|
||||||
enrollmentType: enrollmentType,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { current, deviceType, enrollmentType } = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col span={16} offset={4}>
|
|
||||||
<Steps style={{ minHeight: 32 }} current={current}>
|
|
||||||
<Step key="DeviceType" title="Select Device Type" />
|
|
||||||
<Step key="DownloadAgent" title="Download Agent" />
|
|
||||||
<Step key="EnrollmentType" title="Enrollment Type" />
|
|
||||||
<Step key="EnrollDevice" title="Enroll Device" />
|
|
||||||
</Steps>
|
|
||||||
</Col>
|
|
||||||
<Col span={16} offset={4}>
|
|
||||||
<Card style={{ marginTop: 24 }}>
|
|
||||||
<div style={{ display: current === 0 ? 'unset' : 'none' }}>
|
|
||||||
<DeviceType getDeviceType={this.getDeviceType} />
|
|
||||||
</div>
|
|
||||||
<div style={{ display: current === 1 ? 'unset' : 'none' }}>
|
|
||||||
<DownloadAgent
|
|
||||||
deviceType={deviceType}
|
|
||||||
goNext={this.goNext}
|
|
||||||
goBack={this.goBackToDeviceType}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: current === 2 ? 'unset' : 'none' }}>
|
|
||||||
<SelectEnrollmentType
|
|
||||||
deviceType={deviceType}
|
|
||||||
getEnrollmentData={this.getEnrollmentData}
|
|
||||||
goBack={this.goBackToDownloadAgent}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{ display: current === 3 ? 'unset' : 'none' }}>
|
|
||||||
<EnrollDevice
|
|
||||||
deviceType={deviceType}
|
|
||||||
enrollmentType={enrollmentType}
|
|
||||||
goBack={this.goBackToEnrollmentType}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(
|
|
||||||
Form.create({ name: 'add-device' })(AddDevice),
|
|
||||||
);
|
|
||||||
@ -1,173 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Button, Card, Divider, message, notification } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago/modules/JavascriptTimeAgo';
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import QRCode from 'qrcode.react';
|
|
||||||
|
|
||||||
class DownloadAgent extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
buttonTitle: 'Download Agent',
|
|
||||||
skipButtonTitle: 'Skip',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickSkip = () => {
|
|
||||||
this.props.goNext();
|
|
||||||
};
|
|
||||||
|
|
||||||
onClickGoBack = () => {
|
|
||||||
this.props.goBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
onClickDownloadAgent = () => {
|
|
||||||
this.downloadAgent();
|
|
||||||
};
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
downloadAgent = () => {
|
|
||||||
const { deviceType } = this.props;
|
|
||||||
this.setState({ loading: true, buttonTitle: 'Downloading..' });
|
|
||||||
|
|
||||||
const apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
'/api/application-mgt/v1.0/artifact/' +
|
|
||||||
deviceType +
|
|
||||||
'/agent/-1234';
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
// Download file in same window
|
|
||||||
const url = window.URL.createObjectURL(new Blob([res.data]));
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = url;
|
|
||||||
link.setAttribute('download', 'android-agent.apk'); // or any other extension
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
buttonTitle: 'Download Agent',
|
|
||||||
skipButtonTitle: 'Next',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 download Entgra Android Agent',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { loading, buttonTitle, skipButtonTitle } = this.state;
|
|
||||||
const { deviceType } = this.props;
|
|
||||||
|
|
||||||
const apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
'/api/application-mgt/v1.0/artifact/' +
|
|
||||||
deviceType +
|
|
||||||
'/agent/-1234';
|
|
||||||
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', textAlign: 'center' }}>
|
|
||||||
<Divider>Scan to get the Android Agent.</Divider>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
marginBottm: 10,
|
|
||||||
display: 'inline-block',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Card hoverable>
|
|
||||||
<QRCode size={200} value={apiUrl} />
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
<Divider>OR</Divider>
|
|
||||||
<div style={{ textAlign: 'center', marginTop: 10, marginBottom: 10 }}>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.onClickDownloadAgent}
|
|
||||||
loading={loading}
|
|
||||||
>
|
|
||||||
{buttonTitle}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
Need help? Read
|
|
||||||
<a
|
|
||||||
href={
|
|
||||||
'https://entgra-documentation.gitlab.io/v3.8.0/docs/guide-to-work-with-the-product/' +
|
|
||||||
'enrollment-guide/enroll-android/'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Entgra IoT Server documentation.
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div style={{ textAlign: 'right' }}>
|
|
||||||
<Button type="primary" size={'default'} onClick={this.onClickSkip}>
|
|
||||||
{skipButtonTitle}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
style={{ marginLeft: 10 }}
|
|
||||||
type="default"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.onClickGoBack}
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(DownloadAgent);
|
|
||||||
@ -1,217 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Divider,
|
|
||||||
message,
|
|
||||||
notification,
|
|
||||||
Select,
|
|
||||||
Card,
|
|
||||||
Spin,
|
|
||||||
Button,
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
} from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago/modules/JavascriptTimeAgo';
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import axios from 'axios';
|
|
||||||
import QRCode from 'qrcode.react';
|
|
||||||
import QRPlaceholder from '../../../../../../../../../public/images/qr-code.png';
|
|
||||||
import installAgent from '../../../../../../../../../public/images/install_agent.png';
|
|
||||||
import register from '../../../../../../../../../public/images/register.png';
|
|
||||||
import registration from '../../../../../../../../../public/images/registration.png';
|
|
||||||
import setProfile from '../../../../../../../../../public/images/set_profile.png';
|
|
||||||
|
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
class EnrollDevice extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
isSelected: false,
|
|
||||||
loading: false,
|
|
||||||
payload: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
generateQRCode = ownershipType => {
|
|
||||||
const { deviceType } = this.props;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
'/device-mgt/' +
|
|
||||||
deviceType +
|
|
||||||
'/v1.0/configuration/enrollment-qr-config/' +
|
|
||||||
ownershipType;
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
payload: res.data.data,
|
|
||||||
isSelected: 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 get QR code payload.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onChange = value => {
|
|
||||||
this.generateQRCode(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
onClick = () => {
|
|
||||||
this.props.goBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { payload, isSelected, loading } = this.state;
|
|
||||||
const { enrollmentType } = this.props;
|
|
||||||
return (
|
|
||||||
<div style={{ textAlign: 'center', fontSize: 12 }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: enrollmentType === 'manual' ? 'inline-block' : 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Row gutter={[16, 16]}>
|
|
||||||
<Col span={6}>
|
|
||||||
<h1>Step 1</h1>
|
|
||||||
<p>
|
|
||||||
{/* eslint-disable-next-line react/no-unescaped-entities */}
|
|
||||||
Let's start by installing the Android agent on your device. Open
|
|
||||||
the downloaded file, and tap INSTALL.
|
|
||||||
</p>
|
|
||||||
<img src={installAgent} />
|
|
||||||
</Col>
|
|
||||||
<Col span={6}>
|
|
||||||
<h1>Step 2</h1>
|
|
||||||
<p>Tap Skip to proceed with the default enrollment process.</p>
|
|
||||||
<img src={setProfile} />
|
|
||||||
</Col>
|
|
||||||
<Col span={6}>
|
|
||||||
<h1>Step 3</h1>
|
|
||||||
<p>
|
|
||||||
Enter the server address based on your environment, in the text
|
|
||||||
box provided.
|
|
||||||
</p>
|
|
||||||
<img src={registration} />
|
|
||||||
</Col>
|
|
||||||
<Col span={6}>
|
|
||||||
<h1>Step 4</h1>
|
|
||||||
<p>Enter your:</p>
|
|
||||||
<div>
|
|
||||||
<p>Organization: carbon.super</p>
|
|
||||||
<p>Username: admin</p>
|
|
||||||
<p>Password: Your password</p>
|
|
||||||
</div>
|
|
||||||
<img src={register} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: enrollmentType === 'qr' ? 'inline-block' : 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Divider>Generate QR code to QR based Provisioning.</Divider>
|
|
||||||
<div style={{ textAlign: 'center' }}>
|
|
||||||
<div style={{ marginBottom: 10 }}>
|
|
||||||
<Select
|
|
||||||
showSearch
|
|
||||||
style={{ width: 200, textAlign: 'center' }}
|
|
||||||
placeholder="Select device ownership"
|
|
||||||
optionFilterProp="children"
|
|
||||||
onChange={this.onChange}
|
|
||||||
filterOption={(input, option) =>
|
|
||||||
option.props.children
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(input.toLowerCase()) >= 0
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Option key={'byod'} value={'BYOD'}>
|
|
||||||
{'BYOD'}
|
|
||||||
</Option>
|
|
||||||
<Option key={'cope'} value={'COPE'}>
|
|
||||||
{'COPE'}
|
|
||||||
</Option>
|
|
||||||
<Option key={'COSU'} value={'COSU'}>
|
|
||||||
{'COSU (KIOSK)'}
|
|
||||||
</Option>
|
|
||||||
<Option key={'WORK PROFILE'} value={'WORK_PROFILE'}>
|
|
||||||
{'WORK PROFILE'}
|
|
||||||
</Option>
|
|
||||||
<Option key={'GOOGLE_ENTERPRISE'} value={'GOOGLE_ENTERPRISE'}>
|
|
||||||
{'GOOGLE_WORK_PROFILE'}
|
|
||||||
</Option>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
<Spin spinning={loading}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: isSelected ? 'inline-block' : 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Card hoverable>
|
|
||||||
<QRCode size={300} value={JSON.stringify(payload)} />
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: !isSelected ? 'inline-block' : 'none' }}>
|
|
||||||
<Card hoverable>
|
|
||||||
<img src={QRPlaceholder} />
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</Spin>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ textAlign: 'right', marginTop: 10 }}>
|
|
||||||
<Button type="default" size={'default'} onClick={this.onClick}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(EnrollDevice);
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Button, Divider } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago/modules/JavascriptTimeAgo';
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
class SelectEnrollmentType extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onEnrollWithQR = () => {
|
|
||||||
this.props.getEnrollmentData('qr');
|
|
||||||
};
|
|
||||||
|
|
||||||
onEnrollManually = () => {
|
|
||||||
this.props.getEnrollmentData('manual');
|
|
||||||
};
|
|
||||||
|
|
||||||
onClick = () => {
|
|
||||||
this.props.goBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Divider orientation="left">
|
|
||||||
Step 02 - Enroll the Android Agent.
|
|
||||||
</Divider>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
{' '}
|
|
||||||
Your device can be enrolled with Entgra IoTS automatically via QR
|
|
||||||
code. To enroll first download agent as mentioned in Step 1 then
|
|
||||||
proceed with the ENROLL WITH QR option from the device setup
|
|
||||||
activity. Thereafter select the ownership configuration and scan the
|
|
||||||
generated QR to complete the process.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div style={{ margin: '30px' }}>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.onEnrollWithQR}
|
|
||||||
style={{ marginRight: 10 }}
|
|
||||||
>
|
|
||||||
Enroll Using QR
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.onEnrollManually}
|
|
||||||
>
|
|
||||||
Enroll Manually
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div style={{ textAlign: 'right' }}>
|
|
||||||
<Button type="default" size={'default'} onClick={this.onClick}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(SelectEnrollmentType);
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import AddDevice from './components/AddDevice';
|
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
|
||||||
|
|
||||||
class DeviceEnroll extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra/devices">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra/devices">Devices</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Enroll Device</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Devices</h3>
|
|
||||||
<Paragraph>All enrolled devices</Paragraph>
|
|
||||||
</div>
|
|
||||||
<div style={{ borderRadius: 5 }}>
|
|
||||||
<AddDevice />
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DeviceEnroll;
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { Component, Fragment } from 'react';
|
|
||||||
import {
|
|
||||||
Map,
|
|
||||||
TileLayer,
|
|
||||||
Marker,
|
|
||||||
Polyline,
|
|
||||||
Popup,
|
|
||||||
Tooltip,
|
|
||||||
} from 'react-leaflet';
|
|
||||||
import L from 'leaflet';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
// Icons for the location markers
|
|
||||||
const pinStart = new L.Icon({
|
|
||||||
iconUrl: require('./pin_start.svg'),
|
|
||||||
iconRetinaUrl: require('./pin_start.svg'),
|
|
||||||
shadowUrl: require('./pin_shadow.svg'),
|
|
||||||
shadowSize: new L.Point(51, 51),
|
|
||||||
shadowAnchor: [22, 22],
|
|
||||||
popupAnchor: [0, -22],
|
|
||||||
iconSize: new L.Point(50, 50),
|
|
||||||
tooltipAnchor: [0, -22],
|
|
||||||
});
|
|
||||||
const pinEnd = new L.Icon({
|
|
||||||
iconUrl: require('./pin_end.svg'),
|
|
||||||
iconRetinaUrl: require('./pin_end.svg'),
|
|
||||||
shadowUrl: require('./pin_shadow.svg'),
|
|
||||||
shadowSize: new L.Point(51, 51),
|
|
||||||
shadowAnchor: [22, 22],
|
|
||||||
popupAnchor: [0, -22],
|
|
||||||
iconSize: new L.Point(65, 65),
|
|
||||||
tooltipAnchor: [0, -28],
|
|
||||||
});
|
|
||||||
|
|
||||||
class CustomMap extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Polyline draw for historical locations
|
|
||||||
* @param locationHistorySnapshots - location data object
|
|
||||||
* @returns content
|
|
||||||
*/
|
|
||||||
polylineMarker = locationHistorySnapshots => {
|
|
||||||
const polyLines = [];
|
|
||||||
locationHistorySnapshots.forEach(locationHistorySnapshots => {
|
|
||||||
polyLines.push(
|
|
||||||
<Polyline
|
|
||||||
key={polyLines.length}
|
|
||||||
color="#414042"
|
|
||||||
positions={locationHistorySnapshots.map(snapshot => {
|
|
||||||
return [snapshot.latitude, snapshot.longitude];
|
|
||||||
})}
|
|
||||||
smoothFactor={10}
|
|
||||||
weight={5}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let i = 1; i < locationHistorySnapshots.length; i++) {
|
|
||||||
const startPosition = locationHistorySnapshots[i][0];
|
|
||||||
const endingPosition =
|
|
||||||
locationHistorySnapshots[i - 1][
|
|
||||||
locationHistorySnapshots[i - 1].length - 1
|
|
||||||
];
|
|
||||||
polyLines.push(
|
|
||||||
<Polyline
|
|
||||||
key={polyLines.length}
|
|
||||||
color="#414042"
|
|
||||||
positions={[
|
|
||||||
[startPosition.latitude, startPosition.longitude],
|
|
||||||
[endingPosition.latitude, endingPosition.longitude],
|
|
||||||
]}
|
|
||||||
smoothFactor={10}
|
|
||||||
weight={5}
|
|
||||||
dashArray="7"
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ display: 'none' }}>
|
|
||||||
{polyLines.map(polyLine => {
|
|
||||||
return polyLine;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const locationHistorySnapshots = this.props.locationHistorySnapshots;
|
|
||||||
const config = this.props.context;
|
|
||||||
const attribution = config.geoMap.attribution;
|
|
||||||
const url = config.geoMap.url;
|
|
||||||
const firstSnapshot = locationHistorySnapshots[0][0];
|
|
||||||
const lastSnapshotList =
|
|
||||||
locationHistorySnapshots[locationHistorySnapshots.length - 1];
|
|
||||||
const lastSnapshot = lastSnapshotList[lastSnapshotList.length - 1];
|
|
||||||
const startingPoint = [firstSnapshot.latitude, firstSnapshot.longitude];
|
|
||||||
const endPoint = [lastSnapshot.latitude, lastSnapshot.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(locationHistorySnapshots)}
|
|
||||||
<Marker icon={pinStart} position={startingPoint}>
|
|
||||||
<Popup keepInView={true}>Start</Popup>
|
|
||||||
<Tooltip direction="top" permanent={true}>
|
|
||||||
Start
|
|
||||||
</Tooltip>
|
|
||||||
</Marker>
|
|
||||||
<Marker icon={pinEnd} position={endPoint}>
|
|
||||||
<Tooltip direction="top" permanent={true}>
|
|
||||||
End
|
|
||||||
</Tooltip>
|
|
||||||
</Marker>
|
|
||||||
</Fragment>
|
|
||||||
</Map>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(CustomMap);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.80151 122.80151"><defs><style>.a,.b{fill:#8dc63f;}.a{opacity:0.34;}.c{fill:#fff;}</style></defs><title>map</title><circle class="a" cx="61.40076" cy="61.40076" r="57.704"/><circle class="b" cx="61.40076" cy="61.40076" r="40.2134"/><circle class="c" cx="61.40076" cy="61.40076" r="18.64704"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 354 B |
|
Before Width: | Height: | Size: 69 KiB |
@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><style>.a{fill:#414042;}.b{fill:#fff;}</style></defs><title>map</title><circle class="a" cx="50" cy="50" r="40.2134"/><circle class="b" cx="50" cy="50" r="18.64704"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 240 B |
@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import moment from 'moment';
|
|
||||||
import { message, notification, Empty, DatePicker } from 'antd';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import GeoCustomMap from '../CustomMap';
|
|
||||||
import './styles.css';
|
|
||||||
|
|
||||||
class GeoDashboard extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
let start = moment(
|
|
||||||
new Date(
|
|
||||||
new Date().getFullYear(),
|
|
||||||
new Date().getMonth(),
|
|
||||||
new Date().getDate(),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let end = moment(start)
|
|
||||||
.add(1, 'days')
|
|
||||||
.subtract(1, 'seconds');
|
|
||||||
this.state = {
|
|
||||||
deviceData: [],
|
|
||||||
selectedDevice: '',
|
|
||||||
locationHistorySnapshots: [],
|
|
||||||
loading: false,
|
|
||||||
start: start,
|
|
||||||
end: end,
|
|
||||||
buttonTooltip: 'Fetch Locations',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetchLocationHistory();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Call back on apply button in the date time picker
|
|
||||||
* @param startDate - start date
|
|
||||||
* @param endDate - end date
|
|
||||||
*/
|
|
||||||
applyCallback = (dates, dateStrings) => {
|
|
||||||
this.setState({
|
|
||||||
start: dateStrings[0],
|
|
||||||
end: dateStrings[1],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchLocationHistory = () => {
|
|
||||||
const toInMills = moment(this.state.end);
|
|
||||||
const fromInMills = moment(this.state.start);
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
axios
|
|
||||||
.get(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/devices/' +
|
|
||||||
this.props.deviceType +
|
|
||||||
'/' +
|
|
||||||
this.props.deviceIdentifier +
|
|
||||||
'/location-history?' +
|
|
||||||
'from=' +
|
|
||||||
fromInMills +
|
|
||||||
'&to=' +
|
|
||||||
toInMills,
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
locationHistorySnapshots: res.data.data.locationHistorySnapshots,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to fetch locations......',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)],
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="controllerDiv">
|
|
||||||
<RangePicker
|
|
||||||
ranges={ranges}
|
|
||||||
style={{ marginRight: 20, width: 400 }}
|
|
||||||
showTime
|
|
||||||
format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
defaultValue={[this.state.start, this.state.end]}
|
|
||||||
onChange={this.applyCallback}
|
|
||||||
onOk={this.fetchLocationHistory}
|
|
||||||
size="large"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { locationHistorySnapshots } = this.state;
|
|
||||||
return (
|
|
||||||
<div className="container">
|
|
||||||
{this.controllerBar()}
|
|
||||||
{locationHistorySnapshots.length > 0 ? (
|
|
||||||
<GeoCustomMap locationHistorySnapshots={locationHistorySnapshots} />
|
|
||||||
) : (
|
|
||||||
<Empty />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(GeoDashboard);
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
.leaflet-container {
|
|
||||||
align-content: center;
|
|
||||||
padding-top: 80px;
|
|
||||||
height: 550px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.controllerDiv {
|
|
||||||
padding-bottom: 30px;
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import GeoDashboard from './components/GeoDashboard';
|
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
|
||||||
|
|
||||||
class Geo extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { deviceIdentifier, deviceType } = this.props.match.params;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">Devices</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>{`Location History - ${deviceType} / ${deviceIdentifier}`}</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Location History </h3>
|
|
||||||
<Paragraph>{`${deviceType} / ${deviceIdentifier}`}</Paragraph>
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: '#f0f2f5',
|
|
||||||
padding: 24,
|
|
||||||
minHeight: 720,
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<GeoDashboard
|
|
||||||
deviceIdentifier={deviceIdentifier}
|
|
||||||
deviceType={deviceType}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Geo;
|
|
||||||
@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Button, Form, Input, message, Modal, notification } from 'antd';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
class AddGroup extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
addModalVisible: false,
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfirmAdGroup = () => {
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
const groupData = {
|
|
||||||
name: this.state.name,
|
|
||||||
description: this.state.description,
|
|
||||||
};
|
|
||||||
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.post(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/groups',
|
|
||||||
groupData,
|
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 201) {
|
|
||||||
this.props.fetchGroups();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully added the group.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to add group.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
openAddModal = () => {
|
|
||||||
this.setState({
|
|
||||||
addModalVisible: true,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleAddOk = e => {
|
|
||||||
this.props.form.validateFields(err => {
|
|
||||||
if (!err) {
|
|
||||||
this.onConfirmAdGroup();
|
|
||||||
this.setState({
|
|
||||||
addModalVisible: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleAddCancel = e => {
|
|
||||||
this.setState({
|
|
||||||
addModalVisible: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onChangeName = e => {
|
|
||||||
this.setState({
|
|
||||||
name: e.currentTarget.value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onChangeDescription = e => {
|
|
||||||
this.setState({
|
|
||||||
description: e.currentTarget.value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon="plus"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.openAddModal}
|
|
||||||
>
|
|
||||||
Add Group
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="ADD NEW GROUP"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.addModalVisible}
|
|
||||||
onOk={this.handleAddOk}
|
|
||||||
onCancel={this.handleAddCancel}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.handleAddCancel}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.handleAddOk}>
|
|
||||||
Submit
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<div style={{ alignItems: 'center' }}>
|
|
||||||
<p>Create new device group on IoT Server.</p>
|
|
||||||
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
|
||||||
<Form.Item label="Name" style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('name', {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please input group name',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input onChange={this.onChangeName} />)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Description" style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('description', {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please input group description',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input onChange={this.onChangeDescription} />)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create({ name: 'add-group' })(AddGroup));
|
|
||||||
@ -1,395 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Divider,
|
|
||||||
Form,
|
|
||||||
Icon,
|
|
||||||
Input,
|
|
||||||
message,
|
|
||||||
Modal,
|
|
||||||
notification,
|
|
||||||
Popconfirm,
|
|
||||||
Select,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
} from 'antd';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
const { Text } = Typography;
|
|
||||||
|
|
||||||
class GroupActions extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
editModalVisible: false,
|
|
||||||
shareModalVisible: false,
|
|
||||||
name: this.props.data.name,
|
|
||||||
description: this.props.data.description,
|
|
||||||
groupDataObject: {},
|
|
||||||
rolesData: [],
|
|
||||||
shareRolesData: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfirmDeleteGroup = () => {
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.delete(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/groups/id/' +
|
|
||||||
this.props.data.id,
|
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchGroups();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully deleted the group.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to delete group.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmUpdateGroup = data => {
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.put(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/groups/id/' +
|
|
||||||
this.props.data.id,
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchGroups();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully updated the group.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to update group.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchUserRoles = (params = {}) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
const apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/roles';
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
rolesData: res.data.data.roles,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load roles.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmShareGroup = data => {
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.post(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/groups/id/' +
|
|
||||||
this.props.data.id +
|
|
||||||
'/share',
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchGroups();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully shared the group.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to share group.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
openEditModal = () => {
|
|
||||||
this.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,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setState({ groupDataObject });
|
|
||||||
|
|
||||||
this.props.form.validateFields(err => {
|
|
||||||
if (!err) {
|
|
||||||
this.onConfirmUpdateGroup(this.state.groupDataObject);
|
|
||||||
this.setState({
|
|
||||||
editModalVisible: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleEditCancel = e => {
|
|
||||||
this.setState({
|
|
||||||
editModalVisible: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleShareOk = e => {
|
|
||||||
this.setState({
|
|
||||||
shareModalVisible: false,
|
|
||||||
});
|
|
||||||
this.onConfirmShareGroup(this.state.shareRolesData);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleShareCancel = e => {
|
|
||||||
this.setState({
|
|
||||||
shareModalVisible: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onChangeName = e => {
|
|
||||||
this.setState({
|
|
||||||
name: e.currentTarget.value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onChangeDescription = e => {
|
|
||||||
this.setState({
|
|
||||||
description: e.currentTarget.value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleRolesDropdownChange = value => {
|
|
||||||
this.setState({
|
|
||||||
shareRolesData: value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const isAdminGroups = this.props.data.id == 1 || this.props.data.id == 2;
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
let item = this.state.rolesData.map(data => (
|
|
||||||
<Select.Option value={data} key={data}>
|
|
||||||
{data}
|
|
||||||
</Select.Option>
|
|
||||||
));
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div style={{ display: isAdminGroups ? 'none' : 'inline' }}>
|
|
||||||
<Tooltip placement="top" title={'Share Group'}>
|
|
||||||
<a>
|
|
||||||
<Icon type="share-alt" onClick={this.openShareModal} />
|
|
||||||
</a>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="top" title={'Edit Group'}>
|
|
||||||
<a>
|
|
||||||
<Icon type="edit" onClick={this.openEditModal} />
|
|
||||||
</a>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="bottom" title={'Delete Group'}>
|
|
||||||
<Popconfirm
|
|
||||||
placement="top"
|
|
||||||
title={'Are you sure?'}
|
|
||||||
onConfirm={this.onConfirmDeleteGroup}
|
|
||||||
okText="Ok"
|
|
||||||
cancelText="Cancel"
|
|
||||||
>
|
|
||||||
<a>
|
|
||||||
<Text type="danger">
|
|
||||||
<Icon type="delete" />
|
|
||||||
</Text>
|
|
||||||
</a>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="Update Group"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.editModalVisible}
|
|
||||||
onOk={this.handleEditOk}
|
|
||||||
onCancel={this.handleEditCancel}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.handleEditCancel}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.handleEditOk}>
|
|
||||||
Submit
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<div style={{ alignItems: 'center' }}>
|
|
||||||
<p>Enter new name and description for the group</p>
|
|
||||||
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
|
||||||
<Form.Item label="Name" style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('name', {
|
|
||||||
initialValue: this.props.data.name,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please input group name',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input onChange={this.onChangeName} />)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Description" style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('description', {
|
|
||||||
initialValue: this.props.data.description,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please input group description',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input onChange={this.onChangeDescription} />)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="Share Group"
|
|
||||||
width="500px"
|
|
||||||
visible={this.state.shareModalVisible}
|
|
||||||
onOk={this.handleShareOk}
|
|
||||||
onCancel={this.handleShareCancel}
|
|
||||||
footer={[
|
|
||||||
<Button key="new-role" onClick={this.handleShareCancel}>
|
|
||||||
New Role
|
|
||||||
</Button>,
|
|
||||||
<Button key="new-role-selection" onClick={this.handleShareCancel}>
|
|
||||||
New Role from Selection
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.handleShareOk}>
|
|
||||||
Share
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<p>Select user role(s)</p>
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
defaultValue={'admin'}
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
onChange={this.handleRolesDropdownChange}
|
|
||||||
>
|
|
||||||
{item}
|
|
||||||
</Select>
|
|
||||||
,
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(
|
|
||||||
Form.create({ name: 'group-actions' })(GroupActions),
|
|
||||||
);
|
|
||||||
@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { Button, Modal } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import DevicesTable from '../../../../../../components/DevicesTable';
|
|
||||||
|
|
||||||
let apiUrl;
|
|
||||||
|
|
||||||
class GroupDevicesModal extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
visible: false,
|
|
||||||
apiUrl: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
openDrawer = () => {
|
|
||||||
this.setState({ visible: true });
|
|
||||||
const groupData = {
|
|
||||||
groupId: this.props.groupData.id,
|
|
||||||
groupName: this.props.groupData.name,
|
|
||||||
};
|
|
||||||
this.fetchGroupDevices(groupData);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleModalCancel = () => {
|
|
||||||
this.setState({
|
|
||||||
visible: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
fetchGroupDevices = (params = {}, filters = {}) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
|
|
||||||
// get current page
|
|
||||||
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
|
||||||
|
|
||||||
const extraParams = {
|
|
||||||
offset: 10 * (currentPage - 1), // calculate the offset
|
|
||||||
limit: 10,
|
|
||||||
...params,
|
|
||||||
};
|
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
|
||||||
.map(key => key + '=' + extraParams[key])
|
|
||||||
.join('&');
|
|
||||||
|
|
||||||
apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/devices?' +
|
|
||||||
encodedExtraParams;
|
|
||||||
|
|
||||||
this.setState({ apiUrl: apiUrl });
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = { ...this.state.pagination };
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetchGroupDevices({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { apiUrl, visible } = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size={'small'}
|
|
||||||
icon="desktop"
|
|
||||||
onClick={this.openDrawer}
|
|
||||||
>
|
|
||||||
Devices
|
|
||||||
</Button>
|
|
||||||
<Modal
|
|
||||||
title="DEVICES"
|
|
||||||
width="80%"
|
|
||||||
visible={visible}
|
|
||||||
onCancel={this.handleModalCancel}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.handleModalCancel}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="ok" type="primary" onClick={this.handleModalCancel}>
|
|
||||||
OK
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<div style={{ alignItems: 'center' }}>
|
|
||||||
<DevicesTable apiUrl={apiUrl} />
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(GroupDevicesModal);
|
|
||||||
@ -1,219 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { message, notification, Table } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import GroupActions from './components/GroupActions';
|
|
||||||
import AddGroup from './components/AddGroup';
|
|
||||||
import Filter from '../../../../components/Filter';
|
|
||||||
import GroupDevicesModal from './components/GroupDevicesModal';
|
|
||||||
|
|
||||||
const searchFields = [
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
placeholder: 'Name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'owner',
|
|
||||||
placeholder: 'Owner',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
let apiUrl;
|
|
||||||
|
|
||||||
class GroupsTable extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
columns = [
|
|
||||||
{
|
|
||||||
title: 'Group Name',
|
|
||||||
dataIndex: 'name',
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Owner',
|
|
||||||
dataIndex: 'owner',
|
|
||||||
key: 'owner',
|
|
||||||
// render: enrolmentInfo => enrolmentInfo.owner
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Description',
|
|
||||||
dataIndex: 'description',
|
|
||||||
key: 'description',
|
|
||||||
// render: enrolmentInfo => enrolmentInfo.ownership
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Action',
|
|
||||||
dataIndex: 'id',
|
|
||||||
key: 'action',
|
|
||||||
render: (id, row) => (
|
|
||||||
<span>
|
|
||||||
<GroupActions data={row} fetchGroups={this.fetchGroups} />
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Devices',
|
|
||||||
dataIndex: 'id',
|
|
||||||
key: 'details',
|
|
||||||
render: (id, row) => <GroupDevicesModal groupData={row} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Devices',
|
|
||||||
dataIndex: 'id',
|
|
||||||
key: 'details',
|
|
||||||
render: (id, row) => <GroupDevicesModal groupData={row} />,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
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,
|
|
||||||
data: res.data.data,
|
|
||||||
pagination,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load device groups.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
const pager = { ...this.state.pagination };
|
|
||||||
pager.current = pagination.current;
|
|
||||||
this.setState({
|
|
||||||
pagination: pager,
|
|
||||||
});
|
|
||||||
this.fetchGroups({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { data, pagination, loading } = 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);
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import GroupsTable from './components/GroupsTable';
|
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
|
||||||
|
|
||||||
class Groups extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Groups</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Groups</h3>
|
|
||||||
<Paragraph>All device groups.</Paragraph>
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
|
||||||
<GroupsTable />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Groups;
|
|
||||||
@ -1,197 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Icon, Table } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import { handleApiError } from '../../../../../../services/utils/errorHandler';
|
|
||||||
|
|
||||||
let config = null;
|
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
title: 'Device',
|
|
||||||
dataIndex: 'deviceName',
|
|
||||||
width: 100,
|
|
||||||
sorter: (a, b) => a.deviceName.localeCompare(b.deviceName),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Type',
|
|
||||||
dataIndex: 'deviceType',
|
|
||||||
key: 'type',
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
render: type => {
|
|
||||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
|
||||||
let icon = defaultPlatformIcons.default.icon;
|
|
||||||
let color = defaultPlatformIcons.default.color;
|
|
||||||
let theme = defaultPlatformIcons.default.theme;
|
|
||||||
|
|
||||||
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
|
||||||
icon = defaultPlatformIcons[type].icon;
|
|
||||||
color = defaultPlatformIcons[type].color;
|
|
||||||
theme = defaultPlatformIcons[type].theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
|
|
||||||
<Icon type={icon} theme={theme} />
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Description',
|
|
||||||
dataIndex: 'description',
|
|
||||||
key: 'description',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
class NotificationsTable extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
config = this.props.context;
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
paramsObj: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
rowSelection = {
|
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
|
||||||
this.setState({
|
|
||||||
selectedRows: selectedRows,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetchData();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rerender component when parameters change
|
|
||||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
|
||||||
if (prevProps.notificationType !== this.props.notificationType) {
|
|
||||||
this.fetchData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
fetchData = (params = {}) => {
|
|
||||||
// const policyReportData = this.props;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
// get current page
|
|
||||||
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
|
||||||
|
|
||||||
let extraParams;
|
|
||||||
|
|
||||||
extraParams = {
|
|
||||||
offset: 10 * (currentPage - 1), // calculate the offset
|
|
||||||
limit: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
|
||||||
.map(key => key + '=' + extraParams[key])
|
|
||||||
.join('&');
|
|
||||||
|
|
||||||
let apiUrl;
|
|
||||||
|
|
||||||
if (this.props.notificationType === 'unread') {
|
|
||||||
apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/notifications?status=NEW&' +
|
|
||||||
encodedExtraParams;
|
|
||||||
} else {
|
|
||||||
apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/notifications?' +
|
|
||||||
encodedExtraParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
const pagination = { ...this.state.pagination };
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
data: res.data.data,
|
|
||||||
pagination,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
handleApiError(error, '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.fetchData({
|
|
||||||
results: pagination.pageSize,
|
|
||||||
page: pagination.current,
|
|
||||||
sortField: sorter.field,
|
|
||||||
sortOrder: sorter.order,
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let { data, pagination, loading } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
columns={columns}
|
|
||||||
rowKey={record => record.id}
|
|
||||||
dataSource={data.notifications}
|
|
||||||
pagination={{
|
|
||||||
...pagination,
|
|
||||||
size: 'small',
|
|
||||||
// position: "top",
|
|
||||||
total: data.count,
|
|
||||||
showTotal: (total, range) =>
|
|
||||||
`showing ${range[0]}-${range[1]} of ${total} notifications`,
|
|
||||||
}}
|
|
||||||
loading={loading}
|
|
||||||
onChange={this.handleTableChange}
|
|
||||||
rowSelection={this.rowSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(NotificationsTable);
|
|
||||||
@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
message,
|
|
||||||
notification,
|
|
||||||
Button,
|
|
||||||
PageHeader,
|
|
||||||
Breadcrumb,
|
|
||||||
Icon,
|
|
||||||
Radio,
|
|
||||||
} from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../components/ConfigContext';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
|
||||||
import NotificationsTable from './Components/NotificationsTable';
|
|
||||||
|
|
||||||
class Notifications extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
visible: false,
|
|
||||||
data: [],
|
|
||||||
notificationType: 'all',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleModeChange = e => {
|
|
||||||
const notificationType = e.target.value;
|
|
||||||
this.setState({ notificationType });
|
|
||||||
};
|
|
||||||
|
|
||||||
clearNotifications = () => {
|
|
||||||
const config = this.props.context;
|
|
||||||
axios
|
|
||||||
.put(
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/notifications/clear-all',
|
|
||||||
{ 'Content-Type': 'application/json; charset=utf-8' },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 0,
|
|
||||||
description: 'All notifications are cleared.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 clear notifications.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { notificationType } = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Notifications</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
|
||||||
<h3>DEVICE NOTIFICATIONS</h3>
|
|
||||||
<Radio.Group
|
|
||||||
onChange={this.handleModeChange}
|
|
||||||
defaultValue={'all'}
|
|
||||||
value={notificationType}
|
|
||||||
style={{ marginBottom: 8, marginRight: 5 }}
|
|
||||||
>
|
|
||||||
<Radio.Button value={'all'}>All Notifications</Radio.Button>
|
|
||||||
<Radio.Button value={'unread'}>Unread Notifications</Radio.Button>
|
|
||||||
</Radio.Group>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
style={{
|
|
||||||
marginRight: 10,
|
|
||||||
marginBottom: 8,
|
|
||||||
display: notificationType === 'unread' ? 'inline' : 'none',
|
|
||||||
}}
|
|
||||||
onClick={this.clearNotifications}
|
|
||||||
>
|
|
||||||
Clear All Notifications
|
|
||||||
</Button>
|
|
||||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
|
||||||
<NotificationsTable notificationType={notificationType} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Notifications);
|
|
||||||
@ -1,260 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
import React from 'react';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import { Button, Col, Form, message, notification, Radio, Select } from 'antd';
|
|
||||||
import axios from 'axios';
|
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
class AssignGroups extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.userSelector = React.createRef();
|
|
||||||
this.roleSelector = React.createRef();
|
|
||||||
this.state = {
|
|
||||||
roles: [],
|
|
||||||
users: [],
|
|
||||||
groups: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
componentDidMount() {
|
|
||||||
this.getRolesList();
|
|
||||||
this.getGroupsList();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSetUserRoleFormItem = event => {
|
|
||||||
if (event.target.value === 'roleSelector') {
|
|
||||||
this.roleSelector.current.style.cssText = 'display: block;';
|
|
||||||
this.userSelector.current.style.cssText = 'display: none;';
|
|
||||||
} else {
|
|
||||||
this.roleSelector.current.style.cssText = 'display: none;';
|
|
||||||
this.userSelector.current.style.cssText = 'display: block;';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate payload by adding Assign Groups
|
|
||||||
onHandleContinue = (e, formName) => {
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
if (typeof values.roles === 'string') {
|
|
||||||
values.roles = [values.roles];
|
|
||||||
}
|
|
||||||
if (!values.users) {
|
|
||||||
delete values.users;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values.deviceGroups === 'NONE') {
|
|
||||||
delete values.deviceGroups;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.getPolicyPayloadData(formName, values);
|
|
||||||
this.props.getNextStep();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getRolesList = () => {
|
|
||||||
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) {
|
|
||||||
this.setState({
|
|
||||||
roles: 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.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getUsersList = 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 users = JSON.parse(res.data.data);
|
|
||||||
this.setState({
|
|
||||||
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.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
getGroupsList = () => {
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/admin/groups';
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
groups: 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 trying to load device groups.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Radio.Group
|
|
||||||
defaultValue={'roleSelector'}
|
|
||||||
onChange={this.handleSetUserRoleFormItem}
|
|
||||||
>
|
|
||||||
<Radio value="roleSelector">Set User role(s)</Radio>
|
|
||||||
<Radio value="userSelector">Set User(s)</Radio>
|
|
||||||
</Radio.Group>
|
|
||||||
<div
|
|
||||||
id={'roleSelector'}
|
|
||||||
ref={this.roleSelector}
|
|
||||||
style={{ display: 'block' }}
|
|
||||||
>
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator('roles', {
|
|
||||||
initialValue: 'ANY',
|
|
||||||
})(
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
defaultActiveFirstOption={true}
|
|
||||||
>
|
|
||||||
<Option value={'ANY'}>Any</Option>
|
|
||||||
{this.state.roles.map(role => (
|
|
||||||
<Option key={role} value={role}>
|
|
||||||
{role}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id={'userSelector'}
|
|
||||||
ref={this.userSelector}
|
|
||||||
style={{ display: 'none' }}
|
|
||||||
>
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator('users', {})(
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
onSearch={this.getUsersList}
|
|
||||||
>
|
|
||||||
{this.state.users.map(user => (
|
|
||||||
<Option key={user.username} value={user.username}>
|
|
||||||
{user.username}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Form.Item label={'Select Groups'} style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('deviceGroups', {
|
|
||||||
initialValue: 'NONE',
|
|
||||||
})(
|
|
||||||
<Select mode="multiple" style={{ width: '100%' }}>
|
|
||||||
<Option value={'NONE'}>NONE</Option>
|
|
||||||
{this.state.groups.map(group => (
|
|
||||||
<Option key={group.name} value={group.name}>
|
|
||||||
{group.name}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Col span={16} offset={20}>
|
|
||||||
<div style={{ marginTop: 24 }}>
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={this.props.getPrevStep}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={e => this.onHandleContinue(e, 'groupData')}
|
|
||||||
>
|
|
||||||
Continue
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(AssignGroups));
|
|
||||||
@ -1,971 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Tabs,
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
Switch,
|
|
||||||
Input,
|
|
||||||
Typography,
|
|
||||||
Form,
|
|
||||||
Collapse,
|
|
||||||
Checkbox,
|
|
||||||
Select,
|
|
||||||
Tooltip,
|
|
||||||
Icon,
|
|
||||||
Table,
|
|
||||||
Alert,
|
|
||||||
Upload,
|
|
||||||
Popconfirm,
|
|
||||||
Button,
|
|
||||||
Radio,
|
|
||||||
} from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import '../../../../styles.css';
|
|
||||||
import moment from 'moment';
|
|
||||||
const { Text, Title, Paragraph } = Typography;
|
|
||||||
const { TabPane } = Tabs;
|
|
||||||
const { Option } = Select;
|
|
||||||
const { TextArea } = Input;
|
|
||||||
|
|
||||||
const subPanelpayloadAttributesforCheckboxes = {};
|
|
||||||
const subPanelpayloadAttributesforSelect = {};
|
|
||||||
let formContainers = {};
|
|
||||||
|
|
||||||
class ConfigureProfile extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
loading: false,
|
|
||||||
isDisplayMain: 'none',
|
|
||||||
activePanelKeys: [],
|
|
||||||
activeSubPanelKeys: [],
|
|
||||||
subFormList: [],
|
|
||||||
subPanelpayloadAttributes: {},
|
|
||||||
count: 0,
|
|
||||||
dataArray: [],
|
|
||||||
customInputDataArray: [],
|
|
||||||
inputTableDataSources: {},
|
|
||||||
addPolicyForms: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert time from 24h format to 12h format
|
|
||||||
timeConverter = time => {
|
|
||||||
time = time
|
|
||||||
.toString()
|
|
||||||
.match(/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/) || [time];
|
|
||||||
if (time.length > 1) {
|
|
||||||
time = time.slice(1);
|
|
||||||
time[5] = +time[0] < 12 ? ' AM' : ' PM';
|
|
||||||
time[0] = +time[0] % 12 || 12;
|
|
||||||
}
|
|
||||||
return time.join('');
|
|
||||||
};
|
|
||||||
|
|
||||||
// get Option value from start Time, end Time and time difference between 2 values
|
|
||||||
getOptionForTimeSelectors = (startTimeValue, endTimeValue, timeIncrement) => {
|
|
||||||
let timeOptions = [];
|
|
||||||
let time = new Date(
|
|
||||||
moment()
|
|
||||||
.startOf('day')
|
|
||||||
.format('YYYY/MM/DD'),
|
|
||||||
);
|
|
||||||
let tempValue = startTimeValue;
|
|
||||||
time.setMinutes(time.getMinutes() + tempValue);
|
|
||||||
let startOption = (
|
|
||||||
<Option value={String(tempValue)}>
|
|
||||||
{this.timeConverter(
|
|
||||||
`${String(time)
|
|
||||||
.split(' ')[4]
|
|
||||||
.substring(0, 5)}`,
|
|
||||||
)}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
timeOptions.push(startOption);
|
|
||||||
|
|
||||||
while (tempValue !== endTimeValue) {
|
|
||||||
time = new Date(
|
|
||||||
moment()
|
|
||||||
.startOf('day')
|
|
||||||
.format('YYYY/MM/DD'),
|
|
||||||
);
|
|
||||||
tempValue += timeIncrement;
|
|
||||||
if (tempValue > 1440) {
|
|
||||||
tempValue = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
time.setMinutes(time.getMinutes() + tempValue);
|
|
||||||
let option = (
|
|
||||||
<Option value={String(tempValue)}>
|
|
||||||
{this.timeConverter(
|
|
||||||
`${String(time)
|
|
||||||
.split(' ')[4]
|
|
||||||
.substring(0, 5)}`,
|
|
||||||
)}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
timeOptions.push(option);
|
|
||||||
}
|
|
||||||
return timeOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle items which handle from radio buttons
|
|
||||||
handleRadioPanel = (e, subPanel) => {
|
|
||||||
{
|
|
||||||
subPanel.map((panel, i) => {
|
|
||||||
if (panel.value === e.target.value) {
|
|
||||||
document.getElementById(panel.value).style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById(panel.value).style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle items which handle from select options
|
|
||||||
handleSelectedPanel = (e, subPanel) => {
|
|
||||||
{
|
|
||||||
subPanel.map((panel, i) => {
|
|
||||||
if (panel.id === e) {
|
|
||||||
document.getElementById(panel.id).style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById(panel.id).style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle items which handle from checkbox
|
|
||||||
handleSubPanel = e => {
|
|
||||||
if (e.target.checked) {
|
|
||||||
let joined = this.state.activeSubPanelKeys.concat(e.target.id);
|
|
||||||
this.setState({ activeSubPanelKeys: joined });
|
|
||||||
} else {
|
|
||||||
let index = this.state.activeSubPanelKeys.indexOf(e.target.id);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.state.activeSubPanelKeys.splice(index, 1);
|
|
||||||
let removed = this.state.activeSubPanelKeys;
|
|
||||||
this.setState({ activeSubPanelKeys: removed });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle Switch on off button
|
|
||||||
handleMainPanel = (e, ref) => {
|
|
||||||
if (e) {
|
|
||||||
let joined = this.state.activePanelKeys.concat(ref);
|
|
||||||
this.setState({ activePanelKeys: joined });
|
|
||||||
} else {
|
|
||||||
let index = this.state.activePanelKeys.indexOf(ref);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.state.activePanelKeys.splice(index, 1);
|
|
||||||
let removed = this.state.activePanelKeys;
|
|
||||||
this.setState({ activePanelKeys: removed });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleCustomInputTable = event => {
|
|
||||||
const { count, customInputDataArray } = this.state;
|
|
||||||
|
|
||||||
const newData = [
|
|
||||||
{
|
|
||||||
key: count,
|
|
||||||
CERT_NAME: `${event.file.name}`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
this.setState({
|
|
||||||
customInputDataArray: [...customInputDataArray, newData],
|
|
||||||
count: count + 1,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleAdd = array => {
|
|
||||||
const { count, inputTableDataSources } = this.state;
|
|
||||||
const newData = [
|
|
||||||
{
|
|
||||||
key: count,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
inputTableDataSources[array].push(newData);
|
|
||||||
Object.defineProperty(inputTableDataSources, array, {
|
|
||||||
value: inputTableDataSources[array],
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
inputTableDataSources,
|
|
||||||
count: count + 1,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getColumns = ({ getFieldDecorator }, arr) => {
|
|
||||||
const columnArray = [];
|
|
||||||
const actionColumn = [
|
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
dataIndex: 'operation',
|
|
||||||
render: (name, row) => (
|
|
||||||
<Form.Item>
|
|
||||||
<Popconfirm title="Sure to delete?">
|
|
||||||
<a>
|
|
||||||
<Text type="danger">
|
|
||||||
<Icon type="delete" />
|
|
||||||
</Text>
|
|
||||||
</a>
|
|
||||||
</Popconfirm>
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
Object.values(arr).map((columnData, c) => {
|
|
||||||
if (columnData.type === 'input') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {})(
|
|
||||||
<Input
|
|
||||||
type={columnData.others.inputType}
|
|
||||||
placeholder={columnData.others.placeholder}
|
|
||||||
/>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
} else if (columnData.type === 'upload') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {})(
|
|
||||||
<Upload>
|
|
||||||
<Button>
|
|
||||||
<Icon type="upload" /> Choose file
|
|
||||||
</Button>
|
|
||||||
</Upload>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
} else if (columnData.type === 'select') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {
|
|
||||||
initialValue: columnData.others.initialDataIndex,
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
{columnData.others.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.key}>
|
|
||||||
{option.value}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const columns = columnArray.concat(actionColumn);
|
|
||||||
return columns;
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate payload by adding policy configurations
|
|
||||||
onHandleContinue = (e, formname) => {
|
|
||||||
const allFields = this.props.form.getFieldsValue();
|
|
||||||
let activeFields = [];
|
|
||||||
let subContentsList = {};
|
|
||||||
for (let i = 0; i < this.state.activePanelKeys.length; i++) {
|
|
||||||
Object.keys(allFields).map(key => {
|
|
||||||
if (key.includes(`${this.state.activePanelKeys[i]}-`)) {
|
|
||||||
if (
|
|
||||||
subPanelpayloadAttributesforCheckboxes.hasOwnProperty(
|
|
||||||
`${this.state.activePanelKeys[i]}`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Object.entries(
|
|
||||||
subPanelpayloadAttributesforCheckboxes[
|
|
||||||
this.state.activePanelKeys[i]
|
|
||||||
],
|
|
||||||
).map(([subPanel, subContent]) => {
|
|
||||||
subContentsList[subContent] = {};
|
|
||||||
if (
|
|
||||||
allFields[`${this.state.activePanelKeys[i]}-${subPanel}`] ===
|
|
||||||
true
|
|
||||||
) {
|
|
||||||
activeFields.push(key);
|
|
||||||
} else if (!key.includes(`-${subPanel}`)) {
|
|
||||||
activeFields.push(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (
|
|
||||||
subPanelpayloadAttributesforSelect.hasOwnProperty(
|
|
||||||
`${this.state.activePanelKeys[i]}`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Object.entries(
|
|
||||||
subPanelpayloadAttributesforSelect[this.state.activePanelKeys[i]],
|
|
||||||
).map(([subPanelSwitch, subPanels]) => {
|
|
||||||
if (
|
|
||||||
subPanels.includes(allFields[subPanelSwitch]) &&
|
|
||||||
key.includes(`${subPanelSwitch}-${allFields[subPanelSwitch]}-`)
|
|
||||||
) {
|
|
||||||
activeFields.push(key);
|
|
||||||
} else {
|
|
||||||
for (let panel of subPanels) {
|
|
||||||
if (!key.includes(`${subPanelSwitch}-${panel}-`)) {
|
|
||||||
activeFields.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
activeFields.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// validate fields and get profile features list
|
|
||||||
this.props.form.validateFields(activeFields, (err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
let profileFeaturesList = [];
|
|
||||||
for (let i = 0; i < this.state.activePanelKeys.length; i++) {
|
|
||||||
let content = {};
|
|
||||||
Object.entries(values).map(([key, value]) => {
|
|
||||||
if (key.includes(`${this.state.activePanelKeys[i]}-`)) {
|
|
||||||
if (
|
|
||||||
subPanelpayloadAttributesforCheckboxes.hasOwnProperty(
|
|
||||||
`${this.state.activePanelKeys[i]}`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Object.entries(
|
|
||||||
subPanelpayloadAttributesforCheckboxes[
|
|
||||||
this.state.activePanelKeys[i]
|
|
||||||
],
|
|
||||||
).map(([subPanel, contentKey]) => {
|
|
||||||
if (key.includes(`-${subPanel}-`)) {
|
|
||||||
subContentsList[contentKey][
|
|
||||||
key.replace(
|
|
||||||
`${this.state.activePanelKeys[i]}-${subPanel}-`,
|
|
||||||
'',
|
|
||||||
)
|
|
||||||
] = value;
|
|
||||||
content = { ...content, ...subContentsList };
|
|
||||||
} else {
|
|
||||||
content[
|
|
||||||
key.replace(`${this.state.activePanelKeys[i]}-`, '')
|
|
||||||
] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (this.state.activePanelKeys[i] in formContainers) {
|
|
||||||
formContainers[this.state.activePanelKeys[i]].forEach(
|
|
||||||
subFeature => {
|
|
||||||
if (
|
|
||||||
key.includes(
|
|
||||||
`${this.state.activePanelKeys[i]}-${subFeature}-`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
let subFormContent = {};
|
|
||||||
subFormContent[
|
|
||||||
key.replace(
|
|
||||||
`${this.state.activePanelKeys[i]}-${subFeature}-`,
|
|
||||||
'',
|
|
||||||
)
|
|
||||||
] = value;
|
|
||||||
let feature = {
|
|
||||||
featureCode: subFeature,
|
|
||||||
deviceType: 'android',
|
|
||||||
content: subFormContent,
|
|
||||||
};
|
|
||||||
profileFeaturesList.push(feature);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
subPanelpayloadAttributesforSelect.hasOwnProperty(
|
|
||||||
`${this.state.activePanelKeys[i]}`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Object.keys(
|
|
||||||
subPanelpayloadAttributesforSelect[
|
|
||||||
this.state.activePanelKeys[i]
|
|
||||||
],
|
|
||||||
).map(subPanelSwitch => {
|
|
||||||
if (
|
|
||||||
key.includes(`${subPanelSwitch}-${values[subPanelSwitch]}-`)
|
|
||||||
) {
|
|
||||||
content[
|
|
||||||
key.replace(
|
|
||||||
`${subPanelSwitch}-${values[subPanelSwitch]}-`,
|
|
||||||
'',
|
|
||||||
)
|
|
||||||
] = value;
|
|
||||||
} else {
|
|
||||||
content[
|
|
||||||
key.replace(`${this.state.activePanelKeys[i]}-`, '')
|
|
||||||
] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
content[
|
|
||||||
key.replace(`${this.state.activePanelKeys[i]}-`, '')
|
|
||||||
] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!(this.state.activePanelKeys[i] in formContainers)) {
|
|
||||||
let feature = {
|
|
||||||
featureCode: this.state.activePanelKeys[i],
|
|
||||||
deviceType: 'android',
|
|
||||||
content: content,
|
|
||||||
};
|
|
||||||
profileFeaturesList.push(feature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.props.getPolicyPayloadData(formname, profileFeaturesList);
|
|
||||||
this.props.getNextStep();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate form items
|
|
||||||
getPanelItems = (panel, panelId) => {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
const subPanelListforCheckbox = {};
|
|
||||||
const subPanelListforSelect = {};
|
|
||||||
return panel.map((item, k) => {
|
|
||||||
switch (item.type) {
|
|
||||||
case 'select':
|
|
||||||
if (item.optional.hasOwnProperty('subPanel')) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: `${item.optional.option[0].name}`,
|
|
||||||
})(
|
|
||||||
<Select
|
|
||||||
onChange={e =>
|
|
||||||
this.handleSelectedPanel(e, item.optional.subPanel)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{item.optional.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<div className={'sub-panel-container'}>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
id={panel.id}
|
|
||||||
key={i}
|
|
||||||
style={
|
|
||||||
panel.id === item.optional.initialDataIndex
|
|
||||||
? { display: 'block' }
|
|
||||||
: { display: 'none' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{this.getPanelItems(panel.panelItem)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
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}`, {
|
|
||||||
initialValue: `${item.optional.option[0].name}`,
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
{item.optional.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case 'timeSelector':
|
|
||||||
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}`, {
|
|
||||||
initialValue: item.optional.initialDataIndex,
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
{this.getOptionForTimeSelectors(
|
|
||||||
item.optional.firstOptionValue,
|
|
||||||
item.optional.lastOptionValue,
|
|
||||||
item.optional.valueDifference,
|
|
||||||
)}
|
|
||||||
</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}`, {
|
|
||||||
initialValue: null,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
pattern: new RegExp(`${item.optional.rules.regex}`),
|
|
||||||
message: `${item.optional.rules.validationMsg}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input placeholder={item.optional.placeholder} />)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case 'checkbox':
|
|
||||||
if (item.optional.hasOwnProperty('subPanel')) {
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Collapse
|
|
||||||
bordered={false}
|
|
||||||
activeKey={this.state.activeSubPanelKeys}
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
key={item.id}
|
|
||||||
showArrow={false}
|
|
||||||
style={{ border: 0 }}
|
|
||||||
header={
|
|
||||||
<Form.Item key={k}>
|
|
||||||
{getFieldDecorator(`${item.id}`, {
|
|
||||||
valuePropName: 'checked',
|
|
||||||
initialValue: item.optional.ischecked,
|
|
||||||
})(
|
|
||||||
<Checkbox onChange={this.handleSubPanel}>
|
|
||||||
<span>
|
|
||||||
{item.label}
|
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
</Checkbox>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
subPanelListforCheckbox[panel.others.itemSwitch] =
|
|
||||||
panel.others.itemPayload;
|
|
||||||
if (
|
|
||||||
subPanelpayloadAttributesforCheckboxes.hasOwnProperty(
|
|
||||||
panelId,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Object.assign(
|
|
||||||
subPanelpayloadAttributesforCheckboxes[panelId],
|
|
||||||
subPanelListforCheckbox,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
subPanelpayloadAttributesforCheckboxes[
|
|
||||||
panelId
|
|
||||||
] = subPanelListforCheckbox;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div key={i}>
|
|
||||||
{this.getPanelItems(panel.panelItem, panelId)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Form.Item key={k}>
|
|
||||||
{getFieldDecorator(`${item.id}`, {
|
|
||||||
valuePropName: 'checked',
|
|
||||||
initialValue: item.optional.ischecked,
|
|
||||||
})(
|
|
||||||
<Checkbox>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: null,
|
|
||||||
})(
|
|
||||||
<TextArea
|
|
||||||
placeholder={item.optional.placeholder}
|
|
||||||
rows={item.optional.row}
|
|
||||||
/>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case 'radioGroup':
|
|
||||||
// eslint-disable-next-line no-case-declarations
|
|
||||||
let subPanelkeys = [];
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: `${item.optional.initialValue}`,
|
|
||||||
})(
|
|
||||||
<Radio.Group
|
|
||||||
onChange={e =>
|
|
||||||
this.handleRadioPanel(e, item.optional.radio)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{item.optional.radio.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Radio key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Radio>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Radio.Group>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<div className={'sub-panel-container'}>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
if (panel.hasOwnProperty('others')) {
|
|
||||||
subPanelkeys.push(panel.id);
|
|
||||||
subPanelListforSelect[`${item.id}`] = subPanelkeys;
|
|
||||||
subPanelpayloadAttributesforSelect[
|
|
||||||
panelId
|
|
||||||
] = subPanelListforSelect;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
id={panel.id}
|
|
||||||
style={
|
|
||||||
panel.id === item.optional.initialValue
|
|
||||||
? { display: 'block' }
|
|
||||||
: { display: 'none' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{this.getPanelItems(panel.panelItem)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
case 'inputTable':
|
|
||||||
if (
|
|
||||||
!(`${item.optional.dataSource}` in this.state.inputTableDataSources)
|
|
||||||
) {
|
|
||||||
Object.defineProperty(
|
|
||||||
this.state.inputTableDataSources,
|
|
||||||
`${item.optional.dataSource}`,
|
|
||||||
{ value: [], writable: true },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Button
|
|
||||||
onClick={() => this.handleAdd(item.optional.dataSource)}
|
|
||||||
type="primary"
|
|
||||||
style={{ marginBottom: 16 }}
|
|
||||||
>
|
|
||||||
<Icon type="plus-circle" />
|
|
||||||
{item.optional.button.name}
|
|
||||||
</Button>
|
|
||||||
<Table
|
|
||||||
id={item.id}
|
|
||||||
dataSource={
|
|
||||||
this.state.inputTableDataSources[item.optional.dataSource]
|
|
||||||
}
|
|
||||||
columns={this.getColumns(
|
|
||||||
{ getFieldDecorator },
|
|
||||||
item.optional.columns,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case 'customInputTable':
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Upload onChange={this.handleCustomInputTable}>
|
|
||||||
<Button type="primary" style={{ marginBottom: 16 }}>
|
|
||||||
<Icon type="plus-circle" />
|
|
||||||
{item.optional.button.name}
|
|
||||||
</Button>
|
|
||||||
</Upload>
|
|
||||||
<Table
|
|
||||||
id={item.id}
|
|
||||||
dataSource={this.state.customInputDataArray}
|
|
||||||
columns={this.getColumns(
|
|
||||||
{ getFieldDecorator },
|
|
||||||
item.optional.columns,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { policyUIConfigurationsList } = this.props;
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div className="tab-container">
|
|
||||||
<Tabs tabPosition={'left'} size={'large'}>
|
|
||||||
{policyUIConfigurationsList.map((element, i) => {
|
|
||||||
return (
|
|
||||||
<TabPane tab={<span>{element.name}</span>} key={i}>
|
|
||||||
{Object.values(element.panels).map((panel, j) => {
|
|
||||||
panel = panel.panel;
|
|
||||||
let subForms = [];
|
|
||||||
return (
|
|
||||||
<div key={j}>
|
|
||||||
<Collapse
|
|
||||||
bordered={false}
|
|
||||||
activeKey={this.state.activePanelKeys}
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
key={panel.panelId}
|
|
||||||
showArrow={false}
|
|
||||||
style={{ border: 0 }}
|
|
||||||
header={
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col offset={0} span={14}>
|
|
||||||
<Title level={4}> {panel.title} </Title>
|
|
||||||
</Col>
|
|
||||||
<Col offset={8} span={1}>
|
|
||||||
<Switch
|
|
||||||
checkedChildren="ON"
|
|
||||||
unCheckedChildren="OFF"
|
|
||||||
onChange={e =>
|
|
||||||
this.handleMainPanel(
|
|
||||||
e,
|
|
||||||
`${panel.panelId}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>{panel.description}</Row>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{panel.hasOwnProperty('panelItem') && (
|
|
||||||
<div>
|
|
||||||
<Form name={panel.panelId}>
|
|
||||||
<Form.Item style={{ display: 'none' }}>
|
|
||||||
{getFieldDecorator(`${panel.panelId}`, {
|
|
||||||
initialValue: ' ',
|
|
||||||
})(<Input />)}
|
|
||||||
</Form.Item>
|
|
||||||
{this.getPanelItems(
|
|
||||||
panel.panelItem,
|
|
||||||
panel.panelId,
|
|
||||||
)}
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{panel.hasOwnProperty('subFormLists') && (
|
|
||||||
<div>
|
|
||||||
{Object.values(panel.subFormLists).map(
|
|
||||||
(form, i) => {
|
|
||||||
subForms.push(form.id);
|
|
||||||
formContainers[`${panel.panelId}`] = subForms;
|
|
||||||
return (
|
|
||||||
<Form name={form.id} key={i}>
|
|
||||||
<Form.Item style={{ display: 'none' }}>
|
|
||||||
{getFieldDecorator(`${form.id}`, {
|
|
||||||
initialValue: ' ',
|
|
||||||
})(<Input />)}
|
|
||||||
</Form.Item>
|
|
||||||
{this.getPanelItems(form.panelItem)}
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TabPane>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Tabs>
|
|
||||||
<Col span={16} offset={20}>
|
|
||||||
<div style={{ marginTop: 24 }}>
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={this.props.getPrevStep}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={e => this.onHandleContinue(e, 'configureProfileData')}
|
|
||||||
>
|
|
||||||
Continue
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(ConfigureProfile));
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
import React from 'react';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import { Button, Col, Form, Input } from 'antd';
|
|
||||||
const { TextArea } = Input;
|
|
||||||
|
|
||||||
class PublishDevices extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickSavePolicy = (event, isPublish, formName) => {
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
values.active = isPublish;
|
|
||||||
this.props.getPolicyPayloadData(formName, values);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Form.Item
|
|
||||||
label={'Set a name to your policy *'}
|
|
||||||
style={{ display: 'block' }}
|
|
||||||
>
|
|
||||||
{getFieldDecorator('policyName', {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
pattern: new RegExp('^.{1,30}$'),
|
|
||||||
message: 'Should be 1-to-30 characters long',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input placeholder={'Should be 1 to 30 characters long'} />)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label={'Add a Description'} style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('description', {})(<TextArea rows={8} />)}
|
|
||||||
</Form.Item>
|
|
||||||
<Col span={16} offset={18}>
|
|
||||||
<div style={{ marginTop: 24 }}>
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={this.props.getPrevStep}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
style={{ marginRight: 8 }}
|
|
||||||
onClick={e =>
|
|
||||||
this.onClickSavePolicy(e, true, 'publishDevicesData')
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Save & Publish
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={e =>
|
|
||||||
this.onClickSavePolicy(e, false, 'publishDevicesData')
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(PublishDevices));
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Card, Col, Icon, message, notification, Row } from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
|
|
||||||
class SelectPlatform extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
loading: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.getDeviceTypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickCard = (e, type, formname) => {
|
|
||||||
this.props.getPolicyConfigJson(type);
|
|
||||||
let deviceType = {
|
|
||||||
deviceType: type,
|
|
||||||
};
|
|
||||||
this.props.getPolicyPayloadData(formname, deviceType);
|
|
||||||
};
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
getDeviceTypes() {
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/device-types';
|
|
||||||
|
|
||||||
// send request to the invokers
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
data: JSON.parse(res.data.data),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load device types.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ loading: false });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { data } = this.state;
|
|
||||||
const { Meta } = Card;
|
|
||||||
const itemCard = data.map(data => (
|
|
||||||
<Col span={5} key={data.id}>
|
|
||||||
<a>
|
|
||||||
<Card
|
|
||||||
size="default"
|
|
||||||
style={{ width: 150 }}
|
|
||||||
bordered={true}
|
|
||||||
onClick={e =>
|
|
||||||
this.onClickCard(e, data.name, 'selectedPlatformData')
|
|
||||||
}
|
|
||||||
cover={
|
|
||||||
<Icon
|
|
||||||
type={data.name === 'ios' ? 'apple' : data.name}
|
|
||||||
key="device-types"
|
|
||||||
style={{
|
|
||||||
color: '#ffffff',
|
|
||||||
backgroundColor: '#4b92db',
|
|
||||||
fontSize: '100px',
|
|
||||||
padding: '20px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Meta title={data.name} />
|
|
||||||
</Card>
|
|
||||||
</a>
|
|
||||||
</Col>
|
|
||||||
));
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row gutter={16}>{itemCard}</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(SelectPlatform);
|
|
||||||
@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Col,
|
|
||||||
Form,
|
|
||||||
Icon,
|
|
||||||
message,
|
|
||||||
notification,
|
|
||||||
Radio,
|
|
||||||
Select,
|
|
||||||
Tooltip,
|
|
||||||
} from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import axios from 'axios';
|
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
class SelectPolicyType extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
correctivePoliciesList: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetchPolicies();
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate payload using Select policy type
|
|
||||||
onHandleContinue = (e, formName) => {
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
if (values.correctiveActions === 'NONE') {
|
|
||||||
values.correctiveActions = [];
|
|
||||||
}
|
|
||||||
this.props.getPolicyPayloadData(formName, values);
|
|
||||||
this.props.getNextStep();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchPolicies = () => {
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies';
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let policies = res.data.data.policies;
|
|
||||||
let correctivePolicies = [];
|
|
||||||
for (let i = 0; i < policies.length; i++) {
|
|
||||||
if (policies[i].policyType === 'CORRECTIVE') {
|
|
||||||
correctivePolicies.push(
|
|
||||||
<Option key={policies[i].profileId}>
|
|
||||||
{policies[i].policyName}
|
|
||||||
</Option>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
correctivePoliciesList: correctivePolicies,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handlePolicyTypes = event => {
|
|
||||||
if (event.target.value === 'GENERAL') {
|
|
||||||
document.getElementById('generalPolicySubPanel').style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById('generalPolicySubPanel').style.display = 'none';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Form.Item style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('policyType', {
|
|
||||||
initialValue: 'GENERAL',
|
|
||||||
})(
|
|
||||||
<Radio.Group onChange={this.handlePolicyTypes}>
|
|
||||||
<Radio value="GENERAL">General Policy</Radio>
|
|
||||||
<Radio value="CORRECTIVE">Corrective Policy</Radio>
|
|
||||||
</Radio.Group>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<div id="generalPolicySubPanel" style={{ display: 'block' }}>
|
|
||||||
<Form.Item
|
|
||||||
label={
|
|
||||||
<span>
|
|
||||||
Select Corrective Policy
|
|
||||||
<Tooltip
|
|
||||||
title={
|
|
||||||
'Select the corrective policy to be applied when this general policy is violated'
|
|
||||||
}
|
|
||||||
placement="right"
|
|
||||||
>
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{getFieldDecorator('correctiveActions', {
|
|
||||||
initialValue: 'NONE',
|
|
||||||
})(
|
|
||||||
<Select style={{ width: '100%' }}>
|
|
||||||
<Option value="NONE">None</Option>
|
|
||||||
{this.state.correctivePoliciesList}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<Col span={16} offset={20}>
|
|
||||||
<div style={{ marginTop: 24 }}>
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={this.props.getPrevStep}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={e => this.onHandleContinue(e, 'policyTypeData')}
|
|
||||||
>
|
|
||||||
Continue
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(SelectPolicyType));
|
|
||||||
@ -1,233 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Form, Row, Col, Card, Steps, message, notification } from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import SelectPlatform from './components/SelectPlatform';
|
|
||||||
import ConfigureProfile from './components/ConfigureProfile';
|
|
||||||
import SelectPolicyType from './components/SelectPolicyType';
|
|
||||||
import AssignGroups from './components/AssignGroups';
|
|
||||||
import PublishDevices from './components/PublishDevices';
|
|
||||||
import axios from 'axios';
|
|
||||||
const { Step } = Steps;
|
|
||||||
|
|
||||||
class AddPolicy extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
currentStepIndex: 0,
|
|
||||||
isLoading: false,
|
|
||||||
policyUIConfigurationsList: [],
|
|
||||||
newPolicyPayload: { compliance: 'enforce' },
|
|
||||||
policyProfile: {},
|
|
||||||
payloadData: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getPolicyPayloadData = (dataName, dataValue) => {
|
|
||||||
Object.defineProperty(this.state.payloadData, dataName, {
|
|
||||||
value: dataValue,
|
|
||||||
writable: true,
|
|
||||||
});
|
|
||||||
if (dataName === 'publishDevicesData') {
|
|
||||||
this.createPayload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
createPayload = () => {
|
|
||||||
const {
|
|
||||||
publishDevicesData,
|
|
||||||
selectedPlatformData,
|
|
||||||
configureProfileData,
|
|
||||||
policyTypeData,
|
|
||||||
groupData,
|
|
||||||
} = this.state.payloadData;
|
|
||||||
const profile = {
|
|
||||||
profileName: publishDevicesData.policyName,
|
|
||||||
deviceType: selectedPlatformData.deviceType,
|
|
||||||
profileFeaturesList: configureProfileData,
|
|
||||||
};
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
policyName: publishDevicesData.policyName,
|
|
||||||
description: publishDevicesData.description,
|
|
||||||
compliance: 'enforce',
|
|
||||||
ownershipType: null,
|
|
||||||
active: publishDevicesData.active,
|
|
||||||
...policyTypeData,
|
|
||||||
profile: profile,
|
|
||||||
...groupData,
|
|
||||||
};
|
|
||||||
this.onAddNewPolicy(JSON.stringify(payload));
|
|
||||||
};
|
|
||||||
|
|
||||||
getPolicyConfigJson = type => {
|
|
||||||
this.setState({ isLoading: true });
|
|
||||||
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/device-types/' +
|
|
||||||
type +
|
|
||||||
'/ui-policy-configurations';
|
|
||||||
// send request to the invokers
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
isLoading: false,
|
|
||||||
policyUIConfigurationsList: JSON.parse(res.data.data),
|
|
||||||
currentStepIndex: 1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 Policy details.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setState({ isLoading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onAddNewPolicy = value => {
|
|
||||||
axios
|
|
||||||
.post(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies/',
|
|
||||||
value,
|
|
||||||
{ headers: { 'Content-Type': 'application-json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 201) {
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully added new Policy.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 New Policy.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getNextStep = () => {
|
|
||||||
const currentStepIndex = this.state.currentStepIndex + 1;
|
|
||||||
this.setState({ currentStepIndex });
|
|
||||||
};
|
|
||||||
|
|
||||||
getPrevStep = () => {
|
|
||||||
const currentStepIndex = this.state.currentStepIndex - 1;
|
|
||||||
this.setState({ currentStepIndex });
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { currentStepIndex, policyUIConfigurationsList } = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col span={20} offset={2}>
|
|
||||||
<Steps style={{ minHeight: 32 }} current={currentStepIndex}>
|
|
||||||
<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" />
|
|
||||||
</Steps>
|
|
||||||
</Col>
|
|
||||||
<Col span={16} offset={4}>
|
|
||||||
<Card style={{ marginTop: 24 }}>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 0 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<SelectPlatform
|
|
||||||
getPolicyConfigJson={this.getPolicyConfigJson}
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 1 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<ConfigureProfile
|
|
||||||
policyUIConfigurationsList={policyUIConfigurationsList}
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
getPrevStep={this.getPrevStep}
|
|
||||||
getNextStep={this.getNextStep}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 2 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<SelectPolicyType
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
getPrevStep={this.getPrevStep}
|
|
||||||
getNextStep={this.getNextStep}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 3 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<AssignGroups
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
getPrevStep={this.getPrevStep}
|
|
||||||
getNextStep={this.getNextStep}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 4 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<PublishDevices
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
getPrevStep={this.getPrevStep}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(
|
|
||||||
Form.create({ name: 'add-policy' })(AddPolicy),
|
|
||||||
);
|
|
||||||
@ -1,269 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
import React from 'react';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import { Button, Col, Form, message, notification, Radio, Select } from 'antd';
|
|
||||||
import axios from 'axios';
|
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
class AssignGroups extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.userSelector = React.createRef();
|
|
||||||
this.roleSelector = React.createRef();
|
|
||||||
this.state = {
|
|
||||||
roles: [],
|
|
||||||
users: [],
|
|
||||||
groups: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
componentDidMount() {
|
|
||||||
this.getRolesList();
|
|
||||||
this.getGroupsList();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSetUserRoleFormItem = event => {
|
|
||||||
if (event.target.value === 'roleSelector') {
|
|
||||||
this.roleSelector.current.style.cssText = 'display: block;';
|
|
||||||
this.userSelector.current.style.cssText = 'display: none;';
|
|
||||||
} else {
|
|
||||||
this.roleSelector.current.style.cssText = 'display: none;';
|
|
||||||
this.userSelector.current.style.cssText = 'display: block;';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate payload by adding Assign Groups
|
|
||||||
onHandleContinue = (e, formName) => {
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
if (typeof values.roles === 'string') {
|
|
||||||
values.roles = [values.roles];
|
|
||||||
}
|
|
||||||
if (!values.users) {
|
|
||||||
delete values.users;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values.deviceGroups === 'NONE') {
|
|
||||||
delete values.deviceGroups;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.getPolicyPayloadData(formName, values);
|
|
||||||
this.props.getNextStep();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getRolesList = () => {
|
|
||||||
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) {
|
|
||||||
this.setState({
|
|
||||||
roles: 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.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getUsersList = 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 users = JSON.parse(res.data.data);
|
|
||||||
this.setState({
|
|
||||||
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.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
getGroupsList = () => {
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/admin/groups';
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
groups: 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 trying to load device groups.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { policyData } = this.props;
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
let deviceGroups = null;
|
|
||||||
if (policyData.deviceGroups.length > 0) {
|
|
||||||
deviceGroups = policyData.deviceGroups;
|
|
||||||
} else {
|
|
||||||
deviceGroups = 'NONE';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Radio.Group
|
|
||||||
defaultValue={'roleSelector'}
|
|
||||||
onChange={this.handleSetUserRoleFormItem}
|
|
||||||
>
|
|
||||||
<Radio value="roleSelector">Set User role(s)</Radio>
|
|
||||||
<Radio value="userSelector">Set User(s)</Radio>
|
|
||||||
</Radio.Group>
|
|
||||||
<div
|
|
||||||
id={'roleSelector'}
|
|
||||||
ref={this.roleSelector}
|
|
||||||
style={{ display: 'block' }}
|
|
||||||
>
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator('roles', {
|
|
||||||
initialValue: policyData.roles,
|
|
||||||
})(
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
defaultActiveFirstOption={true}
|
|
||||||
>
|
|
||||||
<Option value={'ANY'}>Any</Option>
|
|
||||||
{this.state.roles.map(role => (
|
|
||||||
<Option key={role} value={role}>
|
|
||||||
{role}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id={'userSelector'}
|
|
||||||
ref={this.userSelector}
|
|
||||||
style={{ display: 'none' }}
|
|
||||||
>
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator('users', {
|
|
||||||
initialValue: policyData.users,
|
|
||||||
})(
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
onSearch={this.getUsersList}
|
|
||||||
>
|
|
||||||
{this.state.users.map(user => (
|
|
||||||
<Option key={user.username} value={user.username}>
|
|
||||||
{user.username}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Form.Item label={'Select Groups'} style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('deviceGroups', {
|
|
||||||
initialValue: deviceGroups,
|
|
||||||
})(
|
|
||||||
<Select mode="multiple" style={{ width: '100%' }}>
|
|
||||||
<Option value={'NONE'}>NONE</Option>
|
|
||||||
{this.state.groups.map(group => (
|
|
||||||
<Option key={group.name} value={group.name}>
|
|
||||||
{group.name}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Col span={16} offset={20}>
|
|
||||||
<div style={{ marginTop: 24 }}>
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={this.props.getPrevStep}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={e => this.onHandleContinue(e, 'groupData')}
|
|
||||||
>
|
|
||||||
Continue
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(AssignGroups));
|
|
||||||
@ -1,949 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Tabs,
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
Switch,
|
|
||||||
Input,
|
|
||||||
Typography,
|
|
||||||
Form,
|
|
||||||
Collapse,
|
|
||||||
Checkbox,
|
|
||||||
Select,
|
|
||||||
Tooltip,
|
|
||||||
Icon,
|
|
||||||
Table,
|
|
||||||
Alert,
|
|
||||||
Upload,
|
|
||||||
Popconfirm,
|
|
||||||
Button,
|
|
||||||
Radio,
|
|
||||||
} from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import '../../../../styles.css';
|
|
||||||
import moment from 'moment';
|
|
||||||
const { Text, Title, Paragraph } = Typography;
|
|
||||||
const { TabPane } = Tabs;
|
|
||||||
const { Option } = Select;
|
|
||||||
const { TextArea } = Input;
|
|
||||||
|
|
||||||
const subPanelpayloadAttributes = {};
|
|
||||||
let subFormContainer = {};
|
|
||||||
let radioSubPanelSwitches = [];
|
|
||||||
let initialRadioPanels = {};
|
|
||||||
let radioPanelStatusList = {};
|
|
||||||
|
|
||||||
class ConfigureProfile extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
loading: false,
|
|
||||||
activePanelKeys: [],
|
|
||||||
activeSubPanelKeys: [],
|
|
||||||
subFormList: [],
|
|
||||||
subPanelpayloadAttributes: {},
|
|
||||||
customInputDataArray: [],
|
|
||||||
inputTableDataSources: {},
|
|
||||||
subPanelRadio: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {}
|
|
||||||
|
|
||||||
setProfileInfo = e => {
|
|
||||||
let activePolicies = [];
|
|
||||||
let activePolicyFields = {};
|
|
||||||
let activeSubPanels = [];
|
|
||||||
let subPanelRadio = this.state.subPanelRadio;
|
|
||||||
this.setState({
|
|
||||||
subPanelRadio: radioPanelStatusList,
|
|
||||||
});
|
|
||||||
const allFields = this.props.form.getFieldsValue();
|
|
||||||
this.props.policyFeatureList.map(element => {
|
|
||||||
activePolicies.push(element.featureCode);
|
|
||||||
let featureData = JSON.parse(element.content);
|
|
||||||
Object.keys(featureData).map(key => {
|
|
||||||
if (element.featureCode in subPanelpayloadAttributes) {
|
|
||||||
Object.entries(subPanelpayloadAttributes[element.featureCode]).map(
|
|
||||||
([panelKey, payloadAttr]) => {
|
|
||||||
if (key === payloadAttr) {
|
|
||||||
activeSubPanels.push(`${element.featureCode}-${panelKey}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let regex = new RegExp(`${element.featureCode}.+${key}`, 'g');
|
|
||||||
Object.keys(allFields).map(fieldName => {
|
|
||||||
if (fieldName.match(regex) != null) {
|
|
||||||
activePolicyFields[fieldName] = featureData[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (element.featureCode in subFormContainer) {
|
|
||||||
let regex = new RegExp(`.+${element.featureCode}-${key}`, 'g');
|
|
||||||
Object.keys(allFields).map(fieldName => {
|
|
||||||
if (fieldName.match(regex) != null) {
|
|
||||||
activePolicyFields[fieldName] = featureData[key];
|
|
||||||
if (
|
|
||||||
!activePolicies.includes(
|
|
||||||
fieldName.replace(`-${element.featureCode}-${key}`, ''),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
activePolicies.push(
|
|
||||||
fieldName.replace(`-${element.featureCode}-${key}`, ''),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let regex = new RegExp(`${element.featureCode}.+${key}`, 'g');
|
|
||||||
Object.keys(allFields).map(fieldName => {
|
|
||||||
if (fieldName.match(regex) != null) {
|
|
||||||
activePolicyFields[fieldName] = featureData[key];
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
radioSubPanelSwitches.includes(
|
|
||||||
`${element.featureCode}-${featureData[key]}`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
let subPanelViewStatus = {
|
|
||||||
[featureData[key]]: true,
|
|
||||||
};
|
|
||||||
Object.assign(subPanelRadio, subPanelViewStatus);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.props.form.setFieldsValue(activePolicyFields);
|
|
||||||
Object.keys(initialRadioPanels).map(policy => {
|
|
||||||
if (!activePolicies.includes(policy)) {
|
|
||||||
for (let subPanelKey of initialRadioPanels[policy]) {
|
|
||||||
let subPanelViewStatus = {
|
|
||||||
[subPanelKey]: true,
|
|
||||||
};
|
|
||||||
Object.assign(subPanelRadio, subPanelViewStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
activePanelKeys: activePolicies,
|
|
||||||
activeSubPanelKeys: activeSubPanels,
|
|
||||||
subPanelRadio,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// convert time from 24h format to 12h format
|
|
||||||
timeConverter = time => {
|
|
||||||
time = time
|
|
||||||
.toString()
|
|
||||||
.match(/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/) || [time];
|
|
||||||
if (time.length > 1) {
|
|
||||||
time = time.slice(1);
|
|
||||||
time[5] = +time[0] < 12 ? ' AM' : ' PM';
|
|
||||||
time[0] = +time[0] % 12 || 12;
|
|
||||||
}
|
|
||||||
return time.join('');
|
|
||||||
};
|
|
||||||
|
|
||||||
// get Option value from start Time, end Time and time difference between 2 values
|
|
||||||
getOptionForTimeSelectors = (startTimeValue, endTimeValue, timeIncrement) => {
|
|
||||||
let timeOptions = [];
|
|
||||||
let time = new Date(
|
|
||||||
moment()
|
|
||||||
.startOf('day')
|
|
||||||
.format('YYYY/MM/DD'),
|
|
||||||
);
|
|
||||||
let tempValue = startTimeValue;
|
|
||||||
time.setMinutes(time.getMinutes() + tempValue);
|
|
||||||
let startOption = (
|
|
||||||
<Option value={String(tempValue)}>
|
|
||||||
{this.timeConverter(
|
|
||||||
`${String(time)
|
|
||||||
.split(' ')[4]
|
|
||||||
.substring(0, 5)}`,
|
|
||||||
)}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
timeOptions.push(startOption);
|
|
||||||
|
|
||||||
while (tempValue !== endTimeValue) {
|
|
||||||
time = new Date(
|
|
||||||
moment()
|
|
||||||
.startOf('day')
|
|
||||||
.format('YYYY/MM/DD'),
|
|
||||||
);
|
|
||||||
tempValue += timeIncrement;
|
|
||||||
if (tempValue > 1440) {
|
|
||||||
tempValue = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
time.setMinutes(time.getMinutes() + tempValue);
|
|
||||||
let option = (
|
|
||||||
<Option value={String(tempValue)}>
|
|
||||||
{this.timeConverter(
|
|
||||||
`${String(time)
|
|
||||||
.split(' ')[4]
|
|
||||||
.substring(0, 5)}`,
|
|
||||||
)}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
timeOptions.push(option);
|
|
||||||
}
|
|
||||||
return timeOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle items which handle from radio buttons
|
|
||||||
handleRadioPanel = (e, subPanel) => {
|
|
||||||
{
|
|
||||||
subPanel.map((panel, i) => {
|
|
||||||
if (panel.value === e.target.value) {
|
|
||||||
document.getElementById(panel.value).style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById(panel.value).style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle items which handle from select options
|
|
||||||
handleSelectedPanel = (e, subPanel) => {
|
|
||||||
{
|
|
||||||
subPanel.map((panel, i) => {
|
|
||||||
if (panel.id === e) {
|
|
||||||
document.getElementById(panel.id).style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById(panel.id).style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle items which handle from checkbox
|
|
||||||
handleSubPanel = e => {
|
|
||||||
if (e.target.checked) {
|
|
||||||
let joined = this.state.activeSubPanelKeys.concat(e.target.id);
|
|
||||||
this.setState({ activeSubPanelKeys: joined });
|
|
||||||
} else {
|
|
||||||
let index = this.state.activeSubPanelKeys.indexOf(e.target.id);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.state.activeSubPanelKeys.splice(index, 1);
|
|
||||||
let removed = this.state.activeSubPanelKeys;
|
|
||||||
this.setState({ activeSubPanelKeys: removed });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle Switch on off button
|
|
||||||
handleMainPanel = (e, ref) => {
|
|
||||||
if (e) {
|
|
||||||
let joined = this.state.activePanelKeys.concat(ref);
|
|
||||||
this.setState({ activePanelKeys: joined });
|
|
||||||
} else {
|
|
||||||
let index = this.state.activePanelKeys.indexOf(ref);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.state.activePanelKeys.splice(index, 1);
|
|
||||||
let removed = this.state.activePanelKeys;
|
|
||||||
this.setState({ activePanelKeys: removed });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleCustomInputTable = event => {
|
|
||||||
const { count, customInputDataArray } = this.state;
|
|
||||||
|
|
||||||
const newData = [
|
|
||||||
{
|
|
||||||
key: count,
|
|
||||||
CERT_NAME: `${event.file.name}`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
this.setState({
|
|
||||||
customInputDataArray: [...customInputDataArray, newData],
|
|
||||||
count: count + 1,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleAdd = array => {
|
|
||||||
const { count, inputTableDataSources } = this.state;
|
|
||||||
const newData = [
|
|
||||||
{
|
|
||||||
key: count,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
inputTableDataSources[array].push(newData);
|
|
||||||
Object.defineProperty(inputTableDataSources, array, {
|
|
||||||
value: inputTableDataSources[array],
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
inputTableDataSources,
|
|
||||||
count: count + 1,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getColumns = ({ getFieldDecorator }, arr) => {
|
|
||||||
const columnArray = [];
|
|
||||||
const actionColumn = [
|
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
dataIndex: 'operation',
|
|
||||||
render: (name, row) => (
|
|
||||||
<Form.Item>
|
|
||||||
<Popconfirm title="Sure to delete?">
|
|
||||||
<a>
|
|
||||||
<Text type="danger">
|
|
||||||
<Icon type="delete" />
|
|
||||||
</Text>
|
|
||||||
</a>
|
|
||||||
</Popconfirm>
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
Object.values(arr).map((columnData, c) => {
|
|
||||||
if (columnData.type === 'input') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {})(
|
|
||||||
<Input
|
|
||||||
type={columnData.others.inputType}
|
|
||||||
placeholder={columnData.others.placeholder}
|
|
||||||
/>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
} else if (columnData.type === 'upload') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {})(
|
|
||||||
<Upload>
|
|
||||||
<Button>
|
|
||||||
<Icon type="upload" /> Choose file
|
|
||||||
</Button>
|
|
||||||
</Upload>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
} else if (columnData.type === 'select') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {
|
|
||||||
initialValue: columnData.others.initialDataIndex,
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
{columnData.others.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.key}>
|
|
||||||
{option.value}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const columns = columnArray.concat(actionColumn);
|
|
||||||
return columns;
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate payload by adding policy configurations
|
|
||||||
onHandleContinue = (e, formname) => {
|
|
||||||
const allFields = this.props.form.getFieldsValue();
|
|
||||||
let activeFields = [];
|
|
||||||
// get currently active field list
|
|
||||||
for (let i = 0; i < this.state.activePanelKeys.length; i++) {
|
|
||||||
Object.keys(allFields).map(key => {
|
|
||||||
if (key.includes(`${this.state.activePanelKeys[i]}-`)) {
|
|
||||||
if (
|
|
||||||
subPanelpayloadAttributes.hasOwnProperty(
|
|
||||||
`${this.state.activePanelKeys[i]}`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Object.keys(
|
|
||||||
subPanelpayloadAttributes[this.state.activePanelKeys[i]],
|
|
||||||
).map(subPanel => {
|
|
||||||
if (`${this.state.activePanelKeys[i]}-${subPanel}` === true) {
|
|
||||||
if (key.includes(`-${subPanel}-`)) {
|
|
||||||
activeFields.push(key);
|
|
||||||
}
|
|
||||||
} else if (!key.includes(`-${subPanel}-`)) {
|
|
||||||
activeFields.push(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
activeFields.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.onFieldValidate(activeFields, formname);
|
|
||||||
};
|
|
||||||
|
|
||||||
onFieldValidate = (fields, formName) => {
|
|
||||||
// validate fields and get profile features list
|
|
||||||
this.props.form.validateFields(fields, (err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
let profileFeaturesList = [];
|
|
||||||
for (let i = 0; i < this.state.activePanelKeys.length; i++) {
|
|
||||||
let content = {};
|
|
||||||
Object.entries(values).map(([key, value]) => {
|
|
||||||
if (key.includes(`${this.state.activePanelKeys[i]}-`)) {
|
|
||||||
content[
|
|
||||||
key.replace(`${this.state.activePanelKeys[i]}-`, '')
|
|
||||||
] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let feature = {
|
|
||||||
featureCode: this.state.activePanelKeys[i],
|
|
||||||
deviceType: this.props.deviceType,
|
|
||||||
content: content,
|
|
||||||
};
|
|
||||||
profileFeaturesList.push(feature);
|
|
||||||
}
|
|
||||||
this.props.getPolicyPayloadData(formName, profileFeaturesList);
|
|
||||||
this.props.getNextStep();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate form items
|
|
||||||
getPanelItems = (panel, panelId) => {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
const subPanelList = {};
|
|
||||||
let initialRadioOptions = [];
|
|
||||||
return panel.map((item, k) => {
|
|
||||||
switch (item.type) {
|
|
||||||
case 'select':
|
|
||||||
if (item.optional.hasOwnProperty('subPanel')) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: `${item.optional.option[0].name}`,
|
|
||||||
})(
|
|
||||||
<Select
|
|
||||||
onChange={e =>
|
|
||||||
this.handleSelectedPanel(e, item.optional.subPanel)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{item.optional.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<div className={'sub-panel-container'}>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
id={panel.id}
|
|
||||||
key={i}
|
|
||||||
style={
|
|
||||||
panel.id === item.optional.initialDataIndex
|
|
||||||
? { display: 'block' }
|
|
||||||
: { display: 'none' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{this.getPanelItems(panel.panelItem)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
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}`, {
|
|
||||||
initialValue: `${item.optional.option[0].name}`,
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
{item.optional.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case 'timeSelector':
|
|
||||||
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}`, {
|
|
||||||
initialValue: item.optional.initialDataIndex,
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
{this.getOptionForTimeSelectors(
|
|
||||||
item.optional.firstOptionValue,
|
|
||||||
item.optional.lastOptionValue,
|
|
||||||
item.optional.valueDifference,
|
|
||||||
)}
|
|
||||||
</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':
|
|
||||||
if (item.optional.hasOwnProperty('subPanel')) {
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Collapse
|
|
||||||
bordered={false}
|
|
||||||
activeKey={this.state.activeSubPanelKeys}
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
key={item.id}
|
|
||||||
showArrow={false}
|
|
||||||
style={{ border: 0 }}
|
|
||||||
header={
|
|
||||||
<Form.Item key={k}>
|
|
||||||
{getFieldDecorator(`${item.id}`, {
|
|
||||||
valuePropName: 'checked',
|
|
||||||
initialValue: item.optional.ischecked,
|
|
||||||
})(
|
|
||||||
<Checkbox onChange={this.handleSubPanel}>
|
|
||||||
<span>
|
|
||||||
{item.label}
|
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
</Checkbox>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
subPanelList[panel.others.itemSwitch] =
|
|
||||||
panel.others.itemPayload;
|
|
||||||
if (
|
|
||||||
subPanelpayloadAttributes.hasOwnProperty(panelId)
|
|
||||||
) {
|
|
||||||
Object.assign(
|
|
||||||
subPanelpayloadAttributes[panelId],
|
|
||||||
subPanelList,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
subPanelpayloadAttributes[panelId] = subPanelList;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div key={i}>
|
|
||||||
{this.getPanelItems(panel.panelItem, panelId)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Form.Item key={k}>
|
|
||||||
{getFieldDecorator(`${item.id}`, {
|
|
||||||
valuePropName: 'checked',
|
|
||||||
initialValue: item.optional.ischecked,
|
|
||||||
})(
|
|
||||||
<Checkbox>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: null,
|
|
||||||
})(
|
|
||||||
<TextArea
|
|
||||||
placeholder={item.optional.placeholder}
|
|
||||||
rows={item.optional.row}
|
|
||||||
/>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case 'radioGroup':
|
|
||||||
initialRadioOptions.push(item.optional.initialValue);
|
|
||||||
initialRadioPanels[panelId] = initialRadioOptions;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: `${item.optional.initialValue}`,
|
|
||||||
})(
|
|
||||||
<Radio.Group
|
|
||||||
onChange={e =>
|
|
||||||
this.handleRadioPanel(e, item.optional.radio)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{item.optional.radio.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Radio key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Radio>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Radio.Group>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<div className={'sub-panel-container'}>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
radioSubPanelSwitches.push(`${panelId}-${panel.id}`);
|
|
||||||
radioPanelStatusList[panel.id] = false;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
id={panel.id}
|
|
||||||
ref={panel.id}
|
|
||||||
style={
|
|
||||||
this.state.subPanelRadio[panel.id]
|
|
||||||
? { display: 'block' }
|
|
||||||
: { display: 'none' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{this.getPanelItems(panel.panelItem)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
case 'inputTable':
|
|
||||||
if (
|
|
||||||
!(`${item.optional.dataSource}` in this.state.inputTableDataSources)
|
|
||||||
) {
|
|
||||||
Object.defineProperty(
|
|
||||||
this.state.inputTableDataSources,
|
|
||||||
`${item.optional.dataSource}`,
|
|
||||||
{ value: [], writable: true },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Button
|
|
||||||
onClick={() => this.handleAdd(item.optional.dataSource)}
|
|
||||||
type="primary"
|
|
||||||
style={{ marginBottom: 16 }}
|
|
||||||
>
|
|
||||||
<Icon type="plus-circle" />
|
|
||||||
{item.optional.button.name}
|
|
||||||
</Button>
|
|
||||||
<Table
|
|
||||||
id={item.id}
|
|
||||||
dataSource={
|
|
||||||
this.state.inputTableDataSources[item.optional.dataSource]
|
|
||||||
}
|
|
||||||
columns={this.getColumns(
|
|
||||||
{ getFieldDecorator },
|
|
||||||
item.optional.columns,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case 'customInputTable':
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Upload onChange={this.handleCustomInputTable}>
|
|
||||||
<Button type="primary" style={{ marginBottom: 16 }}>
|
|
||||||
<Icon type="plus-circle" />
|
|
||||||
{item.optional.button.name}
|
|
||||||
</Button>
|
|
||||||
</Upload>
|
|
||||||
<Table
|
|
||||||
id={item.id}
|
|
||||||
dataSource={this.state.customInputDataArray}
|
|
||||||
columns={this.getColumns(
|
|
||||||
{ getFieldDecorator },
|
|
||||||
item.optional.columns,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { policyUIConfigurationsList } = this.props;
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div className="tab-container">
|
|
||||||
<Tabs
|
|
||||||
tabPosition={'left'}
|
|
||||||
size={'large'}
|
|
||||||
onTabClick={this.setProfileInfo}
|
|
||||||
>
|
|
||||||
{policyUIConfigurationsList.map((element, i) => {
|
|
||||||
return (
|
|
||||||
<TabPane tab={<span>{element.name}</span>} key={i}>
|
|
||||||
{Object.values(element.panels).map((panel, j) => {
|
|
||||||
panel = panel.panel;
|
|
||||||
return (
|
|
||||||
<div key={j}>
|
|
||||||
<Collapse
|
|
||||||
bordered={false}
|
|
||||||
activeKey={this.state.activePanelKeys}
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
key={panel.panelId}
|
|
||||||
showArrow={false}
|
|
||||||
style={{ border: 0 }}
|
|
||||||
header={
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col offset={0} span={14}>
|
|
||||||
<Title level={4}> {panel.title} </Title>
|
|
||||||
</Col>
|
|
||||||
<Col offset={8} span={1}>
|
|
||||||
<Switch
|
|
||||||
id={`${panel.panelId}_SWITCH`}
|
|
||||||
checkedChildren="ON"
|
|
||||||
unCheckedChildren="OFF"
|
|
||||||
onChange={e =>
|
|
||||||
this.handleMainPanel(
|
|
||||||
e,
|
|
||||||
`${panel.panelId}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>{panel.description}</Row>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{panel.hasOwnProperty('panelItem') && (
|
|
||||||
<div>
|
|
||||||
<Form name={panel.panelId}>
|
|
||||||
<Form.Item style={{ display: 'none' }}>
|
|
||||||
{getFieldDecorator(`${panel.panelId}`, {
|
|
||||||
initialValue: ' ',
|
|
||||||
})(<Input />)}
|
|
||||||
</Form.Item>
|
|
||||||
{this.getPanelItems(
|
|
||||||
panel.panelItem,
|
|
||||||
panel.panelId,
|
|
||||||
)}
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{panel.hasOwnProperty('subFormLists') && (
|
|
||||||
<div>
|
|
||||||
{Object.values(panel.subFormLists).map(
|
|
||||||
(form, i) => {
|
|
||||||
subFormContainer[`${form.id}`] =
|
|
||||||
panel.panelId;
|
|
||||||
return (
|
|
||||||
<Form name={form.id} key={i}>
|
|
||||||
<Form.Item style={{ display: 'none' }}>
|
|
||||||
{getFieldDecorator(`${form.id}`, {
|
|
||||||
initialValue: ' ',
|
|
||||||
})(<Input />)}
|
|
||||||
</Form.Item>
|
|
||||||
{this.getPanelItems(form.panelItem)}
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TabPane>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Tabs>
|
|
||||||
<Col span={16} offset={20}>
|
|
||||||
<div style={{ marginTop: 24 }}>
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={this.props.getPrevStep}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={e => this.onHandleContinue(e, 'configureProfileData')}
|
|
||||||
>
|
|
||||||
Continue
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(ConfigureProfile));
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
import React from 'react';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import { Button, Col, Form, Input } from 'antd';
|
|
||||||
const { TextArea } = Input;
|
|
||||||
|
|
||||||
class PublishDevices extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickSavePolicy = (event, formName) => {
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
this.props.getPolicyPayloadData(formName, values);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { policyData } = this.props;
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Form.Item
|
|
||||||
label={'Set a name to your policy *'}
|
|
||||||
style={{ display: 'block' }}
|
|
||||||
>
|
|
||||||
{getFieldDecorator('policyName', {
|
|
||||||
initialValue: policyData.policyName,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
pattern: new RegExp('^.{1,30}$'),
|
|
||||||
message: 'Should be 1-to-30 characters long',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input placeholder={'Should be 1 to 30 characters long'} />)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label={'Add a Description'} style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('description', {
|
|
||||||
initialValue: policyData.description,
|
|
||||||
})(<TextArea rows={8} />)}
|
|
||||||
</Form.Item>
|
|
||||||
<Col span={16} offset={18}>
|
|
||||||
<div style={{ marginTop: 24 }}>
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={this.props.getPrevStep}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
style={{ marginRight: 8 }}
|
|
||||||
onClick={e => this.onClickSavePolicy(e, 'publishDevicesData')}
|
|
||||||
>
|
|
||||||
Save & Publish
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={e => this.onClickSavePolicy(e, 'publishDevicesData')}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(PublishDevices));
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Col,
|
|
||||||
Form,
|
|
||||||
Icon,
|
|
||||||
message,
|
|
||||||
notification,
|
|
||||||
Radio,
|
|
||||||
Select,
|
|
||||||
Tooltip,
|
|
||||||
} from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import axios from 'axios';
|
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
class SelectPolicyType extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
correctivePoliciesList: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetchPolicies();
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate payload using Select policy type
|
|
||||||
onHandleContinue = (e, formName) => {
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
if (
|
|
||||||
values.policyType === 'CORRECTIVE' ||
|
|
||||||
values.correctiveActions === 'NONE'
|
|
||||||
) {
|
|
||||||
values.correctiveActions = [];
|
|
||||||
}
|
|
||||||
this.props.getPolicyPayloadData(formName, values);
|
|
||||||
this.props.getNextStep();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchPolicies = () => {
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies';
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let policies = res.data.data.policies;
|
|
||||||
let correctivePolicies = [];
|
|
||||||
for (let i = 0; i < policies.length; i++) {
|
|
||||||
if (policies[i].policyType === 'CORRECTIVE') {
|
|
||||||
correctivePolicies.push(
|
|
||||||
<Option key={policies[i].profileId}>
|
|
||||||
{policies[i].policyName}
|
|
||||||
</Option>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
correctivePoliciesList: correctivePolicies,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handlePolicyTypes = event => {
|
|
||||||
if (event.target.value === 'GENERAL') {
|
|
||||||
document.getElementById('generalPolicySubPanel').style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById('generalPolicySubPanel').style.display = 'none';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { policyData } = this.props;
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
let correctiveActions = null;
|
|
||||||
if (policyData.correctiveActions.length > 0) {
|
|
||||||
correctiveActions = '';
|
|
||||||
} else {
|
|
||||||
correctiveActions = 'NONE';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Form.Item style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('policyType', {
|
|
||||||
initialValue: policyData.policyType,
|
|
||||||
})(
|
|
||||||
<Radio.Group onChange={this.handlePolicyTypes}>
|
|
||||||
<Radio value="GENERAL">General Policy</Radio>
|
|
||||||
<Radio value="CORRECTIVE">Corrective Policy</Radio>
|
|
||||||
</Radio.Group>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<div id="generalPolicySubPanel" style={{ display: 'block' }}>
|
|
||||||
<Form.Item
|
|
||||||
label={
|
|
||||||
<span>
|
|
||||||
Select Corrective Policy
|
|
||||||
<Tooltip
|
|
||||||
title={
|
|
||||||
'Select the corrective policy to be applied when this general policy is violated'
|
|
||||||
}
|
|
||||||
placement="right"
|
|
||||||
>
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{getFieldDecorator('correctiveActions', {
|
|
||||||
initialValue: correctiveActions,
|
|
||||||
})(
|
|
||||||
<Select style={{ width: '100%' }}>
|
|
||||||
<Option value="NONE">None</Option>
|
|
||||||
{this.state.correctivePoliciesList}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<Col span={16} offset={20}>
|
|
||||||
<div style={{ marginTop: 24 }}>
|
|
||||||
<Button style={{ marginRight: 8 }} onClick={this.props.getPrevStep}>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={e => this.onHandleContinue(e, 'policyTypeData')}
|
|
||||||
>
|
|
||||||
Continue
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(SelectPolicyType));
|
|
||||||
@ -1,273 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Form, Row, Col, Card, Steps, message, notification } from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import ConfigureProfile from './components/ConfigureProfile';
|
|
||||||
import SelectPolicyType from './components/SelectPolicyType';
|
|
||||||
import AssignGroups from './components/AssignGroups';
|
|
||||||
import PublishDevices from './components/PublishDevices';
|
|
||||||
import axios from 'axios';
|
|
||||||
const { Step } = Steps;
|
|
||||||
|
|
||||||
class EditPolicy extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
currentStepIndex: 0,
|
|
||||||
policyUIConfigurationsList: null,
|
|
||||||
newPolicyPayload: { compliance: 'enforce' },
|
|
||||||
policyProfile: {},
|
|
||||||
payloadData: {},
|
|
||||||
policyFeatureList: [],
|
|
||||||
policyData: {},
|
|
||||||
deviceType: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.getSelectedPolicy(this.props.policyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPolicyPayloadData = (dataName, dataValue) => {
|
|
||||||
Object.defineProperty(this.state.payloadData, dataName, {
|
|
||||||
value: dataValue,
|
|
||||||
writable: true,
|
|
||||||
});
|
|
||||||
if (dataName === 'publishDevicesData') {
|
|
||||||
this.createPayload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
createPayload = () => {
|
|
||||||
const {
|
|
||||||
publishDevicesData,
|
|
||||||
configureProfileData,
|
|
||||||
policyTypeData,
|
|
||||||
groupData,
|
|
||||||
} = this.state.payloadData;
|
|
||||||
const profile = {
|
|
||||||
profileName: publishDevicesData.policyName,
|
|
||||||
deviceType: this.state.deviceType,
|
|
||||||
profileFeaturesList: configureProfileData,
|
|
||||||
};
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
...publishDevicesData,
|
|
||||||
compliance: 'enforce',
|
|
||||||
ownershipType: null,
|
|
||||||
...policyTypeData,
|
|
||||||
profile: profile,
|
|
||||||
...groupData,
|
|
||||||
};
|
|
||||||
this.onEditPolicy(JSON.stringify(payload));
|
|
||||||
};
|
|
||||||
|
|
||||||
getSelectedPolicy = policyId => {
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies/' +
|
|
||||||
policyId;
|
|
||||||
|
|
||||||
// send request to the invokers
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
isLoading: true,
|
|
||||||
policyData: res.data.data,
|
|
||||||
deviceType: res.data.data.profile.deviceType,
|
|
||||||
policyFeatureList: res.data.data.profile.profileFeaturesList,
|
|
||||||
});
|
|
||||||
this.getPolicyConfigJson(res.data.data.profile.deviceType);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 selected policy.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getPolicyConfigJson = type => {
|
|
||||||
this.setState({ isLoading: true });
|
|
||||||
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/device-types/' +
|
|
||||||
type +
|
|
||||||
'/ui-policy-configurations';
|
|
||||||
// send request to the invokers
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
policyUIConfigurationsList: JSON.parse(res.data.data),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load Policy details.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onEditPolicy = value => {
|
|
||||||
axios
|
|
||||||
.put(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies/' +
|
|
||||||
this.props.policyId,
|
|
||||||
value,
|
|
||||||
{ headers: { 'Content-Type': 'application-json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully Updated the Policy.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 Updated the Policy.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getNextStep = () => {
|
|
||||||
const currentStepIndex = this.state.currentStepIndex + 1;
|
|
||||||
this.setState({ currentStepIndex });
|
|
||||||
};
|
|
||||||
|
|
||||||
getPrevStep = () => {
|
|
||||||
const currentStepIndex = this.state.currentStepIndex - 1;
|
|
||||||
this.setState({ currentStepIndex });
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
currentStepIndex,
|
|
||||||
policyUIConfigurationsList,
|
|
||||||
policyFeatureList,
|
|
||||||
policyData,
|
|
||||||
deviceType,
|
|
||||||
} = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{policyUIConfigurationsList != null && (
|
|
||||||
<Row>
|
|
||||||
<Col span={20} offset={2}>
|
|
||||||
<Steps style={{ minHeight: 32 }} current={currentStepIndex}>
|
|
||||||
<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" />
|
|
||||||
</Steps>
|
|
||||||
</Col>
|
|
||||||
<Col span={16} offset={4}>
|
|
||||||
<Card style={{ marginTop: 24 }}>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 0 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<ConfigureProfile
|
|
||||||
policyUIConfigurationsList={policyUIConfigurationsList}
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
getNextStep={this.getNextStep}
|
|
||||||
policyFeatureList={policyFeatureList}
|
|
||||||
deviceType={deviceType}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 1 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<SelectPolicyType
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
policyData={policyData}
|
|
||||||
getPrevStep={this.getPrevStep}
|
|
||||||
getNextStep={this.getNextStep}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 2 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<AssignGroups
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
policyData={policyData}
|
|
||||||
getPrevStep={this.getPrevStep}
|
|
||||||
getNextStep={this.getNextStep}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: currentStepIndex === 3 ? 'unset' : 'none' }}
|
|
||||||
>
|
|
||||||
<PublishDevices
|
|
||||||
policyData={policyData}
|
|
||||||
getPolicyPayloadData={this.getPolicyPayloadData}
|
|
||||||
getPrevStep={this.getPrevStep}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(
|
|
||||||
Form.create({ name: 'edit-policy' })(EditPolicy),
|
|
||||||
);
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Divider, Icon, Tooltip } from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
|
||||||
class PolicyAction extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Tooltip placement="top" title={'Edit Policy'}>
|
|
||||||
<Link
|
|
||||||
to={`/entgra/policy/edit/${this.props.selectedPolicyData.id}`}
|
|
||||||
>
|
|
||||||
<Icon type="edit" />
|
|
||||||
</Link>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="top" title={''}>
|
|
||||||
<Link
|
|
||||||
to={`/entgra/policy/view/${this.props.selectedPolicyData.id}`}
|
|
||||||
>
|
|
||||||
<Icon type="eye" />
|
|
||||||
</Link>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(PolicyAction);
|
|
||||||
@ -1,178 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Button, Tooltip, Popconfirm, Divider } from 'antd';
|
|
||||||
|
|
||||||
class BulkActionBar extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
selectedMultiple: false,
|
|
||||||
selectedSingle: false,
|
|
||||||
isPolicyActive: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method checks whether active devices are selected
|
|
||||||
onCheckPolicyStatus = () => {
|
|
||||||
let tempIsPolicyActive;
|
|
||||||
for (let i = 0; i < this.props.selectedRows.length; i++) {
|
|
||||||
if (this.props.selectedRows[i].active) {
|
|
||||||
tempIsPolicyActive = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tempIsPolicyActive = false;
|
|
||||||
}
|
|
||||||
this.setState({ isPolicyActive: tempIsPolicyActive });
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmRemove = () => {
|
|
||||||
if (!this.state.isPolicyActive) {
|
|
||||||
this.props.removePolicy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmPublish = () => {
|
|
||||||
if (!this.state.isPolicyActive) {
|
|
||||||
this.props.publishPolicy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmUnpublish = () => {
|
|
||||||
if (this.state.isPolicyActive) {
|
|
||||||
this.props.unpublishPolicy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const isSelected = this.props.selectedRows.length > 0;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div style={{ padding: '5px' }}>
|
|
||||||
<Tooltip placement="bottom" title={'Apply Changes to Device'}>
|
|
||||||
<Popconfirm
|
|
||||||
placement="topLeft"
|
|
||||||
title={'Do you really want to apply changes to all policies?'}
|
|
||||||
onConfirm={this.props.applyChanges}
|
|
||||||
okText="Yes"
|
|
||||||
cancelText="No"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="check-circle"
|
|
||||||
size={'default'}
|
|
||||||
style={{ margin: '2px' }}
|
|
||||||
>
|
|
||||||
APPLY CHANGES TO DEVICES
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: isSelected ? 'inline' : 'none', padding: '8px' }}
|
|
||||||
>
|
|
||||||
<Tooltip
|
|
||||||
placement="bottom"
|
|
||||||
title={'Remove'}
|
|
||||||
autoAdjustOverflow={true}
|
|
||||||
>
|
|
||||||
<Popconfirm
|
|
||||||
placement="topLeft"
|
|
||||||
title={
|
|
||||||
!this.state.isPolicyActive
|
|
||||||
? 'Do you really want to remove the selected policy(s)?'
|
|
||||||
: 'You cannot select already active policies. Please deselect active policies and try again.'
|
|
||||||
}
|
|
||||||
onConfirm={this.onConfirmRemove}
|
|
||||||
okText="Yes"
|
|
||||||
cancelText="No"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="delete"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.onCheckPolicyStatus}
|
|
||||||
style={{ margin: '2px' }}
|
|
||||||
>
|
|
||||||
Remove
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="bottom" title={'Publish'}>
|
|
||||||
<Popconfirm
|
|
||||||
placement="topLeft"
|
|
||||||
title={
|
|
||||||
!this.state.isPolicyActive
|
|
||||||
? 'Do you really want to publish the selected policy(s)??'
|
|
||||||
: 'You cannot select already active policies. Please deselect active policies and try again.'
|
|
||||||
}
|
|
||||||
okText="Yes"
|
|
||||||
onConfirm={this.onConfirmPublish}
|
|
||||||
cancelText="No"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="import"
|
|
||||||
onClick={this.onCheckPolicyStatus}
|
|
||||||
size={'default'}
|
|
||||||
style={{
|
|
||||||
margin: '2px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Publish
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Tooltip placement="bottom" title={'Unpublish'}>
|
|
||||||
<Popconfirm
|
|
||||||
placement="topLeft"
|
|
||||||
title={
|
|
||||||
this.state.isPolicyActive
|
|
||||||
? 'Do you really want to unpublish the selected policy(s)?'
|
|
||||||
: 'You cannot select already inactive policies to be unpublished. Please deselect inactive policies and try again.'
|
|
||||||
}
|
|
||||||
okText="Yes"
|
|
||||||
onConfirm={this.onConfirmUnpublish}
|
|
||||||
cancelText="No"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
shape="circle"
|
|
||||||
icon="export"
|
|
||||||
onClick={this.onCheckPolicyStatus}
|
|
||||||
size={'default'}
|
|
||||||
style={{ margin: '2px' }}
|
|
||||||
>
|
|
||||||
Unpublish
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BulkActionBar;
|
|
||||||
@ -1,344 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { message, notification, Table } from 'antd';
|
|
||||||
import TimeAgo from 'javascript-time-ago';
|
|
||||||
|
|
||||||
// Load locale-specific relative date/time formatting rules.
|
|
||||||
import en from 'javascript-time-ago/locale/en';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import PolicyAction from './component/PolicyAction';
|
|
||||||
import PolicyBulkActionBar from './component/PolicyBulkActionBar';
|
|
||||||
|
|
||||||
let apiUrl;
|
|
||||||
|
|
||||||
class PoliciesTable extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
TimeAgo.addLocale(en);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
data: [],
|
|
||||||
pagination: {},
|
|
||||||
loading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
rowSelection = {
|
|
||||||
onChange: (selectedRowKeys, selectedRows) => {
|
|
||||||
this.setState({
|
|
||||||
selectedRows: selectedRows,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetchGroups();
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch data from api
|
|
||||||
fetchGroups = (params = {}) => {
|
|
||||||
const config = this.props.context;
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
// get current page
|
|
||||||
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
|
||||||
|
|
||||||
const extraParams = {
|
|
||||||
offset: 10 * (currentPage - 1), // calculate the offset
|
|
||||||
limit: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
const encodedExtraParams = Object.keys(extraParams)
|
|
||||||
.map(key => key + '=' + extraParams[key])
|
|
||||||
.join('&');
|
|
||||||
|
|
||||||
apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
config.serverConfig.invoker.uri +
|
|
||||||
config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies?' +
|
|
||||||
encodedExtraParams;
|
|
||||||
|
|
||||||
// send request to the invokerss
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
const pagination = { ...this.state.pagination };
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
unpublishPolicy = () => {
|
|
||||||
const policyIDs = this.state.selectedRows.map(obj => obj.id);
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.post(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies/deactivate-policy',
|
|
||||||
policyIDs,
|
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetchGroups();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Selected policy(s) was successfully unpublished',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 unpublish policy(s).',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
publishPolicy = () => {
|
|
||||||
const policyIDs = this.state.selectedRows.map(obj => obj.id);
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.post(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies/activate-policy',
|
|
||||||
policyIDs,
|
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetchGroups();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Selected policy(s) was successfully unpublished',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 unpublish policy(s).',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
removePolicy = () => {
|
|
||||||
const policyIDs = this.state.selectedRows.map(obj => obj.id);
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.post(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies/remove-policy',
|
|
||||||
policyIDs,
|
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetchGroups();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Selected policy(s) was successfully removed.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 remove policy(s).',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
applyChanges = () => {
|
|
||||||
// send request to the invoker
|
|
||||||
axios
|
|
||||||
.put(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies/apply-changes',
|
|
||||||
'null',
|
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.fetchGroups();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Changes applied successfully.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 apply changes to device.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { data, pagination, loading, selectedRows } = this.state;
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
title: 'Policy Name',
|
|
||||||
dataIndex: 'policyName',
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Description',
|
|
||||||
dataIndex: 'description',
|
|
||||||
key: 'description',
|
|
||||||
// render: enrolmentInfo => enrolmentInfo.owner
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Compilance',
|
|
||||||
dataIndex: 'compliance',
|
|
||||||
key: 'compliance',
|
|
||||||
// render: enrolmentInfo => enrolmentInfo.ownership
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Policy Type',
|
|
||||||
dataIndex: 'policyType',
|
|
||||||
key: 'policyType',
|
|
||||||
// render: enrolmentInfo => enrolmentInfo.ownership
|
|
||||||
// todo add filtering options
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Action',
|
|
||||||
dataIndex: 'id',
|
|
||||||
key: 'action',
|
|
||||||
render: (id, row) => (
|
|
||||||
<span>
|
|
||||||
<PolicyAction selectedPolicyData={row} />
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PolicyBulkActionBar
|
|
||||||
selectedRows={selectedRows}
|
|
||||||
unpublishPolicy={this.unpublishPolicy}
|
|
||||||
publishPolicy={this.publishPolicy}
|
|
||||||
removePolicy={this.removePolicy}
|
|
||||||
applyChanges={this.applyChanges}
|
|
||||||
/>
|
|
||||||
<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);
|
|
||||||
@ -1,831 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Alert,
|
|
||||||
Button,
|
|
||||||
Checkbox,
|
|
||||||
Col,
|
|
||||||
Collapse,
|
|
||||||
Form,
|
|
||||||
Icon,
|
|
||||||
Input,
|
|
||||||
Popconfirm,
|
|
||||||
Radio,
|
|
||||||
Row,
|
|
||||||
Select,
|
|
||||||
Table,
|
|
||||||
Tabs,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
Upload,
|
|
||||||
} from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
const { Text, Title, Paragraph } = Typography;
|
|
||||||
const { TabPane } = Tabs;
|
|
||||||
const { Option } = Select;
|
|
||||||
const { TextArea } = Input;
|
|
||||||
|
|
||||||
const subPanelpayloadAttributes = {};
|
|
||||||
const fieldKeys = [];
|
|
||||||
let subFormContainer = {};
|
|
||||||
let radioSubPanelSwitches = [];
|
|
||||||
let radioPanelStatusList = {};
|
|
||||||
|
|
||||||
class PolicyInfo extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
data: {},
|
|
||||||
policyFeatureList: [],
|
|
||||||
activePanelKeys: [],
|
|
||||||
activeSubPanelKeys: [],
|
|
||||||
profilePreviewKey: '',
|
|
||||||
customInputDataArray: [],
|
|
||||||
inputTableDataSources: {},
|
|
||||||
isInfoPreview: false,
|
|
||||||
subPanelRadio: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
setProfileInfo = e => {
|
|
||||||
let activePolicies = [];
|
|
||||||
let activePolicyFields = {};
|
|
||||||
let activeSubPanels = [];
|
|
||||||
let subPanelRadio = this.state.subPanelRadio;
|
|
||||||
this.setState({
|
|
||||||
subPanelRadio: radioPanelStatusList,
|
|
||||||
});
|
|
||||||
const allFields = this.props.form.getFieldsValue();
|
|
||||||
this.props.policyFeatureList.map(element => {
|
|
||||||
activePolicies.push(element.featureCode);
|
|
||||||
let featureData = JSON.parse(element.content);
|
|
||||||
Object.keys(featureData).map(key => {
|
|
||||||
if (element.featureCode in subPanelpayloadAttributes) {
|
|
||||||
Object.entries(subPanelpayloadAttributes[element.featureCode]).map(
|
|
||||||
([panelKey, payloadAttr]) => {
|
|
||||||
if (key === payloadAttr) {
|
|
||||||
activeSubPanels.push(`${element.featureCode}-${panelKey}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let regex = new RegExp(`${element.featureCode}.+${key}`, 'g');
|
|
||||||
Object.keys(allFields).map(fieldName => {
|
|
||||||
if (fieldName.match(regex) != null) {
|
|
||||||
activePolicyFields[fieldName] = featureData[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (element.featureCode in subFormContainer) {
|
|
||||||
let regex = new RegExp(`.+${element.featureCode}-${key}`, 'g');
|
|
||||||
Object.keys(allFields).map(fieldName => {
|
|
||||||
if (fieldName.match(regex) != null) {
|
|
||||||
activePolicyFields[fieldName] = featureData[key];
|
|
||||||
if (
|
|
||||||
!activePolicies.includes(
|
|
||||||
fieldName.replace(`-${element.featureCode}-${key}`, ''),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
activePolicies.push(
|
|
||||||
fieldName.replace(`-${element.featureCode}-${key}`, ''),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let regex = new RegExp(`${element.featureCode}.+${key}`, 'g');
|
|
||||||
Object.keys(allFields).map(fieldName => {
|
|
||||||
if (fieldName.match(regex) != null) {
|
|
||||||
activePolicyFields[fieldName] = featureData[key];
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
radioSubPanelSwitches.includes(
|
|
||||||
`${element.featureCode}-${featureData[key]}`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
let subPanelViewStatus = {
|
|
||||||
[featureData[key]]: true,
|
|
||||||
};
|
|
||||||
Object.assign(subPanelRadio, subPanelViewStatus);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.props.form.setFieldsValue(activePolicyFields);
|
|
||||||
this.setState({
|
|
||||||
activePanelKeys: activePolicies,
|
|
||||||
activeSubPanelKeys: activeSubPanels,
|
|
||||||
subPanelRadio,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// convert time from 24h format to 12h format
|
|
||||||
timeConverter = time => {
|
|
||||||
time = time
|
|
||||||
.toString()
|
|
||||||
.match(/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/) || [time];
|
|
||||||
if (time.length > 1) {
|
|
||||||
time = time.slice(1);
|
|
||||||
time[5] = +time[0] < 12 ? ' AM' : ' PM';
|
|
||||||
time[0] = +time[0] % 12 || 12;
|
|
||||||
}
|
|
||||||
return time.join('');
|
|
||||||
};
|
|
||||||
|
|
||||||
// get Option value from start Time, end Time and time difference between 2 values
|
|
||||||
getOptionForTimeSelectors = (startTimeValue, endTimeValue, timeIncrement) => {
|
|
||||||
let timeOptions = [];
|
|
||||||
let time = new Date(
|
|
||||||
moment()
|
|
||||||
.startOf('day')
|
|
||||||
.format('YYYY/MM/DD'),
|
|
||||||
);
|
|
||||||
let tempValue = startTimeValue;
|
|
||||||
time.setMinutes(time.getMinutes() + tempValue);
|
|
||||||
let startOption = (
|
|
||||||
<Option value={String(tempValue)}>
|
|
||||||
{this.timeConverter(
|
|
||||||
`${String(time)
|
|
||||||
.split(' ')[4]
|
|
||||||
.substring(0, 5)}`,
|
|
||||||
)}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
timeOptions.push(startOption);
|
|
||||||
|
|
||||||
while (tempValue !== endTimeValue) {
|
|
||||||
time = new Date(
|
|
||||||
moment()
|
|
||||||
.startOf('day')
|
|
||||||
.format('YYYY/MM/DD'),
|
|
||||||
);
|
|
||||||
tempValue += timeIncrement;
|
|
||||||
if (tempValue > 1440) {
|
|
||||||
tempValue = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
time.setMinutes(time.getMinutes() + tempValue);
|
|
||||||
let option = (
|
|
||||||
<Option value={String(tempValue)}>
|
|
||||||
{this.timeConverter(
|
|
||||||
`${String(time)
|
|
||||||
.split(' ')[4]
|
|
||||||
.substring(0, 5)}`,
|
|
||||||
)}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
timeOptions.push(option);
|
|
||||||
}
|
|
||||||
return timeOptions;
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle items which handle from radio buttons
|
|
||||||
handleRadioPanel = (e, subPanel) => {
|
|
||||||
{
|
|
||||||
subPanel.map((panel, i) => {
|
|
||||||
if (panel.value === e.target.value) {
|
|
||||||
document.getElementById(panel.value).style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById(panel.value).style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle items which handle from select options
|
|
||||||
handleSelectedPanel = (e, subPanel) => {
|
|
||||||
{
|
|
||||||
subPanel.map((panel, i) => {
|
|
||||||
if (panel.id === e) {
|
|
||||||
document.getElementById(panel.id).style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById(panel.id).style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getColumns = ({ getFieldDecorator }, arr) => {
|
|
||||||
const columnArray = [];
|
|
||||||
const actionColumn = [
|
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
dataIndex: 'operation',
|
|
||||||
render: (name, row) => (
|
|
||||||
<Form.Item>
|
|
||||||
<Popconfirm title="Sure to delete?">
|
|
||||||
<a>
|
|
||||||
<Text type="danger">
|
|
||||||
<Icon type="delete" />
|
|
||||||
</Text>
|
|
||||||
</a>
|
|
||||||
</Popconfirm>
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
Object.values(arr).map((columnData, c) => {
|
|
||||||
if (columnData.type === 'input') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {})(
|
|
||||||
<Input
|
|
||||||
type={columnData.others.inputType}
|
|
||||||
placeholder={columnData.others.placeholder}
|
|
||||||
/>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
} else if (columnData.type === 'upload') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {})(
|
|
||||||
<Upload>
|
|
||||||
<Button>
|
|
||||||
<Icon type="upload" /> Choose file
|
|
||||||
</Button>
|
|
||||||
</Upload>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
} else if (columnData.type === 'select') {
|
|
||||||
const column = {
|
|
||||||
title: `${columnData.name}`,
|
|
||||||
dataIndex: `${columnData.key}`,
|
|
||||||
key: `${columnData.key}`,
|
|
||||||
render: (name, row, i) => (
|
|
||||||
<Form.Item>
|
|
||||||
{getFieldDecorator(`${columnData.key}${i}`, {
|
|
||||||
initialValue: columnData.others.initialDataIndex,
|
|
||||||
})(
|
|
||||||
<Select disabled>
|
|
||||||
{columnData.others.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.key}>
|
|
||||||
{option.value}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
columnArray.push(column);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const columns = columnArray.concat(actionColumn);
|
|
||||||
return columns;
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate form items
|
|
||||||
getPanelItems = (panel, panelId) => {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
const subPanelList = {};
|
|
||||||
return panel.map((item, k) => {
|
|
||||||
fieldKeys.push(item.id);
|
|
||||||
switch (item.type) {
|
|
||||||
case 'select':
|
|
||||||
if (item.optional.hasOwnProperty('subPanel')) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: `${item.optional.option[0].name}`,
|
|
||||||
})(
|
|
||||||
<Select
|
|
||||||
onChange={e =>
|
|
||||||
this.handleSelectedPanel(e, item.optional.subPanel)
|
|
||||||
}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
{item.optional.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<div className={'sub-panel-container'}>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
id={panel.id}
|
|
||||||
key={i}
|
|
||||||
style={
|
|
||||||
panel.id === item.optional.initialDataIndex
|
|
||||||
? { display: 'block' }
|
|
||||||
: { display: 'none' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{this.getPanelItems(panel.panelItem)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
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}`, {
|
|
||||||
initialValue: `${item.optional.option[0].name}`,
|
|
||||||
})(
|
|
||||||
<Select disabled>
|
|
||||||
{item.optional.option.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Option key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case 'timeSelector':
|
|
||||||
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}`, {
|
|
||||||
initialValue: item.optional.initialDataIndex,
|
|
||||||
})(
|
|
||||||
<Select disabled>
|
|
||||||
{this.getOptionForTimeSelectors(
|
|
||||||
item.optional.firstOptionValue,
|
|
||||||
item.optional.lastOptionValue,
|
|
||||||
item.optional.valueDifference,
|
|
||||||
)}
|
|
||||||
</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} disabled />)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case 'checkbox':
|
|
||||||
if (item.optional.hasOwnProperty('subPanel')) {
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Collapse
|
|
||||||
bordered={false}
|
|
||||||
activeKey={this.state.activeSubPanelKeys}
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
key={item.id}
|
|
||||||
showArrow={false}
|
|
||||||
style={{ border: 0 }}
|
|
||||||
header={
|
|
||||||
<Form.Item key={k}>
|
|
||||||
{getFieldDecorator(`${item.id}`, {
|
|
||||||
valuePropName: 'checked',
|
|
||||||
initialValue: item.optional.ischecked,
|
|
||||||
})(
|
|
||||||
<Checkbox disabled>
|
|
||||||
<span>
|
|
||||||
{item.label}
|
|
||||||
<Tooltip title={item.tooltip} placement="right">
|
|
||||||
<Icon type="question-circle-o" />
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
</Checkbox>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
subPanelList[panel.others.itemSwitch] =
|
|
||||||
panel.others.itemPayload;
|
|
||||||
if (
|
|
||||||
subPanelpayloadAttributes.hasOwnProperty(panelId)
|
|
||||||
) {
|
|
||||||
Object.assign(
|
|
||||||
subPanelpayloadAttributes[panelId],
|
|
||||||
subPanelList,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
subPanelpayloadAttributes[panelId] = subPanelList;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div key={i}>
|
|
||||||
{this.getPanelItems(panel.panelItem, panelId)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Form.Item key={k}>
|
|
||||||
{getFieldDecorator(`${item.id}`, {
|
|
||||||
valuePropName: 'checked',
|
|
||||||
initialValue: item.optional.ischecked,
|
|
||||||
})(
|
|
||||||
<Checkbox disabled>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: null,
|
|
||||||
})(
|
|
||||||
<TextArea
|
|
||||||
placeholder={item.optional.placeholder}
|
|
||||||
rows={item.optional.row}
|
|
||||||
disabled
|
|
||||||
/>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
case 'radioGroup':
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<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}`, {
|
|
||||||
initialValue: `${item.optional.initialValue}`,
|
|
||||||
})(
|
|
||||||
<Radio.Group
|
|
||||||
onChange={e =>
|
|
||||||
this.handleRadioPanel(e, item.optional.radio)
|
|
||||||
}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
{item.optional.radio.map((option, i) => {
|
|
||||||
return (
|
|
||||||
<Radio key={i} value={option.value}>
|
|
||||||
{option.name}
|
|
||||||
</Radio>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Radio.Group>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<div className={'sub-panel-container'}>
|
|
||||||
{item.optional.subPanel.map((panel, i) => {
|
|
||||||
radioSubPanelSwitches.push(`${panelId}-${panel.id}`);
|
|
||||||
radioPanelStatusList[panel.id] = false;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
id={panel.id}
|
|
||||||
style={
|
|
||||||
this.state.subPanelRadio[panel.id]
|
|
||||||
? { display: 'block' }
|
|
||||||
: { display: 'none' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{this.getPanelItems(panel.panelItem)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
case 'inputTable':
|
|
||||||
if (
|
|
||||||
!(`${item.optional.dataSource}` in this.state.inputTableDataSources)
|
|
||||||
) {
|
|
||||||
Object.defineProperty(
|
|
||||||
this.state.inputTableDataSources,
|
|
||||||
`${item.optional.dataSource}`,
|
|
||||||
{ value: [], writable: true },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Table
|
|
||||||
id={item.id}
|
|
||||||
dataSource={
|
|
||||||
this.state.inputTableDataSources[item.optional.dataSource]
|
|
||||||
}
|
|
||||||
columns={this.getColumns(
|
|
||||||
{ getFieldDecorator },
|
|
||||||
item.optional.columns,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case 'customInputTable':
|
|
||||||
return (
|
|
||||||
<div key={k}>
|
|
||||||
<Table
|
|
||||||
id={item.id}
|
|
||||||
dataSource={this.state.customInputDataArray}
|
|
||||||
columns={this.getColumns(
|
|
||||||
{ getFieldDecorator },
|
|
||||||
item.optional.columns,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onPreview = e => {
|
|
||||||
this.setProfileInfo();
|
|
||||||
this.setState({
|
|
||||||
profilePreviewKey: 'profileInfo',
|
|
||||||
isInfoPreview: true,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onCancelPreview = e => {
|
|
||||||
this.setState({
|
|
||||||
profilePreviewKey: 'profileInfo',
|
|
||||||
isInfoPreview: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { policyUIConfigurationsList } = this.props;
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div style={{ marginTop: 20 }}>
|
|
||||||
<Row>
|
|
||||||
<Col span={4}>
|
|
||||||
<Title level={4}>Profile Information</Title>
|
|
||||||
</Col>
|
|
||||||
<Col span={16}>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
icon="eye"
|
|
||||||
onClick={this.onPreview}
|
|
||||||
style={{ display: this.state.isInfoPreview ? 'none' : 'inline' }}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: 'small',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
(Click to view policy information)
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
icon="eye-invisible"
|
|
||||||
onClick={this.onCancelPreview}
|
|
||||||
style={{ display: this.state.isInfoPreview ? 'inline' : 'none' }}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Collapse
|
|
||||||
bordered={false}
|
|
||||||
activeKey={this.state.profilePreviewKey}
|
|
||||||
style={{ display: this.state.isInfoPreview ? 'block' : 'none' }}
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
key={'profileInfo'}
|
|
||||||
showArrow={false}
|
|
||||||
style={{
|
|
||||||
border: 0,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="tab-container">
|
|
||||||
<Tabs tabPosition={'left'} size={'large'}>
|
|
||||||
{policyUIConfigurationsList.map((element, i) => {
|
|
||||||
return (
|
|
||||||
<TabPane tab={<span>{element.name}</span>} key={i}>
|
|
||||||
{Object.values(element.panels).map((panel, j) => {
|
|
||||||
panel = panel.panel;
|
|
||||||
return (
|
|
||||||
<div key={j}>
|
|
||||||
<Collapse
|
|
||||||
bordered={false}
|
|
||||||
activeKey={this.state.activePanelKeys}
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
key={panel.panelId}
|
|
||||||
showArrow={false}
|
|
||||||
style={{ border: 0 }}
|
|
||||||
header={
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col offset={0} span={14}>
|
|
||||||
<Title level={4}> {panel.title} </Title>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>{panel.description}</Row>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{panel.hasOwnProperty('panelItem') && (
|
|
||||||
<div>
|
|
||||||
<Form name={panel.panelId}>
|
|
||||||
<Form.Item style={{ display: 'none' }}>
|
|
||||||
{getFieldDecorator(`${panel.panelId}`, {
|
|
||||||
initialValue: ' ',
|
|
||||||
})(<Input />)}
|
|
||||||
</Form.Item>
|
|
||||||
{this.getPanelItems(
|
|
||||||
panel.panelItem,
|
|
||||||
panel.panelId,
|
|
||||||
)}
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{panel.hasOwnProperty('subFormLists') && (
|
|
||||||
<div>
|
|
||||||
{Object.values(panel.subFormLists).map(
|
|
||||||
(form, i) => {
|
|
||||||
subFormContainer[`${form.id}`] =
|
|
||||||
panel.panelId;
|
|
||||||
return (
|
|
||||||
<Form name={form.id} key={i}>
|
|
||||||
<Form.Item
|
|
||||||
style={{ display: 'none' }}
|
|
||||||
>
|
|
||||||
{getFieldDecorator(`${form.id}`, {
|
|
||||||
initialValue: ' ',
|
|
||||||
})(<Input />)}
|
|
||||||
</Form.Item>
|
|
||||||
{this.getPanelItems(form.panelItem)}
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TabPane>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create()(PolicyInfo));
|
|
||||||
@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Card, Col, Icon, Row, Typography } from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
const { Title, Text } = Typography;
|
|
||||||
|
|
||||||
class ProfileOverview extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
data: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { policyData } = this.props;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div style={{ marginTop: 20 }}>
|
|
||||||
<div>
|
|
||||||
<Title level={4}>Policy Overview</Title>
|
|
||||||
</div>
|
|
||||||
<Card>
|
|
||||||
<div style={{ paddingLeft: 4 }}>
|
|
||||||
<Row style={{ marginTop: 8 }}>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>Platform</Text>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>{policyData.profile.deviceType.toUpperCase()}</Text>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<hr style={{ backgroundColor: 'grey' }} />
|
|
||||||
<Row style={{ marginTop: 15 }}>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>Groups</Text>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>{policyData.deviceGroups}</Text>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<hr />
|
|
||||||
<Row style={{ marginTop: 15 }}>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>Action upon non-compliance</Text>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>{policyData.compliance.toUpperCase()}</Text>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<hr />
|
|
||||||
<Row style={{ marginTop: 15 }}>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>Status</Text>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>
|
|
||||||
{policyData.active ? (
|
|
||||||
<span>
|
|
||||||
<Icon
|
|
||||||
type="exclamation-circle"
|
|
||||||
style={{ color: '#6ab04c' }}
|
|
||||||
/>
|
|
||||||
Active
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span>
|
|
||||||
<Icon
|
|
||||||
type="exclamation-circle"
|
|
||||||
style={{ color: '#f9ca24' }}
|
|
||||||
/>
|
|
||||||
Inactive
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{policyData.updated ? <span>/Updated</span> : <span></span>}
|
|
||||||
</Text>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<hr />
|
|
||||||
<Row style={{ marginTop: 15 }}>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>Assigned Roles</Text>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>{policyData.roles}</Col>
|
|
||||||
</Row>
|
|
||||||
<hr />
|
|
||||||
<Row style={{ marginTop: 15 }}>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text type={8}>Policy Type</Text>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Text>{policyData.policyType}</Text>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
<div style={{ marginTop: 20 }}>
|
|
||||||
<Title level={4}>Description</Title>
|
|
||||||
<Card>
|
|
||||||
<Row>
|
|
||||||
<Col span={4}>
|
|
||||||
<Text>{policyData.description}</Text>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(ProfileOverview);
|
|
||||||
@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Col, message, notification } from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import PolicyInfo from './component/PolicyInfo';
|
|
||||||
import ProfileOverview from './component/ProfileOverview';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
class PolicyProfile extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
policyId: this.props.policyId,
|
|
||||||
policyData: null,
|
|
||||||
policyUIConfigurationsList: [],
|
|
||||||
policyFeatureList: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.getSelectedPolicy(this.props.policyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedPolicy = policyId => {
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/policies/' +
|
|
||||||
policyId;
|
|
||||||
|
|
||||||
// send request to the invokers
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
policyData: res.data.data,
|
|
||||||
policyFeatureList: res.data.data.profile.profileFeaturesList,
|
|
||||||
});
|
|
||||||
this.getPolicyConfigJson(res.data.data.profile.deviceType);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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 selected policy.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getPolicyConfigJson = type => {
|
|
||||||
this.setState({ isLoading: true });
|
|
||||||
|
|
||||||
let apiUrl =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/device-types/' +
|
|
||||||
type +
|
|
||||||
'/ui-policy-configurations';
|
|
||||||
// send request to the invokers
|
|
||||||
axios
|
|
||||||
.get(apiUrl)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
isLoading: false,
|
|
||||||
policyUIConfigurationsList: JSON.parse(res.data.data),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load Policy details.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setState({ isLoading: false });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
policyData,
|
|
||||||
policyUIConfigurationsList,
|
|
||||||
policyFeatureList,
|
|
||||||
} = this.state;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Col span={16} offset={4}>
|
|
||||||
{/* <Card style={{ marginTop: 24 }}>*/}
|
|
||||||
<div>
|
|
||||||
{policyData != null && (
|
|
||||||
<ProfileOverview
|
|
||||||
policyId={this.props.policyId}
|
|
||||||
policyData={policyData}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{policyData != null && (
|
|
||||||
<PolicyInfo
|
|
||||||
policyId={this.state.policyId}
|
|
||||||
policyFeatureList={policyFeatureList}
|
|
||||||
policyUIConfigurationsList={policyUIConfigurationsList}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(PolicyProfile);
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import PoliciesTable from './components/PoliciesTable';
|
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
|
||||||
|
|
||||||
class Policies extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Policies</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Policies</h3>
|
|
||||||
<Paragraph>All policies for device management</Paragraph>
|
|
||||||
</div>
|
|
||||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
|
||||||
<PoliciesTable />
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Policies;
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import AddPolicy from '../../components/AddPolicy';
|
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
|
||||||
|
|
||||||
class AddNewPolicy extends React.Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Policies</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
<h3>Policies</h3>
|
|
||||||
<Paragraph>Create new policy on IoT Server.</Paragraph>
|
|
||||||
</div>
|
|
||||||
<div style={{ borderRadius: 5 }}>
|
|
||||||
<AddPolicy />
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AddNewPolicy;
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { Breadcrumb, Icon, PageHeader } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import EditPolicy from '../../components/EditPolicy';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
class EditSelectedPolicy extends Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
data: {},
|
|
||||||
policyOverview: {},
|
|
||||||
policyId: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
match: { params },
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Policies</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
{/* <h3>Policies</h3>*/}
|
|
||||||
{/* <Paragraph>Create new policy on IoT Server.</Paragraph>*/}
|
|
||||||
</div>
|
|
||||||
<div style={{ borderRadius: 5 }}>
|
|
||||||
<EditPolicy policyId={params.policyId} />
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default withConfigContext(EditSelectedPolicy);
|
|
||||||
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { Breadcrumb, Icon, PageHeader } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
|
||||||
import PolicyProfile from '../../components/PolicyProfile';
|
|
||||||
class ViewPolicy extends Component {
|
|
||||||
routes;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.routes = props.routes;
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.state = {
|
|
||||||
data: {},
|
|
||||||
policyOverview: {},
|
|
||||||
policyId: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
match: { params },
|
|
||||||
} = this.props;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PageHeader style={{ paddingTop: 0 }}>
|
|
||||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
|
||||||
<Breadcrumb.Item>
|
|
||||||
<Link to="/entgra">
|
|
||||||
<Icon type="home" /> Home
|
|
||||||
</Link>
|
|
||||||
</Breadcrumb.Item>
|
|
||||||
<Breadcrumb.Item>Policies</Breadcrumb.Item>
|
|
||||||
</Breadcrumb>
|
|
||||||
<div className="wrap">
|
|
||||||
{/* <h3>Policies</h3>*/}
|
|
||||||
{/* <Paragraph>Create new policy on IoT Server.</Paragraph>*/}
|
|
||||||
</div>
|
|
||||||
<div style={{ borderRadius: 5 }}>
|
|
||||||
<PolicyProfile policyId={params.policyId} />
|
|
||||||
</div>
|
|
||||||
</PageHeader>
|
|
||||||
<div
|
|
||||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default withConfigContext(ViewPolicy);
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.tab-container > .ant-tabs > .ant-tabs-bar {
|
|
||||||
border-color: #aaaaaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-container > .ant-tabs > .ant-tabs-bar .ant-tabs-tab {
|
|
||||||
height: 50px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-container > .ant-tabs > .ant-tabs-bar .ant-tabs-tab-active {
|
|
||||||
border-color: transparent;
|
|
||||||
background: #4b92db;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
@ -1,410 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
|
|
||||||
* Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
message,
|
|
||||||
Modal,
|
|
||||||
notification,
|
|
||||||
Select,
|
|
||||||
Tree,
|
|
||||||
} from 'antd';
|
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
const { Option } = Select;
|
|
||||||
const { TreeNode } = Tree;
|
|
||||||
|
|
||||||
class AddRole extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.config = this.props.context;
|
|
||||||
this.expandKeys = [];
|
|
||||||
this.state = {
|
|
||||||
isAddRoleModalVisible: false,
|
|
||||||
isAddPermissionModalVisible: false,
|
|
||||||
roleName: '',
|
|
||||||
users: [],
|
|
||||||
nodeList: [],
|
|
||||||
expandedKeys: [],
|
|
||||||
autoExpandParent: true,
|
|
||||||
checkedKeys: [],
|
|
||||||
isNodeList: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
openAddModal = () => {
|
|
||||||
this.setState({
|
|
||||||
isAddRoleModalVisible: true,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onCancelHandler = e => {
|
|
||||||
this.setState({
|
|
||||||
isAddRoleModalVisible: false,
|
|
||||||
isAddPermissionModalVisible: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getCheckedPermissionsList = data => {
|
|
||||||
data.forEach(item => {
|
|
||||||
if (item !== null) {
|
|
||||||
this.expandKeys.push(item.resourcePath);
|
|
||||||
this.getCheckedPermissionsList(item.nodeList);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onAddRole = e => {
|
|
||||||
this.props.form.validateFields((err, values) => {
|
|
||||||
if (!err) {
|
|
||||||
this.onConfirmAddRole(values);
|
|
||||||
}
|
|
||||||
console.log(values);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onExpand = expandedKeys => {
|
|
||||||
this.setState({
|
|
||||||
expandedKeys,
|
|
||||||
autoExpandParent: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onCheck = checkedKeys => {
|
|
||||||
this.setState({ checkedKeys });
|
|
||||||
};
|
|
||||||
|
|
||||||
onConfirmAddRole = value => {
|
|
||||||
const roleData = {
|
|
||||||
roleName: value.roleName,
|
|
||||||
users: value.users,
|
|
||||||
};
|
|
||||||
this.setState({
|
|
||||||
roleName: value.roleName,
|
|
||||||
});
|
|
||||||
axios
|
|
||||||
.post(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/roles',
|
|
||||||
roleData,
|
|
||||||
{ headers: { 'Content-Type': 'application-json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 201) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
this.setState({
|
|
||||||
isAddRoleModalVisible: false,
|
|
||||||
isAddPermissionModalVisible: true,
|
|
||||||
});
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully added the role.',
|
|
||||||
});
|
|
||||||
this.loadPermissionList();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to add role.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
renderTreeNodes = data => {
|
|
||||||
return data.map(item => {
|
|
||||||
if (item !== null) {
|
|
||||||
if (item.hasOwnProperty('nodeList')) {
|
|
||||||
return (
|
|
||||||
<TreeNode
|
|
||||||
title={item.displayName}
|
|
||||||
key={item.resourcePath}
|
|
||||||
dataRef={item}
|
|
||||||
>
|
|
||||||
{this.renderTreeNodes(item.nodeList)}
|
|
||||||
</TreeNode>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <TreeNode key={item.resourcePath} {...item} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line react/jsx-key
|
|
||||||
return <TreeNode />;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onAssignPermissions = () => {
|
|
||||||
const roleData = {
|
|
||||||
roleName: this.state.roleName,
|
|
||||||
permissions: this.state.checkedKeys,
|
|
||||||
};
|
|
||||||
axios
|
|
||||||
.put(
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/roles/' +
|
|
||||||
this.state.roleName,
|
|
||||||
roleData,
|
|
||||||
{ headers: { 'Content-Type': 'application-json' } },
|
|
||||||
)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.props.fetchUsers();
|
|
||||||
notification.success({
|
|
||||||
message: 'Done',
|
|
||||||
duration: 4,
|
|
||||||
description: 'Successfully Updated the Permissions.',
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
isAddPermissionModalVisible: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to add permissions.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
loadPermissionList = () => {
|
|
||||||
let apiURL =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/roles/' +
|
|
||||||
this.state.roleName +
|
|
||||||
'/permissions';
|
|
||||||
|
|
||||||
axios
|
|
||||||
.get(apiURL)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.getCheckedPermissionsList(res.data.data.nodeList);
|
|
||||||
this.setState({
|
|
||||||
nodeList: res.data.data.nodeList,
|
|
||||||
isNodeList: true,
|
|
||||||
expandedKeys: this.expandKeys,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load permission.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
loadUsersList = value => {
|
|
||||||
let apiURL =
|
|
||||||
window.location.origin +
|
|
||||||
this.config.serverConfig.invoker.uri +
|
|
||||||
this.config.serverConfig.invoker.deviceMgt +
|
|
||||||
'/users/search/usernames?filter=' +
|
|
||||||
value +
|
|
||||||
'&domain=Primary';
|
|
||||||
axios
|
|
||||||
.get(apiURL)
|
|
||||||
.then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let user = JSON.parse(res.data.data);
|
|
||||||
let users = [];
|
|
||||||
for (let i = 0; i < user.length; i++) {
|
|
||||||
users.push(
|
|
||||||
<Option key={user[i].username}>{user[i].username}</Option>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
users: users,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
|
||||||
// todo display a popop with error
|
|
||||||
message.error('You are not logged in');
|
|
||||||
window.location.href = window.location.origin + '/entgra/login';
|
|
||||||
} else {
|
|
||||||
notification.error({
|
|
||||||
message: 'There was a problem',
|
|
||||||
duration: 0,
|
|
||||||
description: 'Error occurred while trying to load users.',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { getFieldDecorator } = this.props.form;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon="plus"
|
|
||||||
size={'default'}
|
|
||||||
onClick={this.openAddModal}
|
|
||||||
style={{ marginBottom: '10px' }}
|
|
||||||
>
|
|
||||||
Add Role
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="ADD NEW ROLE"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.isAddRoleModalVisible}
|
|
||||||
onOk={this.onAddRole}
|
|
||||||
onCancel={this.onCancelHandler}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button key="submit" type="primary" onClick={this.onAddRole}>
|
|
||||||
Add Role
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<div style={{ alignItems: 'center' }}>
|
|
||||||
<p>Create new user on IoT Server.</p>
|
|
||||||
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }}>
|
|
||||||
<Form.Item
|
|
||||||
label="User Store Domain"
|
|
||||||
style={{ display: 'block' }}
|
|
||||||
>
|
|
||||||
{getFieldDecorator('userStoreDomain', {
|
|
||||||
initialValue: 'PRIMARY',
|
|
||||||
})(
|
|
||||||
<Select>
|
|
||||||
<Option key="PRIMARY">PRIMARY</Option>
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="Role Name" style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('roleName', {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
pattern: new RegExp('^(((?!(\\@|\\/|\\s)).){3,})*$'),
|
|
||||||
message:
|
|
||||||
'Role name should be in minimum 3 characters long and not ' +
|
|
||||||
'include any whitespaces or @ or /',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'This field is required.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(<Input />)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="User List" style={{ display: 'block' }}>
|
|
||||||
{getFieldDecorator('users', {})(
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
onSearch={this.loadUsersList}
|
|
||||||
>
|
|
||||||
{this.state.users}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Modal
|
|
||||||
title="CHANGE ROLE PERMISSION"
|
|
||||||
width="40%"
|
|
||||||
visible={this.state.isAddPermissionModalVisible}
|
|
||||||
onOk={this.onAssignPermissions}
|
|
||||||
onCancel={this.onCancelHandler}
|
|
||||||
bodyStyle={{
|
|
||||||
overflowY: 'scroll',
|
|
||||||
maxHeight: '500px',
|
|
||||||
marginLeft: '10px',
|
|
||||||
}}
|
|
||||||
footer={[
|
|
||||||
<Button key="cancel" onClick={this.onCancelHandler}>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button
|
|
||||||
key="submit"
|
|
||||||
type="primary"
|
|
||||||
onClick={this.onAssignPermissions}
|
|
||||||
>
|
|
||||||
Assign
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<div style={{ alignItems: 'center' }}>
|
|
||||||
<div>
|
|
||||||
{this.state.isNodeList && (
|
|
||||||
<Tree
|
|
||||||
checkable
|
|
||||||
onExpand={this.onExpand}
|
|
||||||
expandedKeys={this.state.expandedKeys}
|
|
||||||
autoExpandParent={this.state.autoExpandParent}
|
|
||||||
onCheck={this.onCheck}
|
|
||||||
checkedKeys={this.state.checkedKeys}
|
|
||||||
>
|
|
||||||
{this.renderTreeNodes(this.state.nodeList)}
|
|
||||||
</Tree>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withConfigContext(Form.create({ name: 'add-role' })(AddRole));
|
|
||||||