From 04b0356485acd1d40ceea250ea8dc4efcebad1a7 Mon Sep 17 00:00:00 2001 From: Jayasanka Date: Wed, 1 Jan 2020 12:44:02 +0530 Subject: [PATCH 1/4] Add eslint to APPM store --- .../react-app/.eslintrc | 325 ++++++++++++++++++ .../react-app/package.json | 9 + 2 files changed, 334 insertions(+) create mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/.eslintrc diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/.eslintrc b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/.eslintrc new file mode 100644 index 0000000000..9ea2b2a401 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/.eslintrc @@ -0,0 +1,325 @@ +{ + "parser": "babel-eslint", + "plugins": [ + "react", + "babel", + "jsx", + "prettier" + ], + "extends": [ + "eslint:recommended", + "plugin:react/recommended" + ], + "parserOptions": { + "ecmaVersion": 2016, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "settings": { + "react": { + "createClass": "createReactClass", + "pragma": "React", + "version": "16.8.6" + } + }, + "env": { + "node": true, + "commonjs": true, + "browser": true, + "jasmine": true, + "es6": true + }, + "globals": { + "document": true, + "console": true, + // Only for development purposes + "setTimeout": true, + "window" : true + }, + "rules": { + "prettier/prettier": "error", + // Enforce the spacing around the * in generator functions. + "generator-star-spacing": [2, "after"], + // Disallow using variables outside the blocks they are defined (especially + // since only let and const are used, see "no-var"). + "block-scoped-var": 2, + // Require camel case names + "camelcase": 2, + // Allow trailing commas for easy list extension. Having them does not + // impair readability, but also not required either. + "comma-dangle": 0, + // Warn about cyclomatic complexity in functions. + "complexity": 1, + // Don't warn for inconsistent naming when capturing this (not so important + // with auto-binding fat arrow functions). + "consistent-this": 0, + // Enforce curly brace conventions for all control statements. + "curly": 2, + // Don't require a default case in switch statements. Avoid being forced to + // add a bogus default when you know all possible cases are handled. + "default-case": 0, + // Encourage the use of dot notation whenever possible. + "dot-notation": 2, + // Allow mixed 'LF' and 'CRLF' as linebreaks. + "linebreak-style": 0, + // Don't enforce the maximum depth that blocks can be nested. + "max-depth": 0, + // Maximum length of a line. + "max-len": [2, 100, 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 + } +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json index b140135682..2c51b2b550 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json @@ -13,8 +13,10 @@ "acorn": "^6.2.0", "antd": "^3.23.6", "axios": "^0.18.1", + "babel-eslint": "^9.0.0", "d3": "^5.9.7", "dagre": "^0.8.4", + "imagemin": "^5.3.1", "javascript-time-ago": "^2.0.1", "keymirror": "^0.1.1", "lodash.debounce": "^4.0.8", @@ -43,6 +45,12 @@ "body-parser": "^1.19.0", "chai": "^4.1.2", "css-loader": "^0.28.11", + "eslint": "^5.16.0", + "eslint-config-prettier": "4.3.0", + "eslint-plugin-babel": "5.3.0", + "eslint-plugin-jsx": "0.0.2", + "eslint-plugin-prettier": "3.1.0", + "eslint-plugin-react": "7.14.2", "express": "^4.17.1", "express-pino-logger": "^4.0.0", "file-loader": "^2.0.0", @@ -61,6 +69,7 @@ "npm-run-all": "^4.1.5", "pino-colada": "^1.4.5", "postcss-loader": "^3.0.0", + "prettier": "1.18.1", "react": "^16.8.6", "react-dom": "^16.8.6", "react-intl": "^2.9.0", From fae659c32cb86789fd6e371654d36fc25ede4bdb Mon Sep 17 00:00:00 2001 From: Jayasanka Date: Wed, 1 Jan 2020 16:10:17 +0530 Subject: [PATCH 2/4] Add .prettierrc config file to APPM store react app --- .../react-app/.prettierrc | 5 +++++ .../react-app/package.json | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/.prettierrc diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/.prettierrc b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/.prettierrc new file mode 100644 index 0000000000..d281e2bd55 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "parser": "flow" +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json index 2c51b2b550..db8ec651f8 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json @@ -90,6 +90,7 @@ "build_prod": "NODE_ENV=production NODE_OPTIONS=--max_old_space_size=4096 webpack -p --display errors-only --hide-modules", "build_dev": "NODE_ENV=development webpack -d --watch ", "server": "node-env-run server --exec nodemon | pino-colada", - "dev2": "run-p server start" + "dev2": "run-p server start", + "lint": "eslint \"src/**/*.js\"" } } From d4d7089800a9d3824ed7399f01f6d441b5f670e8 Mon Sep 17 00:00:00 2001 From: Jayasanka Date: Wed, 1 Jan 2020 16:47:24 +0530 Subject: [PATCH 3/4] Fix ESLint errors in APPM Store react app --- .../react-app/babel.config.js | 11 +- .../react-app/src/App.js | 247 ++++----- .../src/components/RouteWithSubRoutes.js | 39 +- .../react-app/src/components/apps/AppCard.css | 2 +- .../react-app/src/components/apps/AppCard.js | 105 ++-- .../react-app/src/components/apps/AppList.js | 301 +++++------ .../apps/release/DetailedRating.css | 2 +- .../components/apps/release/DetailedRating.js | 177 ++++--- .../components/apps/release/ReleaseView.js | 491 ++++++++++-------- .../apps/release/SubscriptionDetails.js | 481 +++++++++-------- .../apps/release/images/ImgViewer.js | 79 ++- .../apps/release/install/AppInstallModal.js | 84 +-- .../apps/release/install/AppUninstallModal.js | 93 ++-- .../apps/release/install/DeviceInstall.js | 446 ++++++++-------- .../apps/release/install/DeviceUninstall.js | 436 ++++++++-------- .../apps/release/install/GroupInstall.js | 233 +++++---- .../apps/release/install/GroupUninstall.js | 235 +++++---- .../apps/release/install/RoleInstall.js | 232 +++++---- .../apps/release/install/RoleUninstall.js | 235 +++++---- .../apps/release/install/UserInstall.js | 233 +++++---- .../apps/release/install/UserUninstall.js | 232 +++++---- .../installModalFooter/InstallModalFooter.js | 138 ++--- .../apps/release/review/AddReview.js | 291 ++++++----- .../apps/release/review/CurrentUsersReview.js | 147 +++--- .../apps/release/review/ReviewContainer.js | 235 +++++---- .../apps/release/review/Reviews.css | 2 +- .../components/apps/release/review/Reviews.js | 311 ++++++----- .../review/singleReview/SingleReview.css | 2 +- .../review/singleReview/SingleReview.js | 246 +++++---- .../singleReview/editReview/EditReview.css | 2 +- .../singleReview/editReview/EditReview.js | 317 +++++------ .../react-app/src/context/ConfigContext.js | 18 +- .../react-app/src/index.css | 2 +- .../react-app/src/index.js | 57 +- .../react-app/src/js/Utils.js | 37 +- .../react-app/src/pages/Login.css | 2 +- .../react-app/src/pages/Login.js | 329 ++++++------ .../src/pages/dashboard/Dashboard.css | 2 +- .../src/pages/dashboard/Dashboard.js | 458 ++++++++-------- .../pages/dashboard/add-new-app/AddNewApp.js | 353 ------------- .../pages/dashboard/add-new-app/IconImg.js | 84 --- .../src/pages/dashboard/add-new-app/Step1.js | 170 ------ .../src/pages/dashboard/add-new-app/Step2.js | 29 -- .../src/pages/dashboard/add-new-app/Step3.js | 29 -- .../pages/dashboard/add-new-app/Style.less | 22 - .../add-new-app/UploadScreenshots.js | 67 --- .../add-new-app/components/AddTagModal.js | 67 --- .../src/pages/dashboard/apps/Apps.js | 43 +- .../pages/dashboard/apps/release/Release.js | 219 ++++---- .../src/pages/dashboard/logout/Logout.js | 80 +-- .../react-app/src/serviceWorker.js | 10 +- .../react-app/webpack.config.js | 210 ++++---- 52 files changed, 3995 insertions(+), 4378 deletions(-) delete mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/pages/dashboard/add-new-app/AddNewApp.js delete mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/pages/dashboard/add-new-app/IconImg.js delete mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/pages/dashboard/add-new-app/Step1.js delete mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/pages/dashboard/add-new-app/Step2.js delete mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/pages/dashboard/add-new-app/Step3.js delete mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/pages/dashboard/add-new-app/Style.less delete mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/pages/dashboard/add-new-app/UploadScreenshots.js delete mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/pages/dashboard/add-new-app/components/AddTagModal.js diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/babel.config.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/babel.config.js index 7ec6d0936b..9cfcaf0bd9 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/babel.config.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/babel.config.js @@ -16,14 +16,13 @@ * under the License. */ -module.exports = function (api) { +module.exports = function(api) { api.cache(true); - const presets = [ "@babel/preset-env", - "@babel/preset-react" ]; - const plugins = ["@babel/plugin-proposal-class-properties"]; + const presets = ['@babel/preset-env', '@babel/preset-react']; + const plugins = ['@babel/plugin-proposal-class-properties']; return { presets, - plugins + plugins, }; -}; \ No newline at end of file +}; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/App.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/App.js index fd047221ee..264db3aed8 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/App.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/App.js @@ -16,140 +16,147 @@ * 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} from "antd"; -import ConfigContext from "./context/ConfigContext"; +import React from 'react'; +import 'antd/dist/antd.less'; +import RouteWithSubRoutes from './components/RouteWithSubRoutes'; +import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom'; +import axios from 'axios'; +import { Layout, Spin, Result } from 'antd'; +import ConfigContext from './context/ConfigContext'; -const {Content} = Layout; +const { Content } = Layout; const loadingView = ( - - - - - + + + + + ); const errorView = ( - + ); class App extends React.Component { + constructor(props) { + super(props); + this.state = { + loading: true, + error: false, + config: {}, + }; + } - constructor(props) { - super(props); - this.state = { - loading: true, - error: false, - config: {} + componentDidMount() { + this.updateFavicon(); + axios + .get(window.location.origin + '/store/public/conf/config.json') + .then(res => { + const config = res.data; + this.checkUserLoggedIn(config); + }) + .catch(error => { + this.setState({ + loading: false, + error: true, + }); + }); + } + + updateFavicon = () => { + const link = + document.querySelector("link[rel*='icon']") || + document.createElement('link'); + link.type = 'image/x-icon'; + link.rel = 'shortcut icon'; + link.href = + window.location.origin + + '/devicemgt/public/uuf.unit.favicon/img/favicon.png'; + document.getElementsByTagName('head')[0].appendChild(link); + }; + + checkUserLoggedIn = config => { + axios + .post( + window.location.origin + '/store-ui-request-handler/user', + 'platform=publisher', + ) + .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 + '/store/'; + } else { + this.setState({ + loading: false, + config: config, + }); } - } - - componentDidMount() { - this.updateFavicon(); - axios.get( - window.location.origin + "/store/public/conf/config.json", - ).then(res => { - const config = res.data; - this.checkUserLoggedIn(config); - }).catch((error) => { + }) + .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 + `/store/login?redirect=${redirectUrl}`; + } else { this.setState({ - loading: false, - error: true - }) - }); - } + loading: false, + config: config, + }); + } + } else { + this.setState({ + loading: false, + error: true, + }); + } + }); + }; - updateFavicon = () =>{ - const link = document.querySelector("link[rel*='icon']") || document.createElement('link'); - link.type = 'image/x-icon'; - link.rel = 'shortcut icon'; - link.href = window.location.origin+'/devicemgt/public/uuf.unit.favicon/img/favicon.png'; - document.getElementsByTagName('head')[0].appendChild(link); - }; + render() { + const { loading, error } = this.state; - checkUserLoggedIn = (config) => { - axios.post( - window.location.origin + "/store-ui-request-handler/user", - "platform=publisher" - ).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 + `/store/`; - } else { - this.setState({ - loading: false, - config: 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 + `/store/login?redirect=${redirectUrl}`; - } else { - this.setState({ - loading: false, - config: config - }) - } - } else { - this.setState({ - loading: false, - error: true - }) - } - }); - }; + const applicationView = ( + + +
+ + + {this.props.routes.map(route => ( + + ))} + +
+
+
+ ); - render() { - const {loading, error} = this.state; - - const applicationView = ( - - -
- - - {this.props.routes.map((route) => ( - - ))} - -
-
-
- ); - - return ( -
- {loading && loadingView} - {!loading && !error && applicationView} - {error && errorView} -
- ); - } + return ( +
+ {loading && loadingView} + {!loading && !error && applicationView} + {error && errorView} +
+ ); + } } export default App; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/RouteWithSubRoutes.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/RouteWithSubRoutes.js index f57ec331b0..0f255e852f 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/RouteWithSubRoutes.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/RouteWithSubRoutes.js @@ -17,21 +17,28 @@ */ import React from 'react'; -import {Route} from 'react-router-dom'; -class RouteWithSubRoutes extends React.Component{ - props; - constructor(props){ - super(props); - this.props = props; - } - render() { - return( - ( - - )}/> - ); - } - +import { Route } from 'react-router-dom'; +class RouteWithSubRoutes extends React.Component { + props; + constructor(props) { + super(props); + this.props = props; + } + render() { + return ( + ( + + )} + /> + ); + } } -export default RouteWithSubRoutes; \ No newline at end of file +export default RouteWithSubRoutes; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppCard.css b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppCard.css index e8414a00d0..30256eeebe 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppCard.css +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppCard.css @@ -53,4 +53,4 @@ overflow: hidden; width: 100%; text-overflow: ellipsis; -} \ No newline at end of file +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppCard.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppCard.js index 64d155299f..37ec0504fa 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppCard.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppCard.js @@ -16,63 +16,66 @@ * under the License. */ -import {Card, Typography, Col, Row} from 'antd'; -import React from "react"; -import {Link} from "react-router-dom"; -import "./AppCard.css"; +import { Card, Typography, Col, Row } from 'antd'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import './AppCard.css'; import StarRatings from 'react-star-ratings'; -const {Meta} = Card; -const {Text} = Typography; +const { Meta } = Card; +const { Text } = Typography; class AppCard extends React.Component { + constructor(props) { + super(props); + } - constructor(props) { - super(props); - } + render() { + const app = this.props.app; + const release = this.props.app.applicationReleases[0]; - render() { - const app = this.props.app; - const release = this.props.app.applicationReleases[0]; + const description = ( +
+ + + +
+
+ icon +
+
+ {/* icon*/} + {/* */} + + + + {app.name} + +
+ + {app.type.toLowerCase()} + +
+ + +
+ +
+ ); - const description = ( -
- - - -
-
- icon -
-
- {/*icon*/} - {/**/} - - - {app.name}
- {app.type.toLowerCase()}
- - -
- -
- ); - - return ( - - - - ); - } + return ( + + + + ); + } } -export default AppCard; \ No newline at end of file +export default AppCard; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppList.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppList.js index 7222fe5394..4d3f0fd047 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppList.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/AppList.js @@ -16,163 +16,172 @@ * under the License. */ -import React from "react"; -import AppCard from "./AppCard"; -import {Col, Row, Result} from "antd"; -import axios from "axios"; -import {withConfigContext} from "../../context/ConfigContext"; -import {handleApiError} from "../../js/Utils"; -import InfiniteScroll from "react-infinite-scroller"; +import React from 'react'; +import AppCard from './AppCard'; +import { Col, Row, Result } from 'antd'; +import axios from 'axios'; +import { withConfigContext } from '../../context/ConfigContext'; +import { handleApiError } from '../../js/Utils'; +import InfiniteScroll from 'react-infinite-scroller'; const limit = 30; class AppList extends React.Component { - constructor(props) { - super(props); - this.state = { - apps: [], - loading: true, - hasMore: true, - loadMore: true, - forbiddenErrors: { - apps: false - }, - totalAppCount: 0 - } - } - - componentDidMount() { - const {deviceType} = this.props; - this.props.changeSelectedMenuItem(deviceType); - this.fetchData(0, 30, res => { - this.setState({ - apps: res, - loading: false - }); - }); - } - - - componentDidUpdate(prevProps, prevState) { - if (prevProps.deviceType !== this.props.deviceType) { - const {deviceType} = this.props; - this.props.changeSelectedMenuItem(deviceType); - this.fetchData(0, 30, res => { - this.setState({ - apps: res, - loading: false, - hasMore: true - }); - }); - } - } - - fetchData = (offset, limit, callbackFunction) => { - const {deviceType} = this.props; - const config = this.props.context; - const payload = { - offset, - limit - }; - if (deviceType === "web-clip") { - payload.appType = "WEB_CLIP"; - } else { - payload.deviceType = deviceType; - } - - this.setState({ - loading: true - }); - //send request to the invoker - axios.post( - window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/applications/", - payload, - ).then(res => { - if (res.status === 200) { - //todo remove this property check after backend improvement - let apps = (res.data.data.hasOwnProperty("applications")) ? res.data.data.applications : []; - callbackFunction(apps); - } - - }).catch((error) => { - handleApiError(error, "Error occurred while trying to load apps.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - const {forbiddenErrors} = this.state; - forbiddenErrors.apps = true; - this.setState({ - forbiddenErrors, - loading: false - }) - } else { - this.setState({ - loading: false - }); - } - }); + constructor(props) { + super(props); + this.state = { + apps: [], + loading: true, + hasMore: true, + loadMore: true, + forbiddenErrors: { + apps: false, + }, + totalAppCount: 0, }; + } - handleInfiniteOnLoad = (count) => { - const offset = count * limit; - let apps = this.state.apps; + componentDidMount() { + const { deviceType } = this.props; + this.props.changeSelectedMenuItem(deviceType); + this.fetchData(0, 30, res => { + this.setState({ + apps: res, + loading: false, + }); + }); + } + + componentDidUpdate(prevProps, prevState) { + if (prevProps.deviceType !== this.props.deviceType) { + const { deviceType } = this.props; + this.props.changeSelectedMenuItem(deviceType); + this.fetchData(0, 30, res => { this.setState({ - loading: true, + apps: res, + loading: false, + hasMore: true, }); + }); + } + } - this.fetchData(offset, limit, res => { - if (res.length > 0) { - apps = apps.concat(res); - this.setState({ - apps, - loading: false, - }); - } else { - this.setState({ - hasMore: false, - loading: false - }); - } - }); + fetchData = (offset, limit, callbackFunction) => { + const { deviceType } = this.props; + const config = this.props.context; + const payload = { + offset, + limit, }; + if (deviceType === 'web-clip') { + payload.appType = 'WEB_CLIP'; + } else { + payload.deviceType = deviceType; + } - render() { - const {apps, loading, forbiddenErrors, hasMore} = this.state; - - return ( -
- - - {(forbiddenErrors.apps) && ( - - )} - {!(forbiddenErrors.apps) && apps.length === 0 && ( - - )} - {apps.map(app => ( - - - - ))} - - -
+ this.setState({ + loading: true, + }); + // send request to the invoker + axios + .post( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.store + + '/applications/', + payload, + ) + .then(res => { + if (res.status === 200) { + // todo remove this property check after backend improvement + let apps = res.data.data.hasOwnProperty('applications') + ? res.data.data.applications + : []; + callbackFunction(apps); + } + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load apps.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + const { forbiddenErrors } = this.state; + forbiddenErrors.apps = true; + this.setState({ + forbiddenErrors, + loading: false, + }); + } else { + this.setState({ + loading: false, + }); + } + }); + }; + + handleInfiniteOnLoad = count => { + const offset = count * limit; + let apps = this.state.apps; + this.setState({ + loading: true, + }); + + this.fetchData(offset, limit, res => { + if (res.length > 0) { + apps = apps.concat(res); + this.setState({ + apps, + loading: false, + }); + } else { + this.setState({ + hasMore: false, + loading: false, + }); + } + }); + }; + + render() { + const { apps, loading, forbiddenErrors, hasMore } = this.state; + + return ( +
+ + + {forbiddenErrors.apps && ( + + )} + {!forbiddenErrors.apps && apps.length === 0 && ( + + )} + {apps.map(app => ( + + + + ))} + + +
+ ); + } } -export default withConfigContext(AppList); \ No newline at end of file +export default withConfigContext(AppList); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/DetailedRating.css b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/DetailedRating.css index 28a761eb7b..cfd70c4bdb 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/DetailedRating.css +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/DetailedRating.css @@ -87,4 +87,4 @@ .d-rating .numeric-data .people-count{ padding-top: 6px; -} \ No newline at end of file +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/DetailedRating.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/DetailedRating.js index 2fddb9bf58..3b28f6d1d4 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/DetailedRating.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/DetailedRating.js @@ -16,87 +16,110 @@ * under the License. */ -import React from "react"; -import {Row, Typography, Icon, notification} from "antd"; -import StarRatings from "react-star-ratings"; -import "./DetailedRating.css"; -import axios from "axios"; -import {withConfigContext} from "../../../context/ConfigContext"; -import {handleApiError} from "../../../js/Utils"; +import React from 'react'; +import { Row, Typography, Icon } from 'antd'; +import StarRatings from 'react-star-ratings'; +import './DetailedRating.css'; +import { withConfigContext } from '../../../context/ConfigContext'; const { Text } = Typography; +class DetailedRating extends React.Component { + render() { + const { detailedRating } = this.props; -class DetailedRating extends React.Component{ - - - render() { - const {detailedRating} = this.props; - - if(detailedRating ==null){ - return null; - } - - const totalCount = detailedRating.noOfUsers; - const ratingVariety = detailedRating.ratingVariety; - - const ratingArray = []; - - for (let [key, value] of Object.entries(ratingVariety)) { - ratingArray.push(value); - } - - const maximumRating = Math.max(...ratingArray); - - const ratingBarPercentages = [0,0,0,0,0]; - - if(maximumRating>0){ - for(let i = 0; i<5; i++){ - ratingBarPercentages[i] = (ratingVariety[(i+1).toString()])/maximumRating*100; - } - } - - return ( - -
-
{detailedRating.ratingValue.toFixed(1)}
- -
- {totalCount} total -
-
-
- 5 - -
-
- 4 - -
-
- 3 - -
-
- 2 - -
-
- 1 - -
-
-
- ); + if (detailedRating == null) { + return null; } + + const totalCount = detailedRating.noOfUsers; + const ratingVariety = detailedRating.ratingVariety; + + const ratingArray = []; + + // eslint-disable-next-line no-unused-vars + for (let [key, value] of Object.entries(ratingVariety)) { + ratingArray.push(value); + } + + const maximumRating = Math.max(...ratingArray); + + const ratingBarPercentages = [0, 0, 0, 0, 0]; + + if (maximumRating > 0) { + for (let i = 0; i < 5; i++) { + ratingBarPercentages[i] = + (ratingVariety[(i + 1).toString()] / maximumRating) * 100; + } + } + + return ( + +
+
{detailedRating.ratingValue.toFixed(1)}
+ +
+ + {totalCount} total + +
+
+
+ 5 + + {' '} + +
+
+ 4 + + {' '} + +
+
+ 3 + + {' '} + +
+
+ 2 + + {' '} + +
+
+ 1 + + {' '} + +
+
+
+ ); + } } - -export default withConfigContext(DetailedRating); \ No newline at end of file +export default withConfigContext(DetailedRating); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js index 92b1f1f3c4..8cad68f77a 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js @@ -16,244 +16,279 @@ * under the License. */ -import React from "react"; -import {Divider, Row, Col, Typography, Button, Dropdown, notification, Menu, Icon, Spin, Tabs, Tag} from "antd"; -import "../../../App.css"; -import ImgViewer from "../../apps/release/images/ImgViewer"; -import StarRatings from "react-star-ratings"; -import axios from "axios"; -import pSBC from "shade-blend-color"; -import AppInstallModal from "./install/AppInstallModal"; -import AppUninstallModal from "./install/AppUninstallModal"; -import {withConfigContext} from "../../../context/ConfigContext"; -import {handleApiError} from "../../../js/Utils"; -import ReviewContainer from "./review/ReviewContainer"; -import SubscriptionDetails from "./SubscriptionDetails"; +import React from 'react'; +import { + Divider, + Row, + Col, + Typography, + Button, + Dropdown, + notification, + Menu, + Icon, + Tabs, + Tag, +} from 'antd'; +import '../../../App.css'; +import ImgViewer from '../../apps/release/images/ImgViewer'; +import StarRatings from 'react-star-ratings'; +import axios from 'axios'; +import pSBC from 'shade-blend-color'; +import AppInstallModal from './install/AppInstallModal'; +import AppUninstallModal from './install/AppUninstallModal'; +import { withConfigContext } from '../../../context/ConfigContext'; +import { handleApiError } from '../../../js/Utils'; +import ReviewContainer from './review/ReviewContainer'; +import SubscriptionDetails from './SubscriptionDetails'; -const {Title, Text, Paragraph} = Typography; -const {TabPane} = Tabs; +const { Title, Text, Paragraph } = Typography; +const { TabPane } = Tabs; class ReleaseView extends React.Component { - constructor(props) { - super(props); - this.state = { + constructor(props) { + super(props); + this.state = { + loading: false, + appInstallModalVisible: false, + appUninstallModalVisible: false, + }; + } + + appOperation = (type, payload, operation, timestamp = null) => { + const config = this.props.context; + const release = this.props.app.applicationReleases[0]; + const { uuid } = release; + const { isAndroidEnterpriseApp } = this.props.app; + + this.setState({ + loading: true, + }); + const parameters = {}; + + let url = + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.store + + '/subscription/' + + uuid + + '/' + + type + + '/'; + if (isAndroidEnterpriseApp) { + url += 'ent-app-install/'; // add ent-app-install path param for android enterprise app + parameters.requiresUpdatingExternal = true; + } + url += operation; // add operation to url + if (timestamp != null) { + parameters.timestamp = timestamp; // add timestamp for scheduled operations + } + + const queryParams = Object.keys(parameters) + .map(key => key + '=' + parameters[key]) + .join('&'); + url += '?' + queryParams; + + axios + .post(url, payload, { + headers: { 'X-Platform': config.serverConfig.platform }, + }) + .then(res => { + if (res.status === 200 || res.status === 201) { + this.setState({ loading: false, appInstallModalVisible: false, - appUninstallModalVisible: false + appUninstallModalVisible: false, + }); + notification.success({ + message: 'Done!', + description: 'Operation triggered.', + }); + } else { + this.setState({ + loading: false, + }); + notification.error({ + message: 'There was a problem', + duration: 0, + description: 'Error occurred while ' + operation + 'ing app', + }); } - } - - appOperation = (type, payload, operation, timestamp = null) => { - const config = this.props.context; - const release = this.props.app.applicationReleases[0]; - const {uuid} = release; - const {isAndroidEnterpriseApp} = this.props.app; - - this.setState({ - loading: true, - }); - const parameters = {}; - - let url = window.location.origin + config.serverConfig.invoker.uri + - config.serverConfig.invoker.store + "/subscription/" + uuid + "/" + type + "/"; - if (isAndroidEnterpriseApp) { - url += "ent-app-install/"; // add ent-app-install path param for android enterprise app - parameters.requiresUpdatingExternal = true; - } - url += operation; // add operation to url - if (timestamp != null) { - parameters.timestamp = timestamp; // add timestamp for scheduled operations - } - - const queryParams = Object.keys(parameters).map(key => key + '=' + parameters[key]).join('&'); - url += '?' + queryParams; - - axios.post( - url, - payload, - { - headers: {'X-Platform': config.serverConfig.platform} - } - ).then(res => { - if (res.status === 200 || res.status === 201) { - this.setState({ - loading: false, - appInstallModalVisible: false, - appUninstallModalVisible: false, - }); - notification["success"]({ - message: 'Done!', - description: - 'Operation triggered.', - }); - } else { - this.setState({ - loading: false - }); - notification["error"]({ - message: "There was a problem", - duration: 0, - description: - "Error occurred while " + operation + "ing app", - }); - } - }).catch((error) => { - handleApiError(error, "Error occurred while " + operation + "ing the app."); - }); - }; - - closeAppOperationModal = () => { - this.setState({ - appInstallModalVisible: false, - appUninstallModalVisible: false - }); - }; - - handleSubscribeClick = (e) => { - if (e.key === "install") { - this.setState({ - appInstallModalVisible: true // display app install modal - }) - } else if (e.key === "uninstall") { - this.setState({ - appUninstallModalVisible: true // display app uninstall modal - }) - } - }; - - render() { - const {app, deviceType} = this.props; - const config = this.props.context; - const release = app.applicationReleases[0]; - - let metaData = []; - try { - metaData = JSON.parse(release.metaData); - } catch (e) { - - } - if (app.hasOwnProperty("packageName")) { - metaData.push({ - key: "Package Name", - value: app.packageName - }); - } - const menu = ( - - Install - Uninstall - + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while ' + operation + 'ing the app.', ); + }); + }; - return ( -
- - -
- - - icon - - - {app.name} - Version : {release.version}

- - - -
- - - -
- -
- - - - - - - - - {release.description} - - - CATEGORIES -
- { - app.categories.map(category => { - return ( - - {category} - - ); - }) - } -
- - TAGS -
- { - app.tags.map(tag => { - return ( - - {tag} - - ); - }) - } -
- - META DATA + closeAppOperationModal = () => { + this.setState({ + appInstallModalVisible: false, + appUninstallModalVisible: false, + }); + }; - - { - metaData.map((data, index) => { - return ( - - {data.key}
- {data.value} - - ) - }) - } - {(metaData.length === 0) && (No meta data available.)} -
- - -
- - - -
-
-
- ); + handleSubscribeClick = e => { + if (e.key === 'install') { + this.setState({ + appInstallModalVisible: true, // display app install modal + }); + } else if (e.key === 'uninstall') { + this.setState({ + appUninstallModalVisible: true, // display app uninstall modal + }); } + }; + + render() { + const { app, deviceType } = this.props; + const config = this.props.context; + const release = app.applicationReleases[0]; + + let metaData = []; + try { + metaData = JSON.parse(release.metaData); + // eslint-disable-next-line no-empty + } catch (e) {} + if (app.hasOwnProperty('packageName')) { + metaData.push({ + key: 'Package Name', + value: app.packageName, + }); + } + const menu = ( + + Install + Uninstall + + ); + + return ( +
+ + +
+ + + icon + + + {app.name} + Version : {release.version} +
+
+ + + +
+ + + +
+ +
+ + + + + + + + + {release.description} + + + CATEGORIES +
+ {app.categories.map(category => { + return ( + + {category} + + ); + })} +
+ + TAGS +
+ {app.tags.map(tag => { + return ( + + {tag} + + ); + })} +
+ + META DATA + + + {metaData.map((data, index) => { + return ( + + {data.key} +
+ {data.value} + + ); + })} + {metaData.length === 0 && ( + No meta data available. + )} +
+ + +
+ + + +
+
+
+ ); + } } export default withConfigContext(ReleaseView); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/SubscriptionDetails.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/SubscriptionDetails.js index 9152e9f58b..9fb6f3d91a 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/SubscriptionDetails.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/SubscriptionDetails.js @@ -16,260 +16,257 @@ * under the License. */ -import React from "react"; -import axios from "axios"; -import { - Tag, - message, - notification, - Table, - Typography, - Tooltip, - Icon, - Divider, - Button, - Modal, - Select, - Alert -} from "antd"; -import TimeAgo from 'javascript-time-ago' +import React from 'react'; +import axios from 'axios'; +import { Tag, Table, Typography, Button, Alert } from 'antd'; +import TimeAgo from 'javascript-time-ago'; // Load locale-specific relative date/time formatting rules. -import en from 'javascript-time-ago/locale/en' -import {withConfigContext} from "../../../context/ConfigContext"; -import {handleApiError} from "../../../js/Utils"; +import en from 'javascript-time-ago/locale/en'; +import { withConfigContext } from '../../../context/ConfigContext'; +import { handleApiError } from '../../../js/Utils'; -const {Text} = Typography; - -let config = null; +const { Text } = Typography; const columns = [ - { - title: 'Device', - dataIndex: 'device', - width: 100, - render: device => device.name + { + title: 'Device', + dataIndex: 'device', + width: 100, + render: device => device.name, + }, + { + title: 'Owner', + dataIndex: 'device', + key: 'owner', + render: device => device.enrolmentInfo.owner, + }, + { + title: 'Action Type', + dataIndex: 'actionType', + key: 'actionType', + render: actionType => actionType.toLowerCase(), + }, + { + title: 'Action', + dataIndex: 'action', + key: 'action', + // eslint-disable-next-line react/display-name + render: action => { + action = action.toLowerCase(); + let color = 'fff'; + if (action === 'subscribed') { + color = '#6ab04c'; + } else if (action === 'unsubscribed') { + color = '#f0932b'; + } + return {action}; }, - { - title: 'Owner', - dataIndex: 'device', - key: 'owner', - render: device => device.enrolmentInfo.owner + }, + { + title: 'Triggered By', + dataIndex: 'actionTriggeredBy', + key: 'actionTriggeredBy', + }, + { + title: 'Action Triggered At', + dataIndex: 'actionTriggeredTimestamp', + key: 'actionTriggeredTimestamp', + }, + { + title: 'Action Status', + dataIndex: 'status', + key: 'actionStatus', + // eslint-disable-next-line react/display-name + render: status => { + let color = '#f9ca24'; + switch (status) { + case 'COMPLETED': + color = '#badc58'; + break; + case 'REPEATED': + color = '#6ab04c'; + break; + case 'ERROR': + case 'INVALID': + case 'UNAUTHORIZED': + color = '#ff7979'; + break; + case 'IN_PROGRESS': + color = '#f9ca24'; + break; + case 'PENDING': + color = '#636e72'; + break; + } + return {status.toLowerCase()}; }, - { - title: 'Action Type', - dataIndex: 'actionType', - key: 'actionType', - render: actionType => actionType.toLowerCase() + }, + { + title: 'Device Status', + dataIndex: 'device', + key: 'deviceStatus', + // eslint-disable-next-line react/display-name + render: device => { + const status = device.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 {status}; }, - { - title: 'Action', - dataIndex: 'action', - key: 'action', - render: action => { - action = action.toLowerCase(); - let color = "fff"; - if(action==="subscribed"){ - color = "#6ab04c" - }else if(action === "unsubscribed"){ - color = "#f0932b" - } - return {action} - } - }, - { - title: 'Triggered By', - dataIndex: 'actionTriggeredBy', - key: 'actionTriggeredBy' - }, - { - title: 'Action Triggered At', - dataIndex: 'actionTriggeredTimestamp', - key: 'actionTriggeredTimestamp' - }, - { - title: 'Action Status', - dataIndex: 'status', - key: 'actionStatus', - render: (status) => { - let color = "#f9ca24"; - switch (status) { - case "COMPLETED": - color = "#badc58"; - break; - case "REPEATED": - color = "#6ab04c"; - break; - case "ERROR": - case "INVALID": - case "UNAUTHORIZED": - color = "#ff7979"; - break; - case "IN_PROGRESS": - color = "#f9ca24"; - break; - case "PENDING": - color = "#636e72"; - break; - } - return {status.toLowerCase()}; - } - }, - { - title: 'Device Status', - dataIndex: 'device', - key: 'deviceStatus', - render: (device) => { - const status = device.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 {status}; - } - } + }, ]; -const getTimeAgo = (time) => { - const timeAgo = new TimeAgo('en-US'); - return timeAgo.format(time); -}; - - class SubscriptionDetails extends React.Component { - constructor(props) { - super(props); - config = this.props.context; - TimeAgo.addLocale(en); - this.state = { - data: [], - pagination: {}, + constructor(props) { + super(props); + TimeAgo.addLocale(en); + this.state = { + data: [], + pagination: {}, + loading: false, + selectedRows: [], + deviceGroups: [], + groupModalVisible: false, + selectedGroupId: [], + isForbidden: false, + }; + } + + 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.store + + `/admin/subscription/${this.props.uuid}?` + + encodedExtraParams, + ) + .then(res => { + if (res.status === 200) { + this.setState({ loading: false, - selectedRows: [], - deviceGroups: [], - groupModalVisible: false, - selectedGroupId: [], - isForbidden: false - }; - } - - 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.store + - `/admin/subscription/${this.props.uuid}?` + encodedExtraParams, - ).then(res => { - if (res.status === 200) { - this.setState({ - loading: false, - data: res.data.data - }); - } - - }).catch((error) => { - handleApiError(error, "Something went wrong when trying to load subscription data.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - this.setState({ - loading: false - }); - } - }); - }; - - handleTableChange = (pagination, filters, sorter) => { - const pager = {...this.state.pagination}; - pager.current = pagination.current; - this.setState({ - pagination: pager, - }); - this.fetch({ - results: pagination.pageSize, - page: pagination.current, - sortField: sorter.field, - sortOrder: sorter.order, - ...filters, - }); - }; - - render() { - const {data, pagination, loading, selectedRows} = this.state; - return ( -
- {(this.state.isForbidden) && ( - - )} -
- - The following are the subscription details of the application in each respective device. - -
-
- -
- (record.device.deviceIdentifier + record.device.enrolmentInfo.owner + record.device.enrolmentInfo.ownership)} - dataSource={data.data} - pagination={{ - ...pagination, - size: "small", - // position: "top", - total: data.recordsTotal, - showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices` - // showQuickJumper: true - }} - onChange={this.handleTableChange} - loading={loading} - scroll={{x: 1000}} - /> - + data: res.data.data, + }); + } + }) + .catch(error => { + handleApiError( + error, + 'Something went wrong when trying to load subscription data.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + 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 ( +
+ {this.state.isForbidden && ( + + )} +
+ + The following are the subscription details of the application in + each respective device. + +
+
+ +
+
+ record.device.deviceIdentifier + + record.device.enrolmentInfo.owner + + record.device.enrolmentInfo.ownership + } + dataSource={data.data} + pagination={{ + ...pagination, + size: 'small', + // position: "top", + total: data.recordsTotal, + showTotal: (total, range) => + `showing ${range[0]}-${range[1]} of ${total} devices`, + // showQuickJumper: true + }} + onChange={this.handleTableChange} + loading={loading} + scroll={{ x: 1000 }} + /> + + ); + } } -export default withConfigContext(SubscriptionDetails); \ No newline at end of file +export default withConfigContext(SubscriptionDetails); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/images/ImgViewer.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/images/ImgViewer.js index a0b2dfc491..47edab6623 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/images/ImgViewer.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/images/ImgViewer.js @@ -16,48 +16,47 @@ * under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import RcViewer from 'rc-viewer'; -import {Col} from "antd"; class ImgViewer extends Component { - render() { - const options = { - title: false, - toolbar: { - zoomIn: 0, - zoomOut: 0, - oneToOne: 0, - reset: 0, - prev: 1, - play: { - show: 0 - }, - next: 1, - rotateLeft: 0, - rotateRight: 0, - flipHorizontal: 0, - flipVertical: 0 - }, - rotatable: false, - transition: false, - movable : false - }; - return ( -
- - {this.props.images.map((screenshotUrl, index) => { - return ( -
- screenshot -
- ) - })} -
-
- ); - - } + render() { + const options = { + title: false, + toolbar: { + zoomIn: 0, + zoomOut: 0, + oneToOne: 0, + reset: 0, + prev: 1, + play: { + show: 0, + }, + next: 1, + rotateLeft: 0, + rotateRight: 0, + flipHorizontal: 0, + flipVertical: 0, + }, + rotatable: false, + transition: false, + movable: false, + }; + return ( +
+ {/* eslint-disable-next-line react/no-string-refs */} + + {this.props.images.map((screenshotUrl, index) => { + return ( +
+ screenshot +
+ ); + })} +
+
+ ); + } } -export default ImgViewer; \ No newline at end of file +export default ImgViewer; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppInstallModal.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppInstallModal.js index bd6ae3bd4b..3f3cac0152 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppInstallModal.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppInstallModal.js @@ -16,49 +16,53 @@ * under the License. */ -import React from "react"; -import {Modal, Spin, Tabs} from "antd"; -import UserInstall from "./UserInstall"; -import GroupInstall from "./GroupInstall"; -import RoleInstall from "./RoleInstall"; -import DeviceInstall from "./DeviceInstall"; +import React from 'react'; +import { Modal, Spin, Tabs } from 'antd'; +import UserInstall from './UserInstall'; +import GroupInstall from './GroupInstall'; +import RoleInstall from './RoleInstall'; +import DeviceInstall from './DeviceInstall'; -const {TabPane} = Tabs; +const { TabPane } = Tabs; class AppInstallModal extends React.Component { - state = { - data: [] - }; + state = { + data: [], + }; - render() { - const {deviceType} = this.props; - return ( -
- - - - - - - - - - - - - - - - - - -
- ); - } + render() { + const { deviceType } = this.props; + return ( +
+ + + + + + + + + + + + + + + + + + +
+ ); + } } -export default AppInstallModal; \ No newline at end of file +export default AppInstallModal; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppUninstallModal.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppUninstallModal.js index 6c1f0ce1f1..6b48b7793b 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppUninstallModal.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppUninstallModal.js @@ -15,50 +15,63 @@ * specific language governing permissions and limitations * under the License. */ -import React from "react"; -import {Modal, Spin, Tabs} from "antd"; -import DeviceUninstall from "./DeviceUninstall"; -import UserUninstall from "./UserUninstall"; -import RoleUninstall from "./RoleUninstall"; -import GroupUninstall from "./GroupUninstall"; +import React from 'react'; +import { Modal, Spin, Tabs } from 'antd'; +import DeviceUninstall from './DeviceUninstall'; +import UserUninstall from './UserUninstall'; +import RoleUninstall from './RoleUninstall'; +import GroupUninstall from './GroupUninstall'; -const {TabPane} = Tabs; +const { TabPane } = Tabs; class AppUninstallModal extends React.Component { - state = { - data: [] - }; + state = { + data: [], + }; - render() { - const {deviceType} = this.props; - return ( -
- - - - - - - - - - - - - - - - - - -
- ); - } + render() { + const { deviceType } = this.props; + return ( +
+ + + + + + + + + + + + + + + + + + +
+ ); + } } export default AppUninstallModal; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceInstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceInstall.js index c7e123d843..3bd25828e4 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceInstall.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceInstall.js @@ -16,232 +16,250 @@ * under the License. */ -import React from "react"; -import axios from "axios"; -import {Button, message, DatePicker, Table, Typography, Alert} from "antd"; -import TimeAgo from 'javascript-time-ago' +import React from 'react'; +import axios from 'axios'; +import { Table, Typography, Alert } from 'antd'; +import TimeAgo from 'javascript-time-ago'; // Load locale-specific relative date/time formatting rules. -import en from 'javascript-time-ago/locale/en' -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; -import InstallModalFooter from "./installModalFooter/InstallModalFooter"; +import en from 'javascript-time-ago/locale/en'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; +import InstallModalFooter from './installModalFooter/InstallModalFooter'; -const {Text} = Typography; +const { Text } = Typography; const columns = [ - { - title: 'Device', - dataIndex: 'name', - fixed: 'left', - width: 100, + { + title: 'Device', + dataIndex: 'name', + fixed: 'left', + width: 100, + }, + { + title: 'Modal', + dataIndex: 'deviceInfo', + key: 'modal', + render: deviceInfo => `${deviceInfo.vendor} ${deviceInfo.deviceModel}`, + // todo add filtering options + }, + { + title: 'Owner', + dataIndex: 'enrolmentInfo', + key: 'owner', + render: enrolmentInfo => enrolmentInfo.owner, + // todo add filtering options + }, + { + title: 'Last Updated', + dataIndex: 'deviceInfo', + key: 'updatedTime', + render: data => { + return data.updatedTime; }, - { - title: 'Modal', - dataIndex: 'deviceInfo', - key: 'modal', - render: deviceInfo => `${deviceInfo.vendor} ${deviceInfo.deviceModel}` - // todo add filtering options - }, - { - title: 'Owner', - dataIndex: 'enrolmentInfo', - key: 'owner', - render: enrolmentInfo => enrolmentInfo.owner - // todo add filtering options - }, - { - title: 'Last Updated', - dataIndex: 'deviceInfo', - key: 'updatedTime', - render: (data) => { - return data.updatedTime; + // todo add filtering options + }, + { + title: 'Status', + dataIndex: 'enrolmentInfo', + key: 'status', + render: enrolmentInfo => enrolmentInfo.status, + // todo add filtering options + }, + { + title: 'Ownership', + dataIndex: 'enrolmentInfo', + key: 'ownership', + render: enrolmentInfo => enrolmentInfo.ownership, + // todo add filtering options + }, + { + title: 'OS Version', + dataIndex: 'deviceInfo', + key: 'osVersion', + render: deviceInfo => deviceInfo.osVersion, + // todo add filtering options + }, + { + title: 'IMEI', + dataIndex: 'properties', + key: 'imei', + render: properties => { + let imei = 'not-found'; + for (let i = 0; i < properties.length; i++) { + if (properties[i].name === 'IMEI') { + imei = properties[i].value; } - // todo add filtering options - }, - { - title: 'Status', - dataIndex: 'enrolmentInfo', - key: 'status', - render: enrolmentInfo => enrolmentInfo.status - // todo add filtering options - }, - { - title: 'Ownership', - dataIndex: 'enrolmentInfo', - key: 'ownership', - render: enrolmentInfo => enrolmentInfo.ownership - // todo add filtering options - }, - { - title: 'OS Version', - dataIndex: 'deviceInfo', - key: 'osVersion', - render: deviceInfo => deviceInfo.osVersion - // todo add filtering options - }, - { - title: 'IMEI', - dataIndex: 'properties', - key: 'imei', - render: properties => { - let imei = "not-found"; - for (let i = 0; i < properties.length; i++) { - if (properties[i].name === "IMEI") { - imei = properties[i].value; - } - } - return imei; - } - // todo add filtering options + } + return imei; }, + // todo add filtering options + }, ]; class DeviceInstall extends React.Component { - constructor(props) { - super(props); - TimeAgo.addLocale(en); - this.state = { - data: [], - pagination: {}, + constructor(props) { + super(props); + TimeAgo.addLocale(en); + this.state = { + data: [], + pagination: {}, + loading: false, + selectedRows: [], + scheduledTime: null, + isScheduledInstallVisible: false, + isForbidden: false, + }; + } + + rowSelection = { + onChange: (selectedRowKeys, selectedRows) => { + this.setState({ + selectedRows: selectedRows, + }); + }, + getCheckboxProps: record => ({ + disabled: record.name === 'Disabled User', // Column configuration not to be checked + name: record.name, + }), + }; + + componentDidMount() { + this.fetch(); + } + + // fetch data from api + fetch = (params = {}) => { + const config = this.props.context; + this.setState({ loading: true }); + const { deviceType } = this.props; + // get current page + const currentPage = params.hasOwnProperty('page') ? params.page : 1; + + const extraParams = { + offset: 10 * (currentPage - 1), // calculate the offset + limit: 10, + status: 'ACTIVE', + requireDeviceInfo: true, + }; + + if (deviceType !== 'ANY') { + extraParams.type = deviceType; + } + + // note: encode with '%26' not '&' + const encodedExtraParams = Object.keys(extraParams) + .map(key => key + '=' + extraParams[key]) + .join('&'); + + // send request to the invoker + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + '/devices?' + + encodedExtraParams, + ) + .then(res => { + if (res.status === 200) { + const pagination = { ...this.state.pagination }; + this.setState({ loading: false, - selectedRows: [], - scheduledTime: null, - isScheduledInstallVisible: false, - isForbidden: false - }; - } - - rowSelection = { - onChange: (selectedRowKeys, selectedRows) => { - this.setState({ - selectedRows: selectedRows - }) - }, - getCheckboxProps: record => ({ - disabled: record.name === 'Disabled User', // Column configuration not to be checked - name: record.name, - }), - }; - - componentDidMount() { - this.fetch(); - } - - //fetch data from api - fetch = (params = {}) => { - const config = this.props.context; - this.setState({loading: true}); - const {deviceType} = this.props; - // get current page - const currentPage = (params.hasOwnProperty("page")) ? params.page : 1; - - const extraParams = { - offset: 10 * (currentPage - 1), //calculate the offset - limit: 10, - status: "ACTIVE", - requireDeviceInfo: true, - }; - - if (deviceType !== 'ANY') { - extraParams.type = deviceType; + data: res.data.data, + pagination, + }); } - - // note: encode with '%26' not '&' - 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, - pagination, - }); - } - - }).catch((error) => { - handleApiError(error, "Error occurred while trying to load devices.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - 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, - }); - }; - - install = (timestamp=null) => { - const {selectedRows} = this.state; - const payload = []; - selectedRows.map(device => { - payload.push({ - id: device.deviceIdentifier, - type: device.type - }); - }); - this.props.onInstall("devices", payload, "install",timestamp); - }; - - render() { - const {data, pagination, loading, selectedRows, scheduledTime,isScheduledInstallVisible} = this.state; - return ( -
- - Start installing the application for one or more users by entering the corresponding user name. - Select install to automatically start downloading the application for the respective user/users. - - {(this.state.isForbidden) && ( - - )} -
record.deviceIdentifier} - dataSource={data.devices} - pagination={{ - ...pagination, - size: "small", - // position: "top", - total: data.count, - showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices` - // showQuickJumper: true - }} - loading={loading} - onChange={this.handleTableChange} - rowSelection={this.rowSelection} - scroll={{x: 1000}} - /> - - + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load devices.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + 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, + }); + }; + + install = (timestamp = null) => { + const { selectedRows } = this.state; + const payload = []; + selectedRows.map(device => { + payload.push({ + id: device.deviceIdentifier, + type: device.type, + }); + }); + this.props.onInstall('devices', payload, 'install', timestamp); + }; + + render() { + const { data, pagination, loading, selectedRows } = this.state; + return ( +
+ + Start installing the application for one or more users by entering the + corresponding user name. Select install to automatically start + downloading the application for the respective user/users. + + {this.state.isForbidden && ( + + )} +
record.deviceIdentifier} + dataSource={data.devices} + pagination={{ + ...pagination, + size: 'small', + // position: "top", + total: data.count, + showTotal: (total, range) => + `showing ${range[0]}-${range[1]} of ${total} devices`, + // showQuickJumper: true + }} + loading={loading} + onChange={this.handleTableChange} + rowSelection={this.rowSelection} + scroll={{ x: 1000 }} + /> + + + ); + } } -export default withConfigContext(DeviceInstall); \ No newline at end of file +export default withConfigContext(DeviceInstall); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceUninstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceUninstall.js index 6f4e09e793..6b6c55772c 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceUninstall.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceUninstall.js @@ -16,226 +16,248 @@ * under the License. */ -import React from "react"; -import axios from "axios"; -import {Alert, Button, Select, Table, Typography} from "antd"; -import TimeAgo from 'javascript-time-ago' +import React from 'react'; +import axios from 'axios'; +import { Alert, Table, Typography } from 'antd'; +import TimeAgo from 'javascript-time-ago'; // Load locale-specific relative date/time formatting rules. -import en from 'javascript-time-ago/locale/en' -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; -import InstallModalFooter from "./installModalFooter/InstallModalFooter"; +import en from 'javascript-time-ago/locale/en'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; +import InstallModalFooter from './installModalFooter/InstallModalFooter'; -const {Text} = Typography; +const { Text } = Typography; const columns = [ - { - title: 'Device', - dataIndex: 'name', - fixed: 'left', - width: 100, + { + title: 'Device', + dataIndex: 'name', + fixed: 'left', + width: 100, + }, + { + title: 'Modal', + dataIndex: 'deviceInfo', + key: 'modal', + render: deviceInfo => `${deviceInfo.vendor} ${deviceInfo.deviceModel}`, + // todo add filtering options + }, + { + title: 'Owner', + dataIndex: 'enrolmentInfo', + key: 'owner', + render: enrolmentInfo => enrolmentInfo.owner, + // todo add filtering options + }, + { + title: 'Last Updated', + dataIndex: 'deviceInfo', + key: 'updatedTime', + render: data => { + return data.updatedTime; }, - { - title: 'Modal', - dataIndex: 'deviceInfo', - key: 'modal', - render: deviceInfo => `${deviceInfo.vendor} ${deviceInfo.deviceModel}` - // todo add filtering options - }, - { - title: 'Owner', - dataIndex: 'enrolmentInfo', - key: 'owner', - render: enrolmentInfo => enrolmentInfo.owner - // todo add filtering options - }, - { - title: 'Last Updated', - dataIndex: 'deviceInfo', - key: 'updatedTime', - render: (data) => { - return data.updatedTime; + // todo add filtering options + }, + { + title: 'Status', + dataIndex: 'enrolmentInfo', + key: 'status', + render: enrolmentInfo => enrolmentInfo.status, + // todo add filtering options + }, + { + title: 'Ownership', + dataIndex: 'enrolmentInfo', + key: 'ownership', + render: enrolmentInfo => enrolmentInfo.ownership, + // todo add filtering options + }, + { + title: 'OS Version', + dataIndex: 'deviceInfo', + key: 'osVersion', + render: deviceInfo => deviceInfo.osVersion, + // todo add filtering options + }, + { + title: 'IMEI', + dataIndex: 'properties', + key: 'imei', + render: properties => { + let imei = 'not-found'; + for (let i = 0; i < properties.length; i++) { + if (properties[i].name === 'IMEI') { + imei = properties[i].value; } - // todo add filtering options - }, - { - title: 'Status', - dataIndex: 'enrolmentInfo', - key: 'status', - render: enrolmentInfo => enrolmentInfo.status - // todo add filtering options - }, - { - title: 'Ownership', - dataIndex: 'enrolmentInfo', - key: 'ownership', - render: enrolmentInfo => enrolmentInfo.ownership - // todo add filtering options - }, - { - title: 'OS Version', - dataIndex: 'deviceInfo', - key: 'osVersion', - render: deviceInfo => deviceInfo.osVersion - // todo add filtering options - }, - { - title: 'IMEI', - dataIndex: 'properties', - key: 'imei', - render: properties => { - let imei = "not-found"; - for (let i = 0; i < properties.length; i++) { - if (properties[i].name === "IMEI") { - imei = properties[i].value; - } - } - return imei; - } - // todo add filtering options + } + return imei; }, + // todo add filtering options + }, ]; class DeviceUninstall extends React.Component { - constructor(props) { - super(props); - TimeAgo.addLocale(en); - this.state = { - data: [], - pagination: {}, + constructor(props) { + super(props); + TimeAgo.addLocale(en); + this.state = { + data: [], + pagination: {}, + loading: false, + selectedRows: [], + isForbidden: false, + }; + } + + rowSelection = { + onChange: (selectedRowKeys, selectedRows) => { + this.setState({ + selectedRows: selectedRows, + }); + }, + getCheckboxProps: record => ({ + disabled: record.name === 'Disabled User', // Column configuration not to be checked + name: record.name, + }), + }; + + componentDidMount() { + this.fetch(); + } + + // fetch data from api + fetch = (params = {}) => { + const config = this.props.context; + this.setState({ loading: true }); + const { deviceType } = this.props; + // get current page + const currentPage = params.hasOwnProperty('page') ? params.page : 1; + + const extraParams = { + offset: 10 * (currentPage - 1), // calculate the offset + limit: 10, + status: 'ACTIVE', + }; + + if (deviceType !== 'ANY') { + extraParams.type = deviceType; + } + + // note: encode with '%26' not '&' + const encodedExtraParams = Object.keys(extraParams) + .map(key => key + '=' + extraParams[key]) + .join('&'); + + const uuid = this.props.uuid; + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.store + + '/subscription/' + + uuid + + '/' + + '/devices?' + + encodedExtraParams, + ) + .then(res => { + if (res.status === 200) { + const pagination = { ...this.state.pagination }; + this.setState({ loading: false, - selectedRows: [], - isForbidden: false - }; - } - - rowSelection = { - onChange: (selectedRowKeys, selectedRows) => { - this.setState({ - selectedRows: selectedRows - }) - }, - getCheckboxProps: record => ({ - disabled: record.name === 'Disabled User', // Column configuration not to be checked - name: record.name, - }), - }; - - componentDidMount() { - this.fetch(); - } - - //fetch data from api - fetch = (params = {}) => { - const config = this.props.context; - this.setState({loading: true}); - const {deviceType} = this.props; - // get current page - const currentPage = (params.hasOwnProperty("page")) ? params.page : 1; - - const extraParams = { - offset: 10 * (currentPage - 1), //calculate the offset - limit: 10, - status: "ACTIVE", - }; - - if (deviceType !== 'ANY') { - extraParams.type = deviceType; + data: res.data.data, + pagination, + }); } - - // note: encode with '%26' not '&' - const encodedExtraParams = Object.keys(extraParams).map(key => key + '=' + extraParams[key]).join('&'); - - const uuid = this.props.uuid; - axios.get( - window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/" + - "/devices?" + encodedExtraParams, - ).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.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - 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, - }); - }; - - uninstall = (timestamp = null) => { - const {selectedRows} = this.state; - const payload = []; - selectedRows.map(device => { - payload.push({ - id: device.deviceIdentifier, - type: device.type - }); - }); - this.props.onUninstall("devices", payload, "uninstall", timestamp); - }; - - render() { - const {data, pagination, loading, selectedRows} = this.state; - return ( -
- - Start uninstalling the application for devices by selecting the corresponding devices. - Select uninstall to automatically start uninstalling the application for the respective devices. - - {(this.state.isForbidden) && ( - - )} -
record.deviceIdentifier} - 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} - scroll={{x: 1000}} - /> - - + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load devices.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + 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, + }); + }; + + uninstall = (timestamp = null) => { + const { selectedRows } = this.state; + const payload = []; + selectedRows.map(device => { + payload.push({ + id: device.deviceIdentifier, + type: device.type, + }); + }); + this.props.onUninstall('devices', payload, 'uninstall', timestamp); + }; + + render() { + const { data, pagination, loading, selectedRows } = this.state; + return ( +
+ + Start uninstalling the application for devices by selecting the + corresponding devices. Select uninstall to automatically start + uninstalling the application for the respective devices. + + {this.state.isForbidden && ( + + )} +
record.deviceIdentifier} + 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} + scroll={{ x: 1000 }} + /> + + + ); + } } export default withConfigContext(DeviceUninstall); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupInstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupInstall.js index 7d1d41a048..0ecdcd8b39 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupInstall.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupInstall.js @@ -16,124 +16,139 @@ * under the License. */ -import React from "react"; -import {Typography, Select, Spin, message, notification, Button, Alert} from "antd"; +import React from 'react'; +import { Typography, Select, Spin, Alert } from 'antd'; import debounce from 'lodash.debounce'; -import axios from "axios"; -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; -import InstallModalFooter from "./installModalFooter/InstallModalFooter"; - -const {Text} = Typography; -const {Option} = Select; +import axios from 'axios'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; +import InstallModalFooter from './installModalFooter/InstallModalFooter'; +const { Text } = Typography; +const { Option } = Select; class GroupInstall extends React.Component { + constructor(props) { + super(props); + this.lastFetchId = 0; + this.fetchUser = debounce(this.fetchUser, 800); + } - constructor(props) { - super(props); - this.lastFetchId = 0; - this.fetchUser = debounce(this.fetchUser, 800); - } + state = { + data: [], + value: [], + fetching: false, + isForbidden: false, + }; - state = { - data: [], - value: [], - fetching: false, - isForbidden: false - }; + fetchUser = value => { + this.lastFetchId += 1; + const fetchId = this.lastFetchId; + const config = this.props.context; + this.setState({ data: [], fetching: true }); - fetchUser = value => { - this.lastFetchId += 1; - const fetchId = this.lastFetchId; - const config = this.props.context; - this.setState({data: [], fetching: true}); + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + '/groups?name=' + + value, + ) + .then(res => { + if (res.status === 200) { + if (fetchId !== this.lastFetchId) { + // for fetch callback order + return; + } - axios.get( - window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt+"/groups?name=" + value, + const data = res.data.data.deviceGroups.map(group => ({ + text: group.name, + value: group.name, + })); - ).then(res => { - if (res.status === 200) { - if (fetchId !== this.lastFetchId) { - // for fetch callback order - return; - } - - const data = res.data.data.deviceGroups.map(group => ({ - text: group.name, - value: group.name, - })); - - this.setState({data, fetching: false}); - } - - }).catch((error) => { - handleApiError(error,"Error occurred while trying to load groups.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - this.setState({ - loading: false - }); - } - }); - }; - - handleChange = value => { - this.setState({ - value, - data: [], - fetching: false, - }); - }; - - install = () =>{ - const {value} = this.state; - const data = []; - value.map(val=>{ - data.push(val.key); - }); - this.props.onInstall("group", data, "install"); - }; - - render() { - - const {fetching, data, value} = this.state; - - return ( -
- Start installing the application for one or more groups by entering the corresponding group name. Select install to automatically start downloading the application for the respective device group/ groups. - {(this.state.isForbidden) && ( - - )} -
-
- - -
+ this.setState({ data, fetching: false }); + } + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load groups.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + this.setState({ + loading: false, + }); + } + }); + }; + + handleChange = value => { + this.setState({ + value, + data: [], + fetching: false, + }); + }; + + install = () => { + const { value } = this.state; + const data = []; + value.map(val => { + data.push(val.key); + }); + this.props.onInstall('group', data, 'install'); + }; + + render() { + const { fetching, data, value } = this.state; + + return ( +
+ + Start installing the application for one or more groups by entering + the corresponding group name. Select install to automatically start + downloading the application for the respective device group/ groups. + + {this.state.isForbidden && ( + + )} +
+
+ + +
+ ); + } } -export default withConfigContext(GroupInstall); \ No newline at end of file +export default withConfigContext(GroupInstall); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupUninstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupUninstall.js index b7f998a9d7..6205fc239b 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupUninstall.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupUninstall.js @@ -16,126 +16,143 @@ * under the License. */ -import React from "react"; -import {Typography, Select, Spin, message, notification, Button, Alert} from "antd"; +import React from 'react'; +import { Typography, Select, Spin, Alert } from 'antd'; import debounce from 'lodash.debounce'; -import axios from "axios"; -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; -import InstallModalFooter from "./installModalFooter/InstallModalFooter"; +import axios from 'axios'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; +import InstallModalFooter from './installModalFooter/InstallModalFooter'; -const {Text} = Typography; -const {Option} = Select; +const { Text } = Typography; +const { Option } = Select; class GroupUninstall extends React.Component { + constructor(props) { + super(props); + this.lastFetchId = 0; + this.fetchUser = debounce(this.fetchUser, 800); + } - constructor(props) { - super(props); - this.lastFetchId = 0; - this.fetchUser = debounce(this.fetchUser, 800); - } + state = { + data: [], + value: [], + fetching: false, + isForbidden: false, + }; - state = { - data: [], - value: [], - fetching: false, - isForbidden: false - }; + fetchUser = value => { + this.lastFetchId += 1; + const fetchId = this.lastFetchId; + const config = this.props.context; + this.setState({ data: [], fetching: true }); - fetchUser = value => { - this.lastFetchId += 1; - const fetchId = this.lastFetchId; - const config = this.props.context; - this.setState({data: [], fetching: true}); + const uuid = this.props.uuid; - const uuid = this.props.uuid; + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.store + + '/subscription/' + + uuid + + '/' + + '/GROUP?', + ) + .then(res => { + if (res.status === 200) { + if (fetchId !== this.lastFetchId) { + // for fetch callback order + return; + } - axios.get( - window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/" + - "/GROUP?", - ).then(res => { - if (res.status === 200) { - if (fetchId !== this.lastFetchId) { - // for fetch callback order - return; - } + const data = res.data.data.deviceGroups.map(group => ({ + text: group, + value: group, + })); - const data = res.data.data.deviceGroups.map(group => ({ - text: group, - value: group, - })); - - this.setState({data, fetching: false}); - } - - }).catch((error) => { - handleApiError(error, "Error occurred while trying to load groups.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - this.setState({ - loading: false - }); - } - }); - }; - - handleChange = value => { - this.setState({ - value, - data: [], - fetching: false, - }); - }; - - uninstall = (timestamp = null) => { - const {value} = this.state; - const data = []; - value.map(val => { - data.push(val.key); - }); - this.props.onUninstall("group", data, "uninstall", timestamp); - }; - - render() { - - const {fetching, data, value} = this.state; - - return ( -
- Start uninstalling the application for one or more groups by entering the corresponding group - name. Select uninstall to automatically start uninstalling the application for the respective device - group/ groups. - {(this.state.isForbidden) && ( - - )} -
-
- - -
+ this.setState({ data, fetching: false }); + } + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load groups.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + this.setState({ + loading: false, + }); + } + }); + }; + + handleChange = value => { + this.setState({ + value, + data: [], + fetching: false, + }); + }; + + uninstall = (timestamp = null) => { + const { value } = this.state; + const data = []; + value.map(val => { + data.push(val.key); + }); + this.props.onUninstall('group', data, 'uninstall', timestamp); + }; + + render() { + const { fetching, data, value } = this.state; + + return ( +
+ + Start uninstalling the application for one or more groups by entering + the corresponding group name. Select uninstall to automatically start + uninstalling the application for the respective device group/ groups. + + {this.state.isForbidden && ( + + )} +
+
+ + +
+ ); + } } export default withConfigContext(GroupUninstall); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleInstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleInstall.js index 063311953a..63f6bfca77 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleInstall.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleInstall.js @@ -16,123 +16,139 @@ * under the License. */ -import React from "react"; -import {Typography, Select, Spin, message, notification, Button, Alert} from "antd"; +import React from 'react'; +import { Typography, Select, Spin, Alert } from 'antd'; import debounce from 'lodash.debounce'; -import axios from "axios"; -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; -import InstallModalFooter from "./installModalFooter/InstallModalFooter"; - -const {Text} = Typography; -const {Option} = Select; +import axios from 'axios'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; +import InstallModalFooter from './installModalFooter/InstallModalFooter'; +const { Text } = Typography; +const { Option } = Select; class RoleInstall extends React.Component { + constructor(props) { + super(props); + this.lastFetchId = 0; + this.fetchUser = debounce(this.fetchUser, 800); + } - constructor(props) { - super(props); - this.lastFetchId = 0; - this.fetchUser = debounce(this.fetchUser, 800); - } + state = { + data: [], + value: [], + fetching: false, + isForbidden: false, + }; - state = { - data: [], - value: [], - fetching: false, - isForbidden: false - }; + fetchUser = value => { + const config = this.props.context; + this.lastFetchId += 1; + const fetchId = this.lastFetchId; + this.setState({ data: [], fetching: true }); - fetchUser = value => { - const config = this.props.context; - this.lastFetchId += 1; - const fetchId = this.lastFetchId; - this.setState({data: [], fetching: true}); + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + '/roles?filter=' + + value, + ) + .then(res => { + if (res.status === 200) { + if (fetchId !== this.lastFetchId) { + // for fetch callback order + return; + } - axios.get( - window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt+"/roles?filter=" + value, + const data = res.data.data.roles.map(role => ({ + text: role, + value: role, + })); - ).then(res => { - if (res.status === 200) { - if (fetchId !== this.lastFetchId) { - // for fetch callback order - return; - } - - const data = res.data.data.roles.map(role => ({ - text: role, - value: role, - })); - - this.setState({data, fetching: false}); - } - - }).catch((error) => { - handleApiError(error,"Error occurred while trying to load roles.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - this.setState({ - loading: false - }); - } - }); - }; - - handleChange = value => { - this.setState({ - value, - data: [], - fetching: false, - }); - }; - - install = (timestamp=null) =>{ - const {value} = this.state; - const data = []; - value.map(val=>{ - data.push(val.key); - }); - this.props.onInstall("role", data, "install", timestamp); - }; - - render() { - - const {fetching, data, value} = this.state; - - return ( -
- Start installing the application for one or more roles by entering the corresponding role name. Select install to automatically start downloading the application for the respective user role/roles. - {(this.state.isForbidden) && ( - - )} -
-
- - -
+ this.setState({ data, fetching: false }); + } + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load roles.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + this.setState({ + loading: false, + }); + } + }); + }; + + handleChange = value => { + this.setState({ + value, + data: [], + fetching: false, + }); + }; + + install = (timestamp = null) => { + const { value } = this.state; + const data = []; + value.map(val => { + data.push(val.key); + }); + this.props.onInstall('role', data, 'install', timestamp); + }; + + render() { + const { fetching, data, value } = this.state; + + return ( +
+ + Start installing the application for one or more roles by entering the + corresponding role name. Select install to automatically start + downloading the application for the respective user role/roles. + + {this.state.isForbidden && ( + + )} +
+
+ + +
+ ); + } } -export default withConfigContext(RoleInstall); \ No newline at end of file +export default withConfigContext(RoleInstall); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleUninstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleUninstall.js index 0076e80b70..622cbe787a 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleUninstall.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleUninstall.js @@ -16,126 +16,143 @@ * under the License. */ -import React from "react"; -import {Typography, Select, Spin, message, notification, Button, Alert} from "antd"; +import React from 'react'; +import { Typography, Select, Spin, Alert } from 'antd'; import debounce from 'lodash.debounce'; -import axios from "axios"; -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; -import InstallModalFooter from "./installModalFooter/InstallModalFooter"; +import axios from 'axios'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; +import InstallModalFooter from './installModalFooter/InstallModalFooter'; -const {Text} = Typography; -const {Option} = Select; +const { Text } = Typography; +const { Option } = Select; class RoleUninstall extends React.Component { + constructor(props) { + super(props); + this.lastFetchId = 0; + this.fetchUser = debounce(this.fetchUser, 800); + } - constructor(props) { - super(props); - this.lastFetchId = 0; - this.fetchUser = debounce(this.fetchUser, 800); - } + state = { + data: [], + value: [], + fetching: false, + isForbidden: false, + }; - state = { - data: [], - value: [], - fetching: false, - isForbidden: false - }; + fetchUser = value => { + const config = this.props.context; + this.lastFetchId += 1; + const fetchId = this.lastFetchId; + this.setState({ data: [], fetching: true }); - fetchUser = value => { - const config = this.props.context; - this.lastFetchId += 1; - const fetchId = this.lastFetchId; - this.setState({data: [], fetching: true}); + const uuid = this.props.uuid; - const uuid = this.props.uuid; + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.store + + '/subscription/' + + uuid + + '/' + + '/ROLE?', + ) + .then(res => { + if (res.status === 200) { + if (fetchId !== this.lastFetchId) { + // for fetch callback order + return; + } - axios.get( - window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/" + - "/ROLE?", - ).then(res => { - if (res.status === 200) { - if (fetchId !== this.lastFetchId) { - // for fetch callback order - return; - } + const data = res.data.data.roles.map(role => ({ + text: role, + value: role, + })); - const data = res.data.data.roles.map(role => ({ - text: role, - value: role, - })); - - this.setState({data, fetching: false}); - } - - }).catch((error) => { - handleApiError(error, "Error occurred while trying to load roles.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - this.setState({ - loading: false - }); - } - }); - }; - - handleChange = value => { - this.setState({ - value, - data: [], - fetching: false, - }); - }; - - uninstall = (timestamp = null) => { - const {value} = this.state; - const data = []; - value.map(val => { - data.push(val.key); - }); - this.props.onUninstall("role", data, "uninstall", timestamp); - }; - - render() { - const {fetching, data, value} = this.state; - - return ( -
- Start uninstalling the application for one or more roles by entering the corresponding role name. - Select uninstall to automatically start uninstalling the application for the respective user - role/roles. - {(this.state.isForbidden) && ( - - )} -
-
- - -
+ this.setState({ data, fetching: false }); + } + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load roles.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + this.setState({ + loading: false, + }); + } + }); + }; + + handleChange = value => { + this.setState({ + value, + data: [], + fetching: false, + }); + }; + + uninstall = (timestamp = null) => { + const { value } = this.state; + const data = []; + value.map(val => { + data.push(val.key); + }); + this.props.onUninstall('role', data, 'uninstall', timestamp); + }; + + render() { + const { fetching, data, value } = this.state; + + return ( +
+ + Start uninstalling the application for one or more roles by entering + the corresponding role name. Select uninstall to automatically start + uninstalling the application for the respective user role/roles. + + {this.state.isForbidden && ( + + )} +
+
+ + +
+ ); + } } export default withConfigContext(RoleUninstall); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserInstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserInstall.js index ddac89bcab..9c54d05f56 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserInstall.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserInstall.js @@ -16,124 +16,139 @@ * under the License. */ -import React from "react"; -import {Typography, Select, Spin, message, notification, Button, Alert} from "antd"; +import React from 'react'; +import { Typography, Select, Spin, Alert } from 'antd'; import debounce from 'lodash.debounce'; -import axios from "axios"; -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; -import InstallModalFooter from "./installModalFooter/InstallModalFooter"; - -const {Text} = Typography; -const {Option} = Select; +import axios from 'axios'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; +import InstallModalFooter from './installModalFooter/InstallModalFooter'; +const { Text } = Typography; +const { Option } = Select; class UserInstall extends React.Component { + constructor(props) { + super(props); + this.lastFetchId = 0; + this.fetchUser = debounce(this.fetchUser, 800); + } - constructor(props) { - super(props); - this.lastFetchId = 0; - this.fetchUser = debounce(this.fetchUser, 800); - } + state = { + data: [], + value: [], + fetching: false, + }; - state = { - data: [], - value: [], - fetching: false, - }; + fetchUser = value => { + const config = this.props.context; + this.lastFetchId += 1; + const fetchId = this.lastFetchId; + this.setState({ data: [], fetching: true }); - fetchUser = value => { - const config = this.props.context; - this.lastFetchId += 1; - const fetchId = this.lastFetchId; - this.setState({data: [], fetching: true}); + // send request to the invoker + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + '/users/search?username=' + + value, + ) + .then(res => { + if (res.status === 200) { + if (fetchId !== this.lastFetchId) { + // for fetch callback order + return; + } + const data = res.data.data.users.map(user => ({ + text: user.username, + value: user.username, + })); - //send request to the invoker - axios.get( - window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt+"/users/search?username=" + value, - - ).then(res => { - if (res.status === 200) { - if (fetchId !== this.lastFetchId) { - // for fetch callback order - return; - } - - const data = res.data.data.users.map(user => ({ - text: user.username, - value: user.username, - })); - - this.setState({data, fetching: false}); - } - - }).catch((error) => { - handleApiError(error,"Error occurred while trying to load users.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - this.setState({ - loading: false - }); - } - }); - }; - - handleChange = value => { - this.setState({ - value, - data: [], - fetching: false, - isForbidden: false - }); - }; - - install = (timestamp=null) => { - const {value} = this.state; - const data = []; - value.map(val => { - data.push(val.key); - }); - this.props.onInstall("user", data, "install",timestamp); - }; - - render() { - const {fetching, data, value} = this.state; - - return ( -
- Start installing the application for one or more users by entering the corresponding user name. Select install to automatically start downloading the application for the respective user/users. - {(this.state.isForbidden) && ( - - )} -

Select users

- - -
+ this.setState({ data, fetching: false }); + } + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load users.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + this.setState({ + loading: false, + }); + } + }); + }; + + handleChange = value => { + this.setState({ + value, + data: [], + fetching: false, + isForbidden: false, + }); + }; + + install = (timestamp = null) => { + const { value } = this.state; + const data = []; + value.map(val => { + data.push(val.key); + }); + this.props.onInstall('user', data, 'install', timestamp); + }; + + render() { + const { fetching, data, value } = this.state; + + return ( +
+ + Start installing the application for one or more users by entering the + corresponding user name. Select install to automatically start + downloading the application for the respective user/users.{' '} + + {this.state.isForbidden && ( + + )} +

Select users

+ + +
+ ); + } } -export default withConfigContext(UserInstall); \ No newline at end of file +export default withConfigContext(UserInstall); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserUninstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserUninstall.js index 935d2f47a0..4b7f824cbc 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserUninstall.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserUninstall.js @@ -16,123 +16,141 @@ * under the License. */ -import React from "react"; -import {Typography, Select, Spin, message, notification, Button, Alert} from "antd"; +import React from 'react'; +import { Typography, Select, Spin, Alert } from 'antd'; import debounce from 'lodash.debounce'; -import axios from "axios"; -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; -import InstallModalFooter from "./installModalFooter/InstallModalFooter"; +import axios from 'axios'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; +import InstallModalFooter from './installModalFooter/InstallModalFooter'; -const {Text} = Typography; -const {Option} = Select; +const { Text } = Typography; +const { Option } = Select; class UserUninstall extends React.Component { + constructor(props) { + super(props); + this.lastFetchId = 0; + this.fetchUser = debounce(this.fetchUser, 800); + } - constructor(props) { - super(props); - this.lastFetchId = 0; - this.fetchUser = debounce(this.fetchUser, 800); - } + state = { + data: [], + value: [], + fetching: false, + isForbidden: false, + }; - state = { - data: [], - value: [], - fetching: false, - isForbidden: false - }; + fetchUser = value => { + const config = this.props.context; + this.lastFetchId += 1; + const fetchId = this.lastFetchId; + this.setState({ data: [], fetching: true }); - fetchUser = (value) => { - const config = this.props.context; - this.lastFetchId += 1; - const fetchId = this.lastFetchId; - this.setState({data: [], fetching: true}); + const uuid = this.props.uuid; - const uuid = this.props.uuid; + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.store + + '/subscription/' + + uuid + + '/' + + '/USER?', + ) + .then(res => { + if (res.status === 200) { + if (fetchId !== this.lastFetchId) { + // for fetch callback order + return; + } + const data = res.data.data.users.map(user => ({ + text: user, + value: user, + })); - axios.get( - window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/" + - "/USER?", - ).then(res => { - if (res.status === 200) { - if (fetchId !== this.lastFetchId) { - // for fetch callback order - return; - } - const data = res.data.data.users.map(user => ({ - text: user, - value: user, - })); - - this.setState({data, fetching: false}); - } - - }).catch((error) => { - handleApiError(error, "Error occurred while trying to load users.", true); - if (error.hasOwnProperty("response") && error.response.status === 403) { - this.setState({ - isForbidden: true, - loading: false - }) - } else { - this.setState({ - loading: false - }); - } - }); - }; - - handleChange = value => { - this.setState({ - value, - data: [], - fetching: false, - }); - }; - - uninstall = (timestamp=null) => { - const {value} = this.state; - const data = []; - value.map(val => { - data.push(val.key); - }); - this.props.onUninstall("user", data, "uninstall",timestamp); - }; - - render() { - const {fetching, data, value} = this.state; - - return ( -
- Start uninstalling the application for one or more users by entering the corresponding user name. - Select uninstall to automatically start uninstalling the application for the respective - user/users. - {(this.state.isForbidden) && ( - - )} -

Select users

- - -
+ this.setState({ data, fetching: false }); + } + }) + .catch(error => { + handleApiError( + error, + 'Error occurred while trying to load users.', + true, ); - } + if (error.hasOwnProperty('response') && error.response.status === 403) { + this.setState({ + isForbidden: true, + loading: false, + }); + } else { + this.setState({ + loading: false, + }); + } + }); + }; + + handleChange = value => { + this.setState({ + value, + data: [], + fetching: false, + }); + }; + + uninstall = (timestamp = null) => { + const { value } = this.state; + const data = []; + value.map(val => { + data.push(val.key); + }); + this.props.onUninstall('user', data, 'uninstall', timestamp); + }; + + render() { + const { fetching, data, value } = this.state; + + return ( +
+ + Start uninstalling the application for one or more users by entering + the corresponding user name. Select uninstall to automatically start + uninstalling the application for the respective user/users.{' '} + + {this.state.isForbidden && ( + + )} +

Select users

+ + +
+ ); + } } export default withConfigContext(UserUninstall); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/installModalFooter/InstallModalFooter.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/installModalFooter/InstallModalFooter.js index 056ba57802..409c27557a 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/installModalFooter/InstallModalFooter.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/installModalFooter/InstallModalFooter.js @@ -16,72 +16,84 @@ * under the License. */ -import React from "react"; -import {Button, DatePicker, Checkbox} from "antd"; +import React from 'react'; +import { Button, DatePicker, Checkbox } from 'antd'; class InstallModalFooter extends React.Component { - constructor(props) { - super(props); - this.state = { - scheduledTime: null, - isScheduledInstallVisible: false - } + constructor(props) { + super(props); + this.state = { + scheduledTime: null, + isScheduledInstallVisible: false, + }; + } + + onDateTimeChange = (value, dateString) => { + this.setState({ + scheduledTime: dateString, + }); + }; + + toggleScheduledInstall = () => { + this.setState({ + isScheduledInstallVisible: !this.state.isScheduledInstallVisible, + }); + }; + + triggerInstallOperation = () => { + const { scheduledTime, isScheduledInstallVisible } = this.state; + if (isScheduledInstallVisible && scheduledTime != null) { + this.props.operation(scheduledTime); + } else { + this.props.operation(); } + }; - onDateTimeChange = (value, dateString) => { - this.setState({ - scheduledTime: dateString - }); - }; - - toggleScheduledInstall = () => { - this.setState({ - isScheduledInstallVisible: !this.state.isScheduledInstallVisible - }) - }; - - triggerInstallOperation = () => { - const {scheduledTime, isScheduledInstallVisible} = this.state; - if (isScheduledInstallVisible && scheduledTime != null) { - this.props.operation(scheduledTime); - } else { - this.props.operation(); - } - }; - - render() { - const {scheduledTime, isScheduledInstallVisible} = this.state; - const {disabled, type} = this.props; - return ( -
-
-
- - Schedule {type} - -
- - - - -
- -
- ); - } + render() { + const { scheduledTime, isScheduledInstallVisible } = this.state; + const { disabled, type } = this.props; + return ( +
+
+
+ + Schedule {type} + +
+ + + + +
+
+ ); + } } -export default InstallModalFooter; \ No newline at end of file +export default InstallModalFooter; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/review/AddReview.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/review/AddReview.js index f15c6b812b..4f1c204d72 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/review/AddReview.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/review/AddReview.js @@ -16,155 +16,170 @@ * under the License. */ -import React from "react"; -import {Drawer, Button, Icon, Row, Col, Typography, Divider, Input, Spin, notification} from 'antd'; -import StarRatings from "react-star-ratings"; -import axios from "axios"; -import {withConfigContext} from "../../../../context/ConfigContext"; -import {handleApiError} from "../../../../js/Utils"; +import React from 'react'; +import { + Drawer, + Button, + Icon, + Row, + Col, + Typography, + Divider, + Input, + Spin, + notification, +} from 'antd'; +import StarRatings from 'react-star-ratings'; +import axios from 'axios'; +import { withConfigContext } from '../../../../context/ConfigContext'; +import { handleApiError } from '../../../../js/Utils'; -const {Title} = Typography; -const {TextArea} = Input; +const { Title } = Typography; +const { TextArea } = Input; class AddReview extends React.Component { - state = { - visible: false, - content: '', - rating: 0, - loading: false + state = { + visible: false, + content: '', + rating: 0, + loading: false, + }; + + showDrawer = () => { + this.setState({ + visible: true, + content: '', + rating: 0, + loading: false, + }); + }; + + onClose = () => { + this.setState({ + visible: false, + }); + }; + changeRating = (newRating, name) => { + this.setState({ + rating: newRating, + }); + }; + + onChange = e => { + this.setState({ content: e.target.value }); + }; + + onSubmit = () => { + const config = this.props.context; + const { content, rating } = this.state; + const { uuid } = this.props; + this.setState({ + loading: true, + }); + + const payload = { + content: content, + rating: rating, }; - showDrawer = () => { - this.setState({ - visible: true, - content: '', - rating: 0, - loading: false - }); - }; - - onClose = () => { - this.setState({ + axios + .post( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.store + + '/reviews/' + + uuid, + payload, + ) + .then(res => { + if (res.status === 201) { + this.setState({ + loading: false, visible: false, - - }); - }; - changeRating = (newRating, name) => { + }); + notification.success({ + message: 'Done!', + description: 'Your review has been posted successfully.', + }); + this.props.onUpdateReview(); + } else { + this.setState({ + loading: false, + visible: false, + }); + notification.error({ + message: 'There was a problem', + duration: 0, + description: 'We are unable to add your review right now.', + }); + } + }) + .catch(error => { + handleApiError(error, 'We are unable to add your review right now.'); this.setState({ - rating: newRating + loading: false, + visible: false, }); - }; + }); + }; - onChange = (e) => { - this.setState({content: e.target.value}) - }; + render() { + return ( +
+ - onSubmit = () => { - const config = this.props.context; - const {content, rating} = this.state; - const {uuid} = this.props; - this.setState({ - loading: true - }); - - const payload = { - content: content, - rating: rating - }; - - axios.post( - window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/reviews/" + uuid, - payload, - ).then(res => { - if (res.status === 201) { - this.setState({ - loading: false, - visible: false - }); - notification["success"]({ - message: 'Done!', - description: - 'Your review has been posted successfully.', - }); - this.props.onUpdateReview(); - } else { - this.setState({ - loading: false, - visible: false - }); - notification["error"]({ - message: "There was a problem", - duration: 0, - description: - "We are unable to add your review right now.", - }); - } - - }).catch((error) => { - handleApiError(error,"We are unable to add your review right now."); - this.setState({ - loading: false, - visible: false - }); - }); - - - }; - - render() { - return ( -
-
+ + Add review + +