asab_webui_shell 26.1.3 → 26.3.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.
- package/dist/config/ConfigService.js +18 -49
- package/dist/containers/Application.js +0 -40
- package/dist/containers/Application.scss +10 -0
- package/dist/containers/Header/ApplicationScreenTitle/ApplicationScreenTitle.js +31 -0
- package/dist/containers/Sidebar/SidebarItem.js +1 -1
- package/dist/containers/Sidebar/index.js +42 -0
- package/dist/index.js +8 -1
- package/dist/modules/attentionrequired/index.js +21 -0
- package/dist/modules/attentionrequired/index.jsx +17 -0
- package/dist/modules/attentionrequired/reducer.jsx +20 -0
- package/dist/{services/AttentionRequiredService.js → modules/attentionrequired/service.js} +2 -1
- package/dist/modules/attentionrequired/service.jsx +141 -0
- package/package.json +1 -1
- /package/dist/{containers/AttentionRequired → modules/attentionrequired}/reducer.js +0 -0
|
@@ -5,12 +5,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.default = void 0;
|
|
8
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
8
|
var _asab_webui_components = require("asab_webui_components");
|
|
10
9
|
var _ConfigReducer = _interopRequireDefault(require("./ConfigReducer"));
|
|
11
10
|
var _actions = require("../actions");
|
|
12
|
-
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; }
|
|
13
|
-
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; }
|
|
14
11
|
class ConfigService extends _asab_webui_components.Service {
|
|
15
12
|
constructor(app) {
|
|
16
13
|
var serviceName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "ConfigService";
|
|
@@ -19,53 +16,25 @@ class ConfigService extends _asab_webui_components.Service {
|
|
|
19
16
|
this.Config = new Config();
|
|
20
17
|
}
|
|
21
18
|
initialize() {
|
|
22
|
-
var _document$getElements, _document$getElements2
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
var _document$getElements, _document$getElements2;
|
|
20
|
+
/*
|
|
21
|
+
Initialization of dynamic configuration
|
|
22
|
+
Dynamic branding of the header logo can be done via nginx location configuration.
|
|
23
|
+
The support of meta tags for configuration of the header logo brand image has been striped of in 09/2025
|
|
24
|
+
from ASAB WebUI Shell version 26.3.1
|
|
25
|
+
Example of setting up the nginx location for full logo. Same way it can be done for minimized variation.
|
|
26
|
+
...
|
|
27
|
+
location /<app path>/media/logo/header-logo-full-dark.svg {
|
|
28
|
+
alias /<path to logo>/<logo name for dark theme>.svg;
|
|
29
|
+
}
|
|
30
|
+
location /<app path>/media/logo/header-logo-full.svg {
|
|
31
|
+
alias /<path to logo>/<logo name for light theme>.svg;
|
|
32
|
+
}
|
|
33
|
+
...
|
|
34
|
+
*/
|
|
35
|
+
var title = (_document$getElements = document.getElementsByName('title')[0]) === null || _document$getElements === void 0 ? void 0 : _document$getElements.content;
|
|
36
|
+
var customCSS = (_document$getElements2 = document.getElementsByName('custom-css-file')[0]) === null || _document$getElements2 === void 0 ? void 0 : _document$getElements2.content;
|
|
30
37
|
var dynamicConfig = {};
|
|
31
|
-
// determine if any logos have been dynamically configured and assign brandImage property as an empty object
|
|
32
|
-
if (headerLogoFull != undefined && headerLogoFull != "" || headerLogoFullDark != undefined && headerLogoFullDark != "" || headerLogoMini != undefined && headerLogoMini != "" || headerLogoMiniDark != undefined && headerLogoMiniDark != "") {
|
|
33
|
-
dynamicConfig.brandImage = {};
|
|
34
|
-
}
|
|
35
|
-
// If header's full light logo has been configured, add it to dynamic config object
|
|
36
|
-
if (headerLogoFull != undefined && headerLogoFull != "") {
|
|
37
|
-
Object.assign(dynamicConfig.brandImage, {
|
|
38
|
-
"light": {
|
|
39
|
-
"full": headerLogoFull
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
// If header's full dark logo has been configured, extend/add it to dynamic config's brandImage property
|
|
44
|
-
if (headerLogoFullDark != undefined && headerLogoFullDark != "") {
|
|
45
|
-
Object.assign(dynamicConfig.brandImage, {
|
|
46
|
-
"dark": {
|
|
47
|
-
"full": headerLogoFullDark
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
// If header's minimized light logo has been configured, extend/add it to dynamic config brandImage property
|
|
52
|
-
if (headerLogoMini != undefined && headerLogoMini != "") {
|
|
53
|
-
var _dynamicConfig$brandI;
|
|
54
|
-
Object.assign(dynamicConfig.brandImage, _objectSpread(_objectSpread({}, dynamicConfig.brandImage), {}, {
|
|
55
|
-
"light": _objectSpread(_objectSpread({}, (_dynamicConfig$brandI = dynamicConfig.brandImage) === null || _dynamicConfig$brandI === void 0 ? void 0 : _dynamicConfig$brandI.light), {}, {
|
|
56
|
-
"minimized": headerLogoMini
|
|
57
|
-
})
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
// If header's minimized dark logo has been configured, extend/add it to dynamic config brandImage property
|
|
61
|
-
if (headerLogoMiniDark != undefined && headerLogoMiniDark != "") {
|
|
62
|
-
var _dynamicConfig$brandI2;
|
|
63
|
-
Object.assign(dynamicConfig.brandImage, _objectSpread(_objectSpread({}, dynamicConfig.brandImage), {}, {
|
|
64
|
-
"dark": _objectSpread(_objectSpread({}, (_dynamicConfig$brandI2 = dynamicConfig.brandImage) === null || _dynamicConfig$brandI2 === void 0 ? void 0 : _dynamicConfig$brandI2.dark), {}, {
|
|
65
|
-
"minimized": headerLogoMiniDark
|
|
66
|
-
})
|
|
67
|
-
}));
|
|
68
|
-
}
|
|
69
38
|
|
|
70
39
|
// Add custom title
|
|
71
40
|
if (title != undefined && title != "") {
|
|
@@ -25,9 +25,7 @@ var _reducer4 = _interopRequireDefault(require("./Navigation/reducer"));
|
|
|
25
25
|
var _reducer5 = _interopRequireDefault(require("./Router/reducer"));
|
|
26
26
|
var _reducer6 = _interopRequireDefault(require("./FullscreenMode/reducer"));
|
|
27
27
|
var _reducer7 = _interopRequireDefault(require("./AdvancedMode/reducer"));
|
|
28
|
-
var _reducer8 = _interopRequireDefault(require("./AttentionRequired/reducer"));
|
|
29
28
|
var _ReduxService = _interopRequireDefault(require("../services/ReduxService"));
|
|
30
|
-
var _AttentionRequiredService = _interopRequireDefault(require("../services/AttentionRequiredService"));
|
|
31
29
|
var _ConfigService = _interopRequireDefault(require("../config/ConfigService"));
|
|
32
30
|
var _HeaderService = _interopRequireDefault(require("../services/HeaderService"));
|
|
33
31
|
var _ThemeService = _interopRequireDefault(require("../theme/ThemeService"));
|
|
@@ -43,42 +41,6 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
43
41
|
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; }
|
|
44
42
|
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; }
|
|
45
43
|
class Application extends _react.Component {
|
|
46
|
-
/*
|
|
47
|
-
Example of use hasSidebar.
|
|
48
|
-
It must be set in Application.
|
|
49
|
-
If not set, it is considered as true.
|
|
50
|
-
|
|
51
|
-
...
|
|
52
|
-
|
|
53
|
-
const config = {
|
|
54
|
-
hasSidebar: false,
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
ReactDOM.render((
|
|
59
|
-
<BrowserRouter>
|
|
60
|
-
<Application modules={modules} {...config}/>
|
|
61
|
-
</BrowserRouter>
|
|
62
|
-
), document.getElementById('app'));
|
|
63
|
-
|
|
64
|
-
...
|
|
65
|
-
|
|
66
|
-
Example of settings in Module of the Application
|
|
67
|
-
Following above settings, this will show the item in
|
|
68
|
-
the header and when the screen is diminished (e.g. screening
|
|
69
|
-
using the mobile phone), the item is moved to the sidebar and
|
|
70
|
-
it is accessible by the sidebar toggler button.
|
|
71
|
-
|
|
72
|
-
...
|
|
73
|
-
|
|
74
|
-
app.Navigation.addItem({
|
|
75
|
-
name: 'Item 1',
|
|
76
|
-
url: '',
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
...
|
|
80
|
-
*/
|
|
81
|
-
|
|
82
44
|
constructor(props) {
|
|
83
45
|
super(props);
|
|
84
46
|
|
|
@@ -91,7 +53,6 @@ class Application extends _react.Component {
|
|
|
91
53
|
this.Config = this.ConfigService.Config;
|
|
92
54
|
|
|
93
55
|
// Register reducers which are not part of any app service
|
|
94
|
-
this.ReduxService.addReducer("attentionrequired", _reducer8.default);
|
|
95
56
|
this.ReduxService.addReducer("alerts", _reducer.default);
|
|
96
57
|
this.ReduxService.addReducer("advmode", _reducer7.default);
|
|
97
58
|
this.ReduxService.addReducer("fullscreenmode", _reducer6.default);
|
|
@@ -104,7 +65,6 @@ class Application extends _react.Component {
|
|
|
104
65
|
this.SplashscreenRequestors = new Set(); // If not empty, the splash screen will be rendered
|
|
105
66
|
this.AxiosInterceptors = new Set();
|
|
106
67
|
this.WebSocketInterceptors = new Set();
|
|
107
|
-
this.AttentionRequiredService = new _AttentionRequiredService.default(this, "AttentionRequired");
|
|
108
68
|
this.HeaderService = new _HeaderService.default(this, "HeaderService");
|
|
109
69
|
this.ThemeService = new _ThemeService.default(this, "ThemeService");
|
|
110
70
|
this.BrandingService = new _BrandingService.default(this, "BrandingService");
|
|
@@ -9,6 +9,28 @@ var _reactI18next = require("react-i18next");
|
|
|
9
9
|
var _asab_webui_components = require("asab_webui_components");
|
|
10
10
|
require("./ApplicationScreenTitle.scss");
|
|
11
11
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
12
|
+
/*
|
|
13
|
+
Example of use hasHeaderTitle.
|
|
14
|
+
It must be set in App configuration.
|
|
15
|
+
If not set to `false` or at all, it is considered as true.
|
|
16
|
+
|
|
17
|
+
...
|
|
18
|
+
|
|
19
|
+
const ConfigDefaults = {
|
|
20
|
+
...
|
|
21
|
+
hasHeaderTitle: false,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
root.render(
|
|
25
|
+
<HashRouter>
|
|
26
|
+
<Application
|
|
27
|
+
configdefaults={ConfigDefaults}
|
|
28
|
+
modules={modules}
|
|
29
|
+
/>
|
|
30
|
+
</HashRouter>
|
|
31
|
+
);
|
|
32
|
+
*/
|
|
33
|
+
|
|
12
34
|
var ApplicationScreenTitle = props => {
|
|
13
35
|
var _props$routes;
|
|
14
36
|
var subtitle = (0, _asab_webui_components.useAppSelector)(state => {
|
|
@@ -19,6 +41,10 @@ var ApplicationScreenTitle = props => {
|
|
|
19
41
|
var _state$config;
|
|
20
42
|
return (_state$config = state.config) === null || _state$config === void 0 ? void 0 : _state$config.title;
|
|
21
43
|
});
|
|
44
|
+
var hasHeaderTitle = (0, _asab_webui_components.useAppSelector)(state => {
|
|
45
|
+
var _state$config2;
|
|
46
|
+
return state === null || state === void 0 || (_state$config2 = state.config) === null || _state$config2 === void 0 ? void 0 : _state$config2.hasHeaderTitle;
|
|
47
|
+
});
|
|
22
48
|
var {
|
|
23
49
|
t
|
|
24
50
|
} = (0, _reactI18next.useTranslation)();
|
|
@@ -33,6 +59,11 @@ var ApplicationScreenTitle = props => {
|
|
|
33
59
|
(0, _react.useEffect)(() => {
|
|
34
60
|
document.title = title && routeName ? "".concat(title, " | ").concat(routeName) : title;
|
|
35
61
|
}, [routeName, t]);
|
|
62
|
+
|
|
63
|
+
// If specifically declared in the configuration, that header title should not be available, dont display header title
|
|
64
|
+
if (hasHeaderTitle === false) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
36
67
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
37
68
|
className: "application-screen-title text-primary"
|
|
38
69
|
}, /*#__PURE__*/_react.default.createElement("h4", {
|
|
@@ -38,7 +38,7 @@ var SidebarItem = _ref => {
|
|
|
38
38
|
var [isActive, setActive] = (0, _react.useState)(false);
|
|
39
39
|
var lowercasedItemName = item === null || item === void 0 || (_item$name = item.name) === null || _item$name === void 0 ? void 0 : _item$name.toLowerCase();
|
|
40
40
|
// Attention requred flag
|
|
41
|
-
var itemBeacon = beacon ? beacon["beacon.".concat(lowercasedItemName)] : attentionRequired["beacon.".concat(lowercasedItemName)];
|
|
41
|
+
var itemBeacon = beacon ? beacon["beacon.".concat(lowercasedItemName)] : attentionRequired === null || attentionRequired === void 0 ? void 0 : attentionRequired["beacon.".concat(lowercasedItemName)];
|
|
42
42
|
(0, _react.useEffect)(() => {
|
|
43
43
|
// TODO: refactor the handling of active and open states, since it does not behave as expected in some cases
|
|
44
44
|
if (isOpen && !isActive) {
|
|
@@ -14,6 +14,28 @@ var _BrandImage = require("../../components/branding/BrandImage");
|
|
|
14
14
|
require("./sidebar.scss");
|
|
15
15
|
var _SidebarItemRenderer = require("./SidebarItemRenderer");
|
|
16
16
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
17
|
+
/*
|
|
18
|
+
Example of use hasSidebar.
|
|
19
|
+
It must be set in App configuration.
|
|
20
|
+
If not set to `false` or at all, it is considered as true.
|
|
21
|
+
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
const ConfigDefaults = {
|
|
25
|
+
...
|
|
26
|
+
hasSidebar: false,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
root.render(
|
|
30
|
+
<HashRouter>
|
|
31
|
+
<Application
|
|
32
|
+
configdefaults={ConfigDefaults}
|
|
33
|
+
modules={modules}
|
|
34
|
+
/>
|
|
35
|
+
</HashRouter>
|
|
36
|
+
);
|
|
37
|
+
*/
|
|
38
|
+
|
|
17
39
|
function Sidebar(props) {
|
|
18
40
|
var [isSmallResolution, setIsSmallResolution] = (0, _react.useState)(false);
|
|
19
41
|
var [sidebarBottomBranding, setSidebarBottomBranding] = (0, _react.useState)({});
|
|
@@ -22,6 +44,10 @@ function Sidebar(props) {
|
|
|
22
44
|
var _state$navigation;
|
|
23
45
|
return (_state$navigation = state.navigation) === null || _state$navigation === void 0 ? void 0 : _state$navigation.navItems;
|
|
24
46
|
});
|
|
47
|
+
var hasSidebar = (0, _asab_webui_components.useAppSelector)(state => {
|
|
48
|
+
var _state$config;
|
|
49
|
+
return state === null || state === void 0 || (_state$config = state.config) === null || _state$config === void 0 ? void 0 : _state$config.hasSidebar;
|
|
50
|
+
});
|
|
25
51
|
var sessionExpired = (0, _asab_webui_components.useAppSelector)(state => {
|
|
26
52
|
var _state$auth;
|
|
27
53
|
return (_state$auth = state.auth) === null || _state$auth === void 0 ? void 0 : _state$auth.sessionExpired;
|
|
@@ -30,6 +56,22 @@ function Sidebar(props) {
|
|
|
30
56
|
var {
|
|
31
57
|
dispatch
|
|
32
58
|
} = (0, _asab_webui_components.useAppStore)();
|
|
59
|
+
|
|
60
|
+
// Handling sidebar-hidden app class
|
|
61
|
+
(0, _react.useEffect)(() => {
|
|
62
|
+
var appElement = document.getElementById("app");
|
|
63
|
+
if (!appElement) return;
|
|
64
|
+
if (hasSidebar === false) {
|
|
65
|
+
appElement.classList.add("sidebar-hidden");
|
|
66
|
+
} else {
|
|
67
|
+
appElement.classList.remove("sidebar-hidden");
|
|
68
|
+
}
|
|
69
|
+
}, [hasSidebar]);
|
|
70
|
+
|
|
71
|
+
// If specifically declared in the configuration, that sidebar should not be available, dont display sidebar at all
|
|
72
|
+
if (hasSidebar === false) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
33
75
|
(0, _react.useEffect)(() => {
|
|
34
76
|
// Collapse sidebar if innerWidth is smaller or equal to 944px on page initialization
|
|
35
77
|
if (window.innerWidth <= 944) {
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,12 @@ Object.defineProperty(exports, "Application", {
|
|
|
16
16
|
return _Application.default;
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
|
+
Object.defineProperty(exports, "AttentionRequiredModule", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function get() {
|
|
22
|
+
return _index2.default;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
19
25
|
Object.defineProperty(exports, "AuthModule", {
|
|
20
26
|
enumerable: true,
|
|
21
27
|
get: function get() {
|
|
@@ -46,4 +52,5 @@ var _BrandImage = require("./components/branding/BrandImage");
|
|
|
46
52
|
var _i18n = _interopRequireDefault(require("./modules/i18n"));
|
|
47
53
|
var _tenant = _interopRequireDefault(require("./modules/tenant"));
|
|
48
54
|
var _auth = _interopRequireDefault(require("./modules/auth"));
|
|
49
|
-
var _about = _interopRequireDefault(require("./modules/about"));
|
|
55
|
+
var _about = _interopRequireDefault(require("./modules/about"));
|
|
56
|
+
var _index2 = _interopRequireDefault(require("./modules/attentionrequired/index.js"));
|
|
@@ -0,0 +1,21 @@
|
|
|
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 _asab_webui_components = require("asab_webui_components");
|
|
10
|
+
var _service = _interopRequireDefault(require("./service.js"));
|
|
11
|
+
var _reducer = _interopRequireDefault(require("./reducer.js"));
|
|
12
|
+
class AttentionRequiredModule extends _asab_webui_components.Module {
|
|
13
|
+
constructor(app) {
|
|
14
|
+
var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "AttentionRequiredModule";
|
|
15
|
+
super(app, name);
|
|
16
|
+
this.App = app;
|
|
17
|
+
this.AttentionRequiredService = new _service.default(app, "AttentionRequiredService");
|
|
18
|
+
this.App.ReduxService.addReducer("attentionrequired", _reducer.default);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.default = AttentionRequiredModule;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Module } from 'asab_webui_components';
|
|
3
|
+
import AttentionRequiredService from './service.jsx';
|
|
4
|
+
import reducer from './reducer.jsx';
|
|
5
|
+
|
|
6
|
+
export default class AttentionRequiredModule extends Module {
|
|
7
|
+
|
|
8
|
+
constructor(app, name = "AttentionRequiredModule") {
|
|
9
|
+
super(app, name);
|
|
10
|
+
this.App = app;
|
|
11
|
+
|
|
12
|
+
this.AttentionRequiredService = new AttentionRequiredService(app, "AttentionRequiredService");
|
|
13
|
+
|
|
14
|
+
this.App.ReduxService.addReducer("attentionrequired", reducer);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SET_ATTENTION_REQUIRED_BEACON } from "../../actions";
|
|
2
|
+
|
|
3
|
+
const initialState = {
|
|
4
|
+
beacon: {},
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Reducer for attention required, returning beacon
|
|
8
|
+
export default function attentionRequiredReducer(state = initialState, action) {
|
|
9
|
+
switch (action.type) {
|
|
10
|
+
case SET_ATTENTION_REQUIRED_BEACON: {
|
|
11
|
+
return {
|
|
12
|
+
...state,
|
|
13
|
+
beacon: action.beacon
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
default:
|
|
18
|
+
return state;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _asab_webui_components = require("asab_webui_components");
|
|
8
|
-
var _actions = require("
|
|
8
|
+
var _actions = require("../../actions");
|
|
9
9
|
// Service handling attention required
|
|
10
10
|
class AttentionRequiredService extends _asab_webui_components.Service {
|
|
11
11
|
constructor(app) {
|
|
@@ -101,6 +101,7 @@ class AttentionRequiredService extends _asab_webui_components.Service {
|
|
|
101
101
|
distributeData(data) {
|
|
102
102
|
var _this$App2, _this$App2$dispatch;
|
|
103
103
|
var transformedData = this.transformData(data);
|
|
104
|
+
// TODO: use a pubsub instead of the appstore dispatch
|
|
104
105
|
(_this$App2 = this.App) === null || _this$App2 === void 0 || (_this$App2 = _this$App2.AppStore) === null || _this$App2 === void 0 || (_this$App2$dispatch = _this$App2.dispatch) === null || _this$App2$dispatch === void 0 || _this$App2$dispatch.call(_this$App2, {
|
|
105
106
|
type: _actions.SET_ATTENTION_REQUIRED_BEACON,
|
|
106
107
|
beacon: transformedData
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Service } from 'asab_webui_components';
|
|
2
|
+
import { SET_ATTENTION_REQUIRED_BEACON } from '../../actions';
|
|
3
|
+
|
|
4
|
+
// Service handling attention required
|
|
5
|
+
export default class AttentionRequiredService extends Service {
|
|
6
|
+
|
|
7
|
+
constructor(app, serviceName="AttentionRequiredService"){
|
|
8
|
+
super(app, serviceName);
|
|
9
|
+
this.beaconWebSocket = null; // beacon websocket variable
|
|
10
|
+
this.reconnectTimeout = null; // timeout variable
|
|
11
|
+
this.reconnectInterval = 5000; // initial reconnection interval (5 seconds)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Start beacon websocket connection on initialization
|
|
15
|
+
initialize() {
|
|
16
|
+
this.connectBeaconWebSocket();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Method for connection to beacon websocket
|
|
20
|
+
connectBeaconWebSocket() {
|
|
21
|
+
// Retrieve current tenant
|
|
22
|
+
const currentTenant = this.App?.Services?.TenantService?.getCurrentTenant();
|
|
23
|
+
// Gracefully reconnect if tenant was not found
|
|
24
|
+
if (!currentTenant) {
|
|
25
|
+
console.error("Beacon WebSocket error: Tenant was not found!");
|
|
26
|
+
this.reconnectBeaconWebSocket();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const BeaconServiceClient = this.App.createWebSocket('asab-remote-control', `/beacon/${currentTenant}/ws`);
|
|
31
|
+
this.beaconWebSocket = BeaconServiceClient;
|
|
32
|
+
|
|
33
|
+
this.beaconWebSocket.onopen = () => {
|
|
34
|
+
// TODO: may be removed
|
|
35
|
+
console.log('Beacon WebSocket connection established.');
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
this.beaconWebSocket.onmessage = (message) => {
|
|
39
|
+
try {
|
|
40
|
+
const data = JSON.parse(message.data);
|
|
41
|
+
// TODO: implement some type based recognition
|
|
42
|
+
this.distributeData(data);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.error("Error parsing Beacon WebSocket message data:", e);
|
|
45
|
+
this.distributeData({});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
this.beaconWebSocket.onerror = (error) => {
|
|
50
|
+
console.error("Beacon WebSocket error:", error);
|
|
51
|
+
console.error("Beacon WebSocket is attempting to reconnect...");
|
|
52
|
+
this.distributeData({});
|
|
53
|
+
this.reconnectBeaconWebSocket();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
this.beaconWebSocket.onclose = () => {
|
|
57
|
+
/*
|
|
58
|
+
WebSocket connection is closed by the browser automatically when user
|
|
59
|
+
leaves the application (not the screen).
|
|
60
|
+
*/
|
|
61
|
+
if (this.beaconWebSocket) {
|
|
62
|
+
// Close the WebSocket connection
|
|
63
|
+
this.beaconWebSocket.close();
|
|
64
|
+
|
|
65
|
+
// Clean up event listeners
|
|
66
|
+
this.beaconWebSocket.onopen = null;
|
|
67
|
+
this.beaconWebSocket.onmessage = null;
|
|
68
|
+
this.beaconWebSocket.onerror = null;
|
|
69
|
+
this.beaconWebSocket.onclose = null;
|
|
70
|
+
|
|
71
|
+
// Set WebSocket reference to null to free up memory
|
|
72
|
+
this.beaconWebSocket = null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Clear the reconnect timeout if it exists
|
|
76
|
+
if (this.reconnectTimeout) {
|
|
77
|
+
clearTimeout(this.reconnectTimeout);
|
|
78
|
+
this.reconnectTimeout = null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log("Beacon WebSocket connection closed.");
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Method for reconnection to beacon websocket
|
|
86
|
+
reconnectBeaconWebSocket() {
|
|
87
|
+
if (this.reconnectTimeout) {
|
|
88
|
+
clearTimeout(this.reconnectTimeout);
|
|
89
|
+
}
|
|
90
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
91
|
+
this.connectBeaconWebSocket();
|
|
92
|
+
}, this.reconnectInterval); // Retry connection after the reconnection interval
|
|
93
|
+
|
|
94
|
+
// Increase reconnection time by 5s, the limit is 60s (so that we dont overload the server)
|
|
95
|
+
if ((this.reconnectInterval + 5000) <= 60000) {
|
|
96
|
+
this.reconnectInterval += 5000;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Method for distributing the data into Application store
|
|
101
|
+
distributeData(data) {
|
|
102
|
+
const transformedData = this.transformData(data);
|
|
103
|
+
// TODO: use a pubsub instead of the appstore dispatch
|
|
104
|
+
this.App?.AppStore?.dispatch?.({ type: SET_ATTENTION_REQUIRED_BEACON, beacon: transformedData });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Transform and group beacon data
|
|
108
|
+
transformData(inputData) {
|
|
109
|
+
// Validate if input data are array
|
|
110
|
+
if (!Array.isArray(inputData)) {
|
|
111
|
+
return {};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return inputData.reduce((acc, entry) => {
|
|
115
|
+
const { type, _c, reference_path } = entry;
|
|
116
|
+
|
|
117
|
+
// Identify the dynamic key (it could be 'library', 'configuration', 'services', etc.)
|
|
118
|
+
const dynamicKey = Object.keys(entry).find(key => (typeof entry[key] === 'object') && (entry[key] !== null) && !Array.isArray(entry[key]));
|
|
119
|
+
|
|
120
|
+
if (!dynamicKey) {
|
|
121
|
+
// Skip if no valid dynamic key is found
|
|
122
|
+
return acc;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const data = entry[dynamicKey];
|
|
126
|
+
// Ensure type is present in the accumulator
|
|
127
|
+
if (!acc[type]) {
|
|
128
|
+
acc[type] = {
|
|
129
|
+
count: 0,
|
|
130
|
+
data: []
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Push each entry into the data array
|
|
134
|
+
acc[type].data.push(data);
|
|
135
|
+
// Increment count for the type
|
|
136
|
+
acc[type].count += 1;
|
|
137
|
+
|
|
138
|
+
return acc;
|
|
139
|
+
}, {});
|
|
140
|
+
};
|
|
141
|
+
}
|
package/package.json
CHANGED
|
File without changes
|