asab_webui_shell 25.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +218 -0
  2. package/LICENSE +28 -0
  3. package/README.md +3 -0
  4. package/dist/actions.js +22 -0
  5. package/dist/components/branding/BrandImage.js +72 -0
  6. package/dist/components/locationReplace.js +51 -0
  7. package/dist/config/ConfigReducer.js +22 -0
  8. package/dist/config/ConfigService.js +169 -0
  9. package/dist/containers/AdvancedMode/reducer.js +28 -0
  10. package/dist/containers/Alerts/alerts.scss +9 -0
  11. package/dist/containers/Alerts/index.js +81 -0
  12. package/dist/containers/Alerts/reducer.js +68 -0
  13. package/dist/containers/Application.js +773 -0
  14. package/dist/containers/Application.scss +104 -0
  15. package/dist/containers/AttentionRequired/reducer.js +30 -0
  16. package/dist/containers/FullscreenMode/reducer.js +28 -0
  17. package/dist/containers/Header/ApplicationScreenTitle/ApplicationScreenTitle.js +47 -0
  18. package/dist/containers/Header/ApplicationScreenTitle/ApplicationScreenTitle.scss +8 -0
  19. package/dist/containers/Header/ApplicationScreenTitle/index.js +31 -0
  20. package/dist/containers/Header/Help/HelpButton.js +58 -0
  21. package/dist/containers/Header/Help/HelpButton.scss +15 -0
  22. package/dist/containers/Header/Help/HelpService.js +34 -0
  23. package/dist/containers/Header/Preview/PreviewFlag.js +34 -0
  24. package/dist/containers/Header/Preview/PreviewService.js +34 -0
  25. package/dist/containers/Header/header.scss +24 -0
  26. package/dist/containers/Header/index.js +39 -0
  27. package/dist/containers/Header/reducer.js +53 -0
  28. package/dist/containers/Navigation/index.js +66 -0
  29. package/dist/containers/Navigation/reducer.js +56 -0
  30. package/dist/containers/RouteErrorHandler/ErrorContainer.js +46 -0
  31. package/dist/containers/RouteErrorHandler/index.js +80 -0
  32. package/dist/containers/Router/ApplicationRouter.js +78 -0
  33. package/dist/containers/Router/index.js +50 -0
  34. package/dist/containers/Router/reducer.js +28 -0
  35. package/dist/containers/Sidebar/NavbarBrand.js +59 -0
  36. package/dist/containers/Sidebar/SidebarBottomItem.js +55 -0
  37. package/dist/containers/Sidebar/SidebarIcon.js +21 -0
  38. package/dist/containers/Sidebar/SidebarItem.js +209 -0
  39. package/dist/containers/Sidebar/SidebarItemRenderer.js +30 -0
  40. package/dist/containers/Sidebar/index.js +86 -0
  41. package/dist/containers/Sidebar/reducer.js +35 -0
  42. package/dist/containers/Sidebar/sidebar.scss +176 -0
  43. package/dist/containers/Sidepanel/Sidepanel.js +60 -0
  44. package/dist/containers/Sidepanel/Sidepanel.scss +20 -0
  45. package/dist/containers/Toast/ToastComponent.js +31 -0
  46. package/dist/containers/Toast/ToastComponent.jsx +28 -0
  47. package/dist/containers/Toast/ToastContainer.js +80 -0
  48. package/dist/containers/Toast/ToastContainer.jsx +59 -0
  49. package/dist/containers/Toast/reducer.js +55 -0
  50. package/dist/containers/Toast/reducer.jsx +45 -0
  51. package/dist/index.js +48 -0
  52. package/dist/modules/about/AboutScreen.js +84 -0
  53. package/dist/modules/about/index.js +41 -0
  54. package/dist/modules/auth/actions.js +11 -0
  55. package/dist/modules/auth/api.js +214 -0
  56. package/dist/modules/auth/components/SessionExpirationAlert.js +35 -0
  57. package/dist/modules/auth/header.js +109 -0
  58. package/dist/modules/auth/header.scss +9 -0
  59. package/dist/modules/auth/index.js +761 -0
  60. package/dist/modules/auth/reducer.js +36 -0
  61. package/dist/modules/auth/screens/AccessControlScreen.js +78 -0
  62. package/dist/modules/auth/screens/InvitationScreen.js +161 -0
  63. package/dist/modules/i18n/actions.js +7 -0
  64. package/dist/modules/i18n/dropdown.js +77 -0
  65. package/dist/modules/i18n/index.js +44 -0
  66. package/dist/modules/i18n/reducer.js +26 -0
  67. package/dist/modules/i18n/service.js +158 -0
  68. package/dist/modules/tenant/TenantDropdown.js +53 -0
  69. package/dist/modules/tenant/access/AccessDeniedCard.js +107 -0
  70. package/dist/modules/tenant/access/AccessDeniedCard.scss +6 -0
  71. package/dist/modules/tenant/actions.js +10 -0
  72. package/dist/modules/tenant/index.js +41 -0
  73. package/dist/modules/tenant/reducer.js +26 -0
  74. package/dist/modules/tenant/service.js +228 -0
  75. package/dist/screens/InvalidRouteScreen.js +30 -0
  76. package/dist/screens/InvalidRouteScreen.scss +19 -0
  77. package/dist/screens/SuspenseScreen.js +43 -0
  78. package/dist/screens/SuspenseScreen.scss +9 -0
  79. package/dist/screens/UnauthorizedAccessScreen.js +79 -0
  80. package/dist/screens/UnauthorizedAccessScreen.scss +19 -0
  81. package/dist/services/AttentionRequiredService.js +169 -0
  82. package/dist/services/BrandingService.js +104 -0
  83. package/dist/services/HeaderService.js +84 -0
  84. package/dist/services/ReduxService.js +25 -0
  85. package/dist/services/TitleService.js +45 -0
  86. package/dist/theme/ThemeButton.js +39 -0
  87. package/dist/theme/ThemeReducer.js +20 -0
  88. package/dist/theme/ThemeService.js +52 -0
  89. package/dist/theme/actions.js +7 -0
  90. package/package.json +41 -0
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { Toast, ToastBody, ToastHeader, Button } from 'reactstrap'
3
+ import { DEL_TOAST } from '../../actions';
4
+ // import { timeToString } from 'asab_webui_components';
5
+
6
+ // Component for displaying Toast messages
7
+ export function ToastComponent({ app, content, dispatch }) {
8
+
9
+ return(
10
+ <Toast
11
+ fade={true}
12
+ className='toast d-print-none'
13
+ >
14
+ <ToastHeader
15
+ toggle={() => dispatch({ type: DEL_TOAST, key: content.key })}
16
+ className='toast-header'
17
+ icon={content?.level ? `${content.level}` : 'secondary'}
18
+ >
19
+ {content?.title ? content.title : ':-('}
20
+ {/*TODO add datetime info (the relative time)*/}
21
+ {/*timeToString(1694691607)?.distanceToNow*/}
22
+ </ToastHeader>
23
+ <ToastBody>
24
+ {content?.message ? content.message : 'Ooops, mistake is on our side. Message has not been defined!'}
25
+ </ToastBody>
26
+ </Toast>
27
+ )
28
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports["default"] = ToastContainer;
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
+ var _react = _interopRequireWildcard(require("react"));
11
+ var _reactRedux = require("react-redux");
12
+ var _actions = require("../../actions");
13
+ var _ToastComponent = require("./ToastComponent.js");
14
+ var _reducer = require("./reducer.js");
15
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
16
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
17
+ // Toast container
18
+ function ToastContainer(props) {
19
+ var _attentionRequired$be;
20
+ // Get the toast data from Redux (assuming it comes from `attentionrequired.beacon`)
21
+ var attentionRequired = (0, _reactRedux.useSelector)(function (state) {
22
+ var _state$attentionrequi;
23
+ return (_state$attentionrequi = state.attentionrequired) === null || _state$attentionrequi === void 0 ? void 0 : _state$attentionrequi.beacon;
24
+ });
25
+ var toastData = (attentionRequired === null || attentionRequired === void 0 || (_attentionRequired$be = attentionRequired['beacon.toast']) === null || _attentionRequired$be === void 0 ? void 0 : _attentionRequired$be.data) || [];
26
+
27
+ // useReducer to manage the local state of toasts
28
+ var _useReducer = (0, _react.useReducer)(_reducer.toastReducer, {
29
+ toasts: []
30
+ }),
31
+ _useReducer2 = (0, _slicedToArray2["default"])(_useReducer, 2),
32
+ state = _useReducer2[0],
33
+ dispatch = _useReducer2[1];
34
+
35
+ // Handle new toast data from attention required store
36
+ (0, _react.useEffect)(function () {
37
+ if (toastData && toastData.length > 0) {
38
+ toastData.forEach(function (reduxToast) {
39
+ // Add new toast into the toast redux store
40
+ dispatch({
41
+ type: _actions.ADD_TOAST,
42
+ title: reduxToast === null || reduxToast === void 0 ? void 0 : reduxToast.title,
43
+ message: reduxToast === null || reduxToast === void 0 ? void 0 : reduxToast.message,
44
+ level: reduxToast === null || reduxToast === void 0 ? void 0 : reduxToast.level,
45
+ // 'info', 'warning', etc.
46
+ expire: (reduxToast === null || reduxToast === void 0 ? void 0 : reduxToast.expire) || 30 // Toast expiration time (in seconds)
47
+ });
48
+ });
49
+ }
50
+ }, [toastData, dispatch]);
51
+
52
+ // useEffect to automatically remove expired toasts
53
+ (0, _react.useEffect)(function () {
54
+ var interval = setInterval(function () {
55
+ var now = new Date();
56
+ state === null || state === void 0 || state.toasts.forEach(function (toast) {
57
+ if (toast.expire <= now) {
58
+ dispatch({
59
+ type: _actions.DEL_TOAST,
60
+ key: toast.key
61
+ }); // Remove expired toast
62
+ }
63
+ });
64
+ }, 2000); // Check for expiration every 2 seconds
65
+
66
+ return function () {
67
+ return clearInterval(interval);
68
+ }; // Cleanup interval on component unmount
69
+ }, [state === null || state === void 0 ? void 0 : state.toasts, dispatch]);
70
+ return /*#__PURE__*/_react["default"].createElement("div", {
71
+ className: "toast-container position-fixed bottom-0 end-0 p-3"
72
+ }, (state === null || state === void 0 ? void 0 : state.toasts) && (state === null || state === void 0 ? void 0 : state.toasts.length) > 0 && (state === null || state === void 0 ? void 0 : state.toasts.map(function (toast, idx) {
73
+ return /*#__PURE__*/_react["default"].createElement(_ToastComponent.ToastComponent, {
74
+ key: idx,
75
+ app: props.app,
76
+ content: toast,
77
+ dispatch: dispatch
78
+ });
79
+ })));
80
+ }
@@ -0,0 +1,59 @@
1
+ import React, { useEffect, useReducer } from 'react';
2
+ import { useSelector } from 'react-redux';
3
+ import { DEL_TOAST, ADD_TOAST } from '../../actions';
4
+
5
+ import { ToastComponent } from './ToastComponent.jsx';
6
+ import { toastReducer } from './reducer.jsx';
7
+
8
+ // Toast container
9
+ export default function ToastContainer(props) {
10
+ // Get the toast data from Redux (assuming it comes from `attentionrequired.beacon`)
11
+ const attentionRequired = useSelector((state) => state.attentionrequired?.beacon);
12
+ const toastData = attentionRequired?.['beacon.toast']?.data || [];
13
+
14
+ // useReducer to manage the local state of toasts
15
+ const [state, dispatch] = useReducer(toastReducer, { toasts: [] });
16
+
17
+ // Handle new toast data from attention required store
18
+ useEffect(() => {
19
+ if (toastData && toastData.length > 0) {
20
+ toastData.forEach((reduxToast) => {
21
+ // Add new toast into the toast redux store
22
+ dispatch({
23
+ type: ADD_TOAST,
24
+ title: reduxToast?.title,
25
+ message: reduxToast?.message,
26
+ level: reduxToast?.level, // 'info', 'warning', etc.
27
+ expire: reduxToast?.expire || 30, // Toast expiration time (in seconds)
28
+ });
29
+ });
30
+ }
31
+ }, [toastData, dispatch]);
32
+
33
+ // useEffect to automatically remove expired toasts
34
+ useEffect(() => {
35
+ const interval = setInterval(() => {
36
+ const now = new Date();
37
+ state?.toasts.forEach((toast) => {
38
+ if (toast.expire <= now) {
39
+ dispatch({ type: DEL_TOAST, key: toast.key }); // Remove expired toast
40
+ }
41
+ });
42
+ }, 2000); // Check for expiration every 2 seconds
43
+
44
+ return () => clearInterval(interval); // Cleanup interval on component unmount
45
+ }, [state?.toasts, dispatch]);
46
+
47
+ return (
48
+ <div className="toast-container position-fixed bottom-0 end-0 p-3">
49
+ {state?.toasts && state?.toasts.length > 0 && state?.toasts.map((toast, idx) => (
50
+ <ToastComponent
51
+ key={idx}
52
+ app={props.app}
53
+ content={toast}
54
+ dispatch={dispatch}
55
+ />
56
+ ))}
57
+ </div>
58
+ );
59
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.toastReducer = toastReducer;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _actions = require("../../actions");
11
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
12
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // Actions
13
+ var initialState = {
14
+ toasts: []
15
+ };
16
+
17
+ // Reducer for toast actions
18
+ function toastReducer() {
19
+ var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState;
20
+ var action = arguments.length > 1 ? arguments[1] : undefined;
21
+ switch (action.type) {
22
+ case _actions.ADD_TOAST:
23
+ {
24
+ // Set expiration time
25
+ var expire = new Date();
26
+ expire.setSeconds(expire.getSeconds() + action.expire);
27
+
28
+ // Generate a new toast
29
+ var newToast = {
30
+ key: Math.floor(Math.random() * 65536),
31
+ title: action.title,
32
+ message: action.message,
33
+ level: action.level,
34
+ _c: action._c,
35
+ expire: expire
36
+ };
37
+
38
+ // Return new state with added toast
39
+ return _objectSpread(_objectSpread({}, state), {}, {
40
+ toasts: state !== null && state !== void 0 && state.toasts ? [].concat((0, _toConsumableArray2["default"])(state === null || state === void 0 ? void 0 : state.toasts), [newToast]) : initialState.toasts
41
+ });
42
+ }
43
+ case _actions.DEL_TOAST:
44
+ {
45
+ // Filter out the toast to be deleted by key
46
+ return _objectSpread(_objectSpread({}, state), {}, {
47
+ toasts: state === null || state === void 0 ? void 0 : state.toasts.filter(function (toast) {
48
+ return toast.key !== action.key;
49
+ })
50
+ });
51
+ }
52
+ default:
53
+ return state;
54
+ }
55
+ }
@@ -0,0 +1,45 @@
1
+ // Actions
2
+ import { ADD_TOAST, DEL_TOAST } from '../../actions';
3
+
4
+ const initialState = {
5
+ toasts: [],
6
+ };
7
+
8
+ // Reducer for toast actions
9
+ export function toastReducer(state = initialState, action) {
10
+ switch (action.type) {
11
+
12
+ case ADD_TOAST: {
13
+ // Set expiration time
14
+ const expire = new Date();
15
+ expire.setSeconds(expire.getSeconds() + action.expire);
16
+
17
+ // Generate a new toast
18
+ const newToast = {
19
+ key: Math.floor(Math.random() * 65536),
20
+ title: action.title,
21
+ message: action.message,
22
+ level: action.level,
23
+ _c: action._c,
24
+ expire: expire,
25
+ };
26
+
27
+ // Return new state with added toast
28
+ return {
29
+ ...state,
30
+ toasts: state?.toasts ? [...state?.toasts, newToast] : initialState.toasts,
31
+ };
32
+ }
33
+
34
+ case DEL_TOAST: {
35
+ // Filter out the toast to be deleted by key
36
+ return {
37
+ ...state,
38
+ toasts: state?.toasts.filter(toast => toast.key !== action.key),
39
+ };
40
+ }
41
+
42
+ default:
43
+ return state;
44
+ }
45
+ }
package/dist/index.js ADDED
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ Object.defineProperty(exports, "AboutModule", {
8
+ enumerable: true,
9
+ get: function get() {
10
+ return _about["default"];
11
+ }
12
+ });
13
+ Object.defineProperty(exports, "Application", {
14
+ enumerable: true,
15
+ get: function get() {
16
+ return _Application["default"];
17
+ }
18
+ });
19
+ Object.defineProperty(exports, "AuthModule", {
20
+ enumerable: true,
21
+ get: function get() {
22
+ return _auth["default"];
23
+ }
24
+ });
25
+ Object.defineProperty(exports, "I18nModule", {
26
+ enumerable: true,
27
+ get: function get() {
28
+ return _i18n["default"];
29
+ }
30
+ });
31
+ Object.defineProperty(exports, "TenantModule", {
32
+ enumerable: true,
33
+ get: function get() {
34
+ return _tenant["default"];
35
+ }
36
+ });
37
+ Object.defineProperty(exports, "getBrandImage", {
38
+ enumerable: true,
39
+ get: function get() {
40
+ return _BrandImage.getBrandImage;
41
+ }
42
+ });
43
+ var _Application = _interopRequireDefault(require("./containers/Application"));
44
+ var _BrandImage = require("./components/branding/BrandImage");
45
+ var _i18n = _interopRequireDefault(require("./modules/i18n"));
46
+ var _tenant = _interopRequireDefault(require("./modules/tenant"));
47
+ var _auth = _interopRequireDefault(require("./modules/auth"));
48
+ var _about = _interopRequireDefault(require("./modules/about"));
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports["default"] = void 0;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _reactI18next = require("react-i18next");
10
+ var _reactRedux = require("react-redux");
11
+ var _reactstrap = require("reactstrap");
12
+ function AboutScreen(props) {
13
+ return /*#__PURE__*/_react["default"].createElement(_reactstrap.Container, {
14
+ className: "pt-5"
15
+ }, /*#__PURE__*/_react["default"].createElement(_reactstrap.Row, {
16
+ className: "justify-content-center"
17
+ }, /*#__PURE__*/_react["default"].createElement(_reactstrap.Col, {
18
+ md: "6"
19
+ }, /*#__PURE__*/_react["default"].createElement(AboutCard, {
20
+ app: props.app
21
+ }))));
22
+ }
23
+ var _default = exports["default"] = AboutScreen;
24
+ /*
25
+
26
+ Language localizations for AboutCard can be added to the translation.json files of
27
+ public/locales/en & public/locales/cs
28
+
29
+ Example:
30
+
31
+ {
32
+ "AboutCard": {
33
+ "Vendor": "Vendor Ltd"
34
+ "Web site": "https://example.com",
35
+ }
36
+ }
37
+
38
+ */
39
+ // TODO: add info about version release and date of the release
40
+ function AboutCard(props) {
41
+ var _useTranslation = (0, _reactI18next.useTranslation)(),
42
+ t = _useTranslation.t;
43
+ var title = (0, _reactRedux.useSelector)(function (state) {
44
+ var _state$config;
45
+ return (_state$config = state.config) === null || _state$config === void 0 ? void 0 : _state$config.title;
46
+ });
47
+ var vendor = (0, _reactRedux.useSelector)(function (state) {
48
+ var _state$config2;
49
+ return (_state$config2 = state.config) === null || _state$config2 === void 0 ? void 0 : _state$config2.vendor;
50
+ });
51
+ var website = (0, _reactRedux.useSelector)(function (state) {
52
+ var _state$config3;
53
+ return (_state$config3 = state.config) === null || _state$config3 === void 0 ? void 0 : _state$config3.website;
54
+ });
55
+ var email = (0, _reactRedux.useSelector)(function (state) {
56
+ var _state$config4;
57
+ return (_state$config4 = state.config) === null || _state$config4 === void 0 ? void 0 : _state$config4.email;
58
+ });
59
+ return /*#__PURE__*/_react["default"].createElement(_reactstrap.Card, null, /*#__PURE__*/_react["default"].createElement(_reactstrap.CardHeader, {
60
+ className: "card-header-flex"
61
+ }, /*#__PURE__*/_react["default"].createElement("div", {
62
+ className: "flex-fill"
63
+ }, /*#__PURE__*/_react["default"].createElement("h3", null, t('AboutCard|About'), " ", title))), /*#__PURE__*/_react["default"].createElement("ul", {
64
+ className: "list-group list-group-flush"
65
+ }, vendor && /*#__PURE__*/_react["default"].createElement("li", {
66
+ className: "list-group-item"
67
+ }, /*#__PURE__*/_react["default"].createElement(_reactstrap.Row, null, /*#__PURE__*/_react["default"].createElement(_reactstrap.Col, {
68
+ className: "col-6"
69
+ }, t('AboutCard|Vendor')), /*#__PURE__*/_react["default"].createElement(_reactstrap.Col, null, vendor))), website && /*#__PURE__*/_react["default"].createElement("li", {
70
+ className: "list-group-item"
71
+ }, /*#__PURE__*/_react["default"].createElement(_reactstrap.Row, null, /*#__PURE__*/_react["default"].createElement(_reactstrap.Col, {
72
+ className: "col-6"
73
+ }, t('AboutCard|Website')), /*#__PURE__*/_react["default"].createElement(_reactstrap.Col, null, /*#__PURE__*/_react["default"].createElement("a", {
74
+ href: website,
75
+ target: "_blank",
76
+ rel: "noopener noreferrer"
77
+ }, website)))), website && /*#__PURE__*/_react["default"].createElement("li", {
78
+ className: "list-group-item"
79
+ }, /*#__PURE__*/_react["default"].createElement(_reactstrap.Row, null, /*#__PURE__*/_react["default"].createElement(_reactstrap.Col, {
80
+ className: "col-6"
81
+ }, t('AboutCard|Email')), /*#__PURE__*/_react["default"].createElement(_reactstrap.Col, null, /*#__PURE__*/_react["default"].createElement("a", {
82
+ href: "mailto:".concat(email)
83
+ }, email))))));
84
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports["default"] = void 0;
9
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
12
+ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
13
+ var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
14
+ var _react = require("react");
15
+ var _asab_webui_components = require("asab_webui_components");
16
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
17
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
18
+ function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); }
19
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
20
+ var AboutModule = exports["default"] = /*#__PURE__*/function (_Module) {
21
+ function AboutModule(app, name) {
22
+ var _this;
23
+ (0, _classCallCheck2["default"])(this, AboutModule);
24
+ _this = _callSuper(this, AboutModule, [app, "AboutModule"]);
25
+ var AboutScreen = /*#__PURE__*/(0, _react.lazy)(function () {
26
+ return Promise.resolve().then(function () {
27
+ return _interopRequireWildcard(require("./AboutScreen"));
28
+ });
29
+ });
30
+ app.Router.addRoute({
31
+ path: "/about",
32
+ end: true,
33
+ name: "About",
34
+ component: AboutScreen,
35
+ resource: "*"
36
+ });
37
+ return _this;
38
+ }
39
+ (0, _inherits2["default"])(AboutModule, _Module);
40
+ return (0, _createClass2["default"])(AboutModule);
41
+ }(_asab_webui_components.Module);
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.types = void 0;
7
+ var types = exports.types = {
8
+ AUTH_USERINFO: "SeaCat/AUTH_USERINFO",
9
+ AUTH_RESOURCES: "SeaCat/AUTH_RESOURCES",
10
+ AUTH_SESSION_EXPIRATION: "SeaCat/AUTH_SESSION_EXPIRATION"
11
+ };
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.SeaCatAuthApi = exports.GoogleOAuth2Api = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
12
+ var _axios = _interopRequireDefault(require("axios"));
13
+ var _locationReplace = require("../../components/locationReplace");
14
+ var SeaCatAuthApi = exports.SeaCatAuthApi = /*#__PURE__*/function () {
15
+ /*
16
+ SeaCat Auth Open ID Connect / OAuth2.0
17
+
18
+ From config.js:
19
+ module.exports = {
20
+ app: {
21
+ BASE_URL: 'http://localhost:3000',
22
+ API_PATH: 'api',
23
+ SERVICES: {openidconnect: 'openidconnect'},
24
+ ...
25
+ */
26
+
27
+ function SeaCatAuthApi(app) {
28
+ (0, _classCallCheck2["default"])(this, SeaCatAuthApi);
29
+ this.App = app;
30
+ var scope = this.App.Config.get('seacat.auth.scope');
31
+ this.Scope = scope ? scope : "openid tenant userinfo:* batman";
32
+ this.ClientId = "asab-webui-auth";
33
+ this.SeaCatAuthAPI = this.App.axiosCreate('seacat-auth');
34
+ this.OidcAPI = this.App.axiosCreate('openidconnect');
35
+ }
36
+
37
+ // This method will cause a navigation from the app to the OAuth2 login screen
38
+ return (0, _createClass2["default"])(SeaCatAuthApi, [{
39
+ key: "login",
40
+ value: function () {
41
+ var _login = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee(redirect_uri, force_login_prompt) {
42
+ var currentTenant, scopeArray, tenantValue, loginScope, typedArray, randomIndex, stateIndex, redirectUri, state, params, oidcURL;
43
+ return _regenerator["default"].wrap(function _callee$(_context) {
44
+ while (1) switch (_context.prev = _context.next) {
45
+ case 0:
46
+ /*
47
+ Adding tenant directly to scope (if available).
48
+ */
49
+ currentTenant = null;
50
+ if (this.App.Services.TenantService) {
51
+ currentTenant = this.App.Services.TenantService.getCurrentTenant();
52
+ }
53
+ scopeArray = this.Scope.split(" ");
54
+ tenantValue = scopeArray.find(function (str) {
55
+ return str.includes("tenant");
56
+ });
57
+ loginScope = currentTenant != null && tenantValue != undefined ? this.Scope.replace("".concat(tenantValue), "tenant:".concat(currentTenant)) : this.Scope; // Generate random state
58
+ typedArray = new Uint32Array(10);
59
+ crypto.getRandomValues(typedArray);
60
+ randomIndex = Math.floor(Math.random() * typedArray.length);
61
+ stateIndex = typedArray[randomIndex];
62
+ /*
63
+ As per OAuth2 specs, the redirect_uri must *exactly* match one of the URIs pre-registered
64
+ at the authorization server, hence it cannot contain variable components (query, hash).
65
+ Here we use the application's base URL as the redirect_uri and store the variable parts in the state.
66
+ */
67
+ redirectUri = new URL(redirect_uri);
68
+ state = redirectUri.search + redirectUri.hash;
69
+ localStorage.setItem("oauth2_state_".concat(stateIndex), state);
70
+ params = new URLSearchParams({
71
+ response_type: "code",
72
+ scope: loginScope,
73
+ client_id: this.ClientId,
74
+ redirect_uri: redirectUri.origin + redirectUri.pathname,
75
+ state: stateIndex
76
+ });
77
+ if (force_login_prompt === true) {
78
+ params.append("prompt", "login");
79
+ }
80
+ oidcURL = this.App.getServiceURL('openidconnect');
81
+ _context.next = 17;
82
+ return (0, _locationReplace.locationReplace)(oidcURL + "/authorize?" + params.toString());
83
+ case 17:
84
+ case "end":
85
+ return _context.stop();
86
+ }
87
+ }, _callee, this);
88
+ }));
89
+ function login(_x, _x2) {
90
+ return _login.apply(this, arguments);
91
+ }
92
+ return login;
93
+ }()
94
+ }, {
95
+ key: "logout",
96
+ value: function logout(access_token) {
97
+ return this.OidcAPI.get('/logout', {
98
+ headers: {
99
+ 'Authorization': 'Bearer ' + access_token
100
+ }
101
+ });
102
+ }
103
+ }, {
104
+ key: "userinfo",
105
+ value: function userinfo(access_token) {
106
+ var userinfoPath = '/userinfo';
107
+ var headers = {};
108
+ // Add access bearer token to the Authorization headers
109
+ if (access_token != null) {
110
+ headers.Authorization = 'Bearer ' + access_token;
111
+ }
112
+ return this.OidcAPI.get(userinfoPath, {
113
+ headers: headers
114
+ });
115
+ }
116
+ }, {
117
+ key: "token_authorization_code",
118
+ value: function token_authorization_code(authorization_code, redirect_uri) {
119
+ var redirectUri = new URL(redirect_uri);
120
+ var qs = new URLSearchParams({
121
+ grant_type: "authorization_code",
122
+ code: authorization_code,
123
+ client_id: this.ClientId,
124
+ /*
125
+ As per OAuth2 specs, the redirect_uri must *exactly* match the one provided
126
+ at the authorization endpoint, hence the application base URL.
127
+ */
128
+ redirect_uri: redirectUri.origin + redirectUri.pathname
129
+ });
130
+ return this.OidcAPI.post('/token', qs.toString());
131
+ }
132
+ }]);
133
+ }();
134
+ ;
135
+ var GoogleOAuth2Api = exports.GoogleOAuth2Api = /*#__PURE__*/function () {
136
+ /*
137
+ Google OAuth2 API is configured at Google API Console > Credentials > OAuth 2.0 Client IDs
138
+
139
+ From config.js:
140
+ module.exports = {
141
+ app: {
142
+ "google.oauth2.client_id": "<Google OAuth2 Client ID>.apps.googleusercontent.com",
143
+ "google.oauth2.client_secret": "<Google OAuth2 Client secret>",
144
+ ...
145
+ */
146
+
147
+ function GoogleOAuth2Api(config) {
148
+ (0, _classCallCheck2["default"])(this, GoogleOAuth2Api);
149
+ this.Axios = _axios["default"].create({
150
+ timeout: 10000
151
+ });
152
+ var scope = config.get('google.oauth2.scope');
153
+ this.ClientId = config.get('google.oauth2.client_id');
154
+ this.ClientSecret = config.get('google.oauth2.client_secret');
155
+ this.Scope = scope ? scope : "openid https://www.googleapis.com/auth/userinfo.profile";
156
+ }
157
+
158
+ // This method will cause a navigation from the app to the OAuth2 login screen
159
+ return (0, _createClass2["default"])(GoogleOAuth2Api, [{
160
+ key: "login",
161
+ value: function () {
162
+ var _login2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee2(redirect_uri) {
163
+ var params;
164
+ return _regenerator["default"].wrap(function _callee2$(_context2) {
165
+ while (1) switch (_context2.prev = _context2.next) {
166
+ case 0:
167
+ params = new URLSearchParams({
168
+ response_type: "code",
169
+ scope: this.Scope,
170
+ client_id: this.ClientId,
171
+ redirect_uri: redirect_uri
172
+ });
173
+ _context2.next = 3;
174
+ return (0, _locationReplace.locationReplace)("https://accounts.google.com/o/oauth2/auth" + "?" + params.toString());
175
+ case 3:
176
+ case "end":
177
+ return _context2.stop();
178
+ }
179
+ }, _callee2, this);
180
+ }));
181
+ function login(_x3) {
182
+ return _login2.apply(this, arguments);
183
+ }
184
+ return login;
185
+ }()
186
+ }, {
187
+ key: "logout",
188
+ value: function logout(access_token) {
189
+ // There is no Google logout API URL, to our best knowledge
190
+ return null;
191
+ }
192
+ }, {
193
+ key: "userinfo",
194
+ value: function userinfo(access_token) {
195
+ var qs = new URLSearchParams({
196
+ alt: "json",
197
+ access_token: access_token
198
+ });
199
+ return this.Axios.get('https://www.googleapis.com/oauth2/v1/userinfo?' + qs.toString());
200
+ }
201
+ }, {
202
+ key: "token_authorization_code",
203
+ value: function token_authorization_code(authorization_code, redirect_uri) {
204
+ var qs = new URLSearchParams({
205
+ grant_type: "authorization_code",
206
+ code: authorization_code,
207
+ client_id: this.ClientId,
208
+ client_secret: this.ClientSecret,
209
+ redirect_uri: redirect_uri
210
+ });
211
+ return this.Axios.post('https://oauth2.googleapis.com/token', qs.toString());
212
+ }
213
+ }]);
214
+ }();