asab_webui_shell 27.1.4 → 27.2.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/actions.js +2 -1
- package/dist/containers/Application.js +38 -0
- package/dist/containers/Sidebar/SidebarItem.js +4 -11
- package/dist/containers/Sidebar/SidebarItemRenderer.js +6 -3
- package/dist/containers/Sidebar/index.js +9 -2
- package/dist/modules/attentionrequired/components/OfflineIndication.js +22 -0
- package/dist/modules/attentionrequired/components/OfflineIndication.jsx +13 -0
- package/dist/modules/attentionrequired/connectivityReducer.js +30 -0
- package/dist/modules/attentionrequired/connectivityReducer.jsx +20 -0
- package/dist/modules/attentionrequired/index.js +4 -2
- package/dist/modules/attentionrequired/index.jsx +4 -2
- package/dist/modules/attentionrequired/service.js +56 -9
- package/dist/modules/attentionrequired/service.jsx +52 -4
- package/dist/styles/constants/index.scss +4 -0
- package/package.json +4 -4
- /package/dist/modules/attentionrequired/{reducer.js → attentionRequiredReducer.js} +0 -0
- /package/dist/modules/attentionrequired/{reducer.jsx → attentionRequiredReducer.jsx} +0 -0
package/dist/actions.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.SET_SUBTITLE = exports.SET_ROUTES = exports.SET_NAVIGATION_ITEMS = exports.SET_HELP_PATH = exports.SET_HEADER_NAVIGATION_ITEMS = exports.SET_FULLSCREEN_MODE = exports.SET_ATTENTION_REQUIRED_BEACON = exports.SET_ADVANCED_MODE = exports.DEL_TOAST = exports.DEL_ALERT = exports.COLLAPSE_SIDEBAR = exports.CHANGE_CONFIG = exports.ADD_TOAST = exports.ADD_ALERT = exports.ACK_ALERT = void 0;
|
|
6
|
+
exports.SET_SUBTITLE = exports.SET_ROUTES = exports.SET_NAVIGATION_ITEMS = exports.SET_HELP_PATH = exports.SET_HEADER_NAVIGATION_ITEMS = exports.SET_FULLSCREEN_MODE = exports.SET_CONNECTIVITY_STATUS = exports.SET_ATTENTION_REQUIRED_BEACON = exports.SET_ADVANCED_MODE = exports.DEL_TOAST = exports.DEL_ALERT = exports.COLLAPSE_SIDEBAR = exports.CHANGE_CONFIG = exports.ADD_TOAST = exports.ADD_ALERT = exports.ACK_ALERT = void 0;
|
|
7
7
|
var ADD_ALERT = exports.ADD_ALERT = "asab/addAlert";
|
|
8
8
|
var ACK_ALERT = exports.ACK_ALERT = "asab/ackAlert";
|
|
9
9
|
var DEL_ALERT = exports.DEL_ALERT = "asab/delAlert";
|
|
@@ -18,4 +18,5 @@ var COLLAPSE_SIDEBAR = exports.COLLAPSE_SIDEBAR = "asab/collapseSidebar";
|
|
|
18
18
|
var SET_NAVIGATION_ITEMS = exports.SET_NAVIGATION_ITEMS = "asab/setNavigationItems";
|
|
19
19
|
var SET_ROUTES = exports.SET_ROUTES = "asab/setRoutes";
|
|
20
20
|
var SET_HEADER_NAVIGATION_ITEMS = exports.SET_HEADER_NAVIGATION_ITEMS = "asab/setHeaderNavigationItems";
|
|
21
|
+
var SET_CONNECTIVITY_STATUS = exports.SET_CONNECTIVITY_STATUS = "asab/setConnectivityStatus";
|
|
21
22
|
var SET_ATTENTION_REQUIRED_BEACON = exports.SET_ATTENTION_REQUIRED_BEACON = "asab/setAttentionRequiredBeacon";
|
|
@@ -80,6 +80,10 @@ class Application extends _react.Component {
|
|
|
80
80
|
// If more than zero, some networking activity is happening
|
|
81
81
|
splashscreenRequestors: 0
|
|
82
82
|
};
|
|
83
|
+
|
|
84
|
+
// Subscribe and unsubscribe handlers for connectivity detection
|
|
85
|
+
this._initConnectivitySubscription = this._initConnectivitySubscription.bind(this);
|
|
86
|
+
this._unsubscribeConnectivity = null;
|
|
83
87
|
this.ConfigService.addDefaults(props.configdefaults);
|
|
84
88
|
this.addSplashScreenRequestor(this);
|
|
85
89
|
this.state.splashscreenRequestors = this.SplashscreenRequestors.size;
|
|
@@ -442,6 +446,9 @@ class Application extends _react.Component {
|
|
|
442
446
|
componentDidMount() {
|
|
443
447
|
document.addEventListener("keyup", this._handleKeyUp, false);
|
|
444
448
|
|
|
449
|
+
// Subscribe to Application.status! once PubSub is available
|
|
450
|
+
this._initConnectivitySubscription();
|
|
451
|
+
|
|
445
452
|
// Add print-landscape class to body if not present
|
|
446
453
|
if (!document.body.classList.contains('print-landscape')) {
|
|
447
454
|
document.body.classList.add('print-landscape');
|
|
@@ -449,6 +456,12 @@ class Application extends _react.Component {
|
|
|
449
456
|
}
|
|
450
457
|
componentWillUnmount() {
|
|
451
458
|
document.removeEventListener("keyup", this._handleKeyUp, false);
|
|
459
|
+
|
|
460
|
+
// Unsubscribe from Application.status! PubSub
|
|
461
|
+
if (this._unsubscribeConnectivity) {
|
|
462
|
+
this._unsubscribeConnectivity();
|
|
463
|
+
this._unsubscribeConnectivity = null;
|
|
464
|
+
}
|
|
452
465
|
}
|
|
453
466
|
|
|
454
467
|
// Splash screen
|
|
@@ -648,4 +661,29 @@ class Application extends _react.Component {
|
|
|
648
661
|
}))));
|
|
649
662
|
}
|
|
650
663
|
}
|
|
664
|
+
|
|
665
|
+
/*
|
|
666
|
+
On Application initialization, initialize subscription to Application.status!
|
|
667
|
+
once PubSub is assigned by PubSubProvider
|
|
668
|
+
*/
|
|
669
|
+
Application.prototype._initConnectivitySubscription = function () {
|
|
670
|
+
if (this.PubSub && typeof this.PubSub.subscribe === 'function') {
|
|
671
|
+
if (!this._unsubscribeConnectivity) {
|
|
672
|
+
this._unsubscribeConnectivity = this.PubSub.subscribe('Application.status!', value => {
|
|
673
|
+
var _this$AppStore$dispat5, _this$AppStore5;
|
|
674
|
+
// Prefer store so UI updates predictably
|
|
675
|
+
(_this$AppStore$dispat5 = (_this$AppStore5 = this.AppStore).dispatch) === null || _this$AppStore$dispat5 === void 0 || _this$AppStore$dispat5.call(_this$AppStore5, {
|
|
676
|
+
type: _actions.SET_CONNECTIVITY_STATUS,
|
|
677
|
+
status: value.status
|
|
678
|
+
});
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
/*
|
|
684
|
+
This is a safety precaution which retry initialization, PubSubProvider may assigns app.PubSub
|
|
685
|
+
in its useEffect after first render (however we use useLayoutEffect there, so it should not be an issue).
|
|
686
|
+
*/
|
|
687
|
+
setTimeout(this._initConnectivitySubscription, 0);
|
|
688
|
+
};
|
|
651
689
|
var _default = exports.default = Application;
|
|
@@ -30,14 +30,10 @@ var SidebarItem = _ref => {
|
|
|
30
30
|
var _state$sidebar;
|
|
31
31
|
return (_state$sidebar = state.sidebar) === null || _state$sidebar === void 0 ? void 0 : _state$sidebar.isSidebarCollapsed;
|
|
32
32
|
});
|
|
33
|
-
var attentionRequired = (0, _asab_webui_components.useAppSelector)(state => {
|
|
34
|
-
var _state$attentionrequi;
|
|
35
|
-
return (_state$attentionrequi = state.attentionrequired) === null || _state$attentionrequi === void 0 ? void 0 : _state$attentionrequi.beacon;
|
|
36
|
-
});
|
|
37
33
|
var [isActive, setActive] = (0, _react.useState)(false);
|
|
38
34
|
var lowercasedItemName = item === null || item === void 0 || (_item$name = item.name) === null || _item$name === void 0 ? void 0 : _item$name.toLowerCase();
|
|
39
35
|
// Attention requred flag
|
|
40
|
-
var itemBeacon = beacon ? beacon["beacon.".concat(lowercasedItemName)] :
|
|
36
|
+
var itemBeacon = beacon ? beacon["beacon.".concat(lowercasedItemName)] : {};
|
|
41
37
|
(0, _react.useEffect)(() => {
|
|
42
38
|
// TODO: refactor the handling of active and open states, since it does not behave as expected in some cases
|
|
43
39
|
if (isOpen && !isActive) {
|
|
@@ -80,7 +76,8 @@ var SidebarCollapsibleItem = _ref2 => {
|
|
|
80
76
|
var {
|
|
81
77
|
item,
|
|
82
78
|
disabled,
|
|
83
|
-
isSmallResolution
|
|
79
|
+
isSmallResolution,
|
|
80
|
+
beacon = undefined
|
|
84
81
|
} = _ref2;
|
|
85
82
|
var [isOpen, setOpen] = (0, _react.useState)(false);
|
|
86
83
|
var location = (0, _reactRouter.useLocation)();
|
|
@@ -91,14 +88,10 @@ var SidebarCollapsibleItem = _ref2 => {
|
|
|
91
88
|
var _state$sidebar2;
|
|
92
89
|
return (_state$sidebar2 = state.sidebar) === null || _state$sidebar2 === void 0 ? void 0 : _state$sidebar2.isSidebarCollapsed;
|
|
93
90
|
});
|
|
94
|
-
var attentionRequired = (0, _asab_webui_components.useAppSelector)(state => {
|
|
95
|
-
var _state$attentionrequi2;
|
|
96
|
-
return (_state$attentionrequi2 = state.attentionrequired) === null || _state$attentionrequi2 === void 0 ? void 0 : _state$attentionrequi2.beacon;
|
|
97
|
-
});
|
|
98
91
|
var lowercasedItemName = item.name.toLowerCase();
|
|
99
92
|
|
|
100
93
|
// Attention required flag
|
|
101
|
-
var itemsBeacon = parentBeacon(
|
|
94
|
+
var itemsBeacon = parentBeacon(beacon, "beacon.".concat(lowercasedItemName), lowercasedItemName);
|
|
102
95
|
// Summarize parent beacon count based on children
|
|
103
96
|
var beaconCount = itemsBeacon && Object.keys(itemsBeacon).length > 0 ? Object.values(itemsBeacon).reduce((sum, current) => {
|
|
104
97
|
return sum + (current.count || 0); // Ensure we sum only valid count values
|
|
@@ -11,7 +11,8 @@ var SidebarItemRenderer = _ref => {
|
|
|
11
11
|
var {
|
|
12
12
|
sidebarItems,
|
|
13
13
|
sessionExpired,
|
|
14
|
-
isSmallResolution = undefined
|
|
14
|
+
isSmallResolution = undefined,
|
|
15
|
+
beacon = undefined
|
|
15
16
|
} = _ref;
|
|
16
17
|
return /*#__PURE__*/_react.default.createElement("nav", {
|
|
17
18
|
className: "nav flex-column"
|
|
@@ -19,12 +20,14 @@ var SidebarItemRenderer = _ref => {
|
|
|
19
20
|
key: idx,
|
|
20
21
|
item: item,
|
|
21
22
|
disabled: sessionExpired,
|
|
22
|
-
isSmallResolution: isSmallResolution
|
|
23
|
+
isSmallResolution: isSmallResolution,
|
|
24
|
+
beacon: beacon
|
|
23
25
|
}) : /*#__PURE__*/_react.default.createElement(_SidebarItem.SidebarItem, {
|
|
24
26
|
key: idx,
|
|
25
27
|
item: item,
|
|
26
28
|
disabled: sessionExpired,
|
|
27
|
-
isSmallResolution: isSmallResolution
|
|
29
|
+
isSmallResolution: isSmallResolution,
|
|
30
|
+
beacon: beacon
|
|
28
31
|
})));
|
|
29
32
|
};
|
|
30
33
|
exports.SidebarItemRenderer = SidebarItemRenderer;
|
|
@@ -53,6 +53,11 @@ function Sidebar(props) {
|
|
|
53
53
|
return (_state$auth = state.auth) === null || _state$auth === void 0 ? void 0 : _state$auth.sessionExpired;
|
|
54
54
|
});
|
|
55
55
|
var theme = (0, _asab_webui_components.useAppSelector)(state => state.theme);
|
|
56
|
+
// Subscription to a beacon
|
|
57
|
+
var beacon = (0, _asab_webui_components.useAppSelector)(state => {
|
|
58
|
+
var _state$attentionrequi;
|
|
59
|
+
return state === null || state === void 0 || (_state$attentionrequi = state.attentionrequired) === null || _state$attentionrequi === void 0 ? void 0 : _state$attentionrequi.beacon;
|
|
60
|
+
});
|
|
56
61
|
var {
|
|
57
62
|
dispatch
|
|
58
63
|
} = (0, _asab_webui_components.useAppStore)();
|
|
@@ -98,13 +103,15 @@ function Sidebar(props) {
|
|
|
98
103
|
}, /*#__PURE__*/_react.default.createElement(_SidebarItemRenderer.SidebarItemRenderer, {
|
|
99
104
|
sidebarItems: sidebarItems,
|
|
100
105
|
sessionExpired: sessionExpired,
|
|
101
|
-
isSmallResolution: isSmallResolution
|
|
106
|
+
isSmallResolution: isSmallResolution,
|
|
107
|
+
beacon: beacon
|
|
102
108
|
})))) : /*#__PURE__*/_react.default.createElement("div", {
|
|
103
109
|
className: "h-100",
|
|
104
110
|
id: "app-sidebar"
|
|
105
111
|
}, /*#__PURE__*/_react.default.createElement(_SidebarItemRenderer.SidebarItemRenderer, {
|
|
106
112
|
sidebarItems: sidebarItems,
|
|
107
|
-
sessionExpired: sessionExpired
|
|
113
|
+
sessionExpired: sessionExpired,
|
|
114
|
+
beacon: beacon
|
|
108
115
|
}), /*#__PURE__*/_react.default.createElement("div", {
|
|
109
116
|
className: "flex-fill"
|
|
110
117
|
}, "\xA0"), /*#__PURE__*/_react.default.createElement(_SidebarBottomItem.default, {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.OfflineIndication = OfflineIndication;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _reactI18next = require("react-i18next");
|
|
10
|
+
// Header badge for displaying offline status
|
|
11
|
+
function OfflineIndication() {
|
|
12
|
+
var {
|
|
13
|
+
t
|
|
14
|
+
} = (0, _reactI18next.useTranslation)();
|
|
15
|
+
return /*#__PURE__*/_react.default.createElement("i", {
|
|
16
|
+
title: t('General|You are offline. Functionality of the Application may be limited.'),
|
|
17
|
+
className: "bi bi-wifi-off mx-3",
|
|
18
|
+
style: {
|
|
19
|
+
fontSize: '16px'
|
|
20
|
+
} // Align with fontsize of navitems of Header
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
|
|
4
|
+
// Header badge for displaying offline status
|
|
5
|
+
export function OfflineIndication() {
|
|
6
|
+
const { t } = useTranslation();
|
|
7
|
+
|
|
8
|
+
return <i
|
|
9
|
+
title={t('General|You are offline. Functionality of the Application may be limited.')}
|
|
10
|
+
className='bi bi-wifi-off mx-3'
|
|
11
|
+
style={{ fontSize: '16px' }} // Align with fontsize of navitems of Header
|
|
12
|
+
/>
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = connectivityReducer;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _actions = require("../../actions");
|
|
10
|
+
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; }
|
|
11
|
+
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; }
|
|
12
|
+
var initialState = {
|
|
13
|
+
status: null
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Reducer for connectivity status
|
|
17
|
+
function connectivityReducer() {
|
|
18
|
+
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState;
|
|
19
|
+
var action = arguments.length > 1 ? arguments[1] : undefined;
|
|
20
|
+
switch (action.type) {
|
|
21
|
+
case _actions.SET_CONNECTIVITY_STATUS:
|
|
22
|
+
{
|
|
23
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
24
|
+
status: action.status
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
default:
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SET_CONNECTIVITY_STATUS } from "../../actions";
|
|
2
|
+
|
|
3
|
+
const initialState = {
|
|
4
|
+
status: null
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// Reducer for connectivity status
|
|
8
|
+
export default function connectivityReducer(state = initialState, action) {
|
|
9
|
+
switch (action.type) {
|
|
10
|
+
case SET_CONNECTIVITY_STATUS: {
|
|
11
|
+
return {
|
|
12
|
+
...state,
|
|
13
|
+
status: action.status
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
default:
|
|
18
|
+
return state;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -8,14 +8,16 @@ exports.default = void 0;
|
|
|
8
8
|
var _react = _interopRequireDefault(require("react"));
|
|
9
9
|
var _asab_webui_components = require("asab_webui_components");
|
|
10
10
|
var _service = _interopRequireDefault(require("./service.js"));
|
|
11
|
-
var
|
|
11
|
+
var _connectivityReducer = _interopRequireDefault(require("./connectivityReducer.js"));
|
|
12
|
+
var _attentionRequiredReducer = _interopRequireDefault(require("./attentionRequiredReducer.js"));
|
|
12
13
|
class AttentionRequiredModule extends _asab_webui_components.Module {
|
|
13
14
|
constructor(app) {
|
|
14
15
|
var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "AttentionRequiredModule";
|
|
15
16
|
super(app, name);
|
|
16
17
|
this.App = app;
|
|
17
18
|
this.AttentionRequiredService = new _service.default(app, "AttentionRequiredService");
|
|
18
|
-
this.App.ReduxService.addReducer("attentionrequired",
|
|
19
|
+
this.App.ReduxService.addReducer("attentionrequired", _attentionRequiredReducer.default);
|
|
20
|
+
this.App.ReduxService.addReducer("connectivity", _connectivityReducer.default);
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
exports.default = AttentionRequiredModule;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Module } from 'asab_webui_components';
|
|
3
3
|
import AttentionRequiredService from './service.jsx';
|
|
4
|
-
import
|
|
4
|
+
import connectivityReducer from './connectivityReducer.jsx';
|
|
5
|
+
import attentionRequiredReducer from './attentionRequiredReducer.jsx';
|
|
5
6
|
|
|
6
7
|
export default class AttentionRequiredModule extends Module {
|
|
7
8
|
|
|
@@ -11,7 +12,8 @@ export default class AttentionRequiredModule extends Module {
|
|
|
11
12
|
|
|
12
13
|
this.AttentionRequiredService = new AttentionRequiredService(app, "AttentionRequiredService");
|
|
13
14
|
|
|
14
|
-
this.App.ReduxService.addReducer("attentionrequired",
|
|
15
|
+
this.App.ReduxService.addReducer("attentionrequired", attentionRequiredReducer);
|
|
16
|
+
this.App.ReduxService.addReducer("connectivity", connectivityReducer);
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
}
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _asab_webui_components = require("asab_webui_components");
|
|
8
8
|
var _actions = require("../../actions");
|
|
9
|
+
var _OfflineIndication = require("./components/OfflineIndication.js");
|
|
9
10
|
// Service handling attention required
|
|
10
11
|
class AttentionRequiredService extends _asab_webui_components.Service {
|
|
11
12
|
constructor(app) {
|
|
@@ -14,6 +15,8 @@ class AttentionRequiredService extends _asab_webui_components.Service {
|
|
|
14
15
|
this.beaconWebSocket = null; // beacon websocket variable
|
|
15
16
|
this.reconnectTimeout = null; // timeout variable
|
|
16
17
|
this.reconnectInterval = 5000; // initial reconnection interval (5 seconds)
|
|
18
|
+
this.prevStatus = null; // initial status
|
|
19
|
+
this.prevBeacon = null; // initial beacon
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
// Start beacon websocket connection on initialization
|
|
@@ -28,6 +31,7 @@ class AttentionRequiredService extends _asab_webui_components.Service {
|
|
|
28
31
|
var currentTenant = (_this$App = this.App) === null || _this$App === void 0 || (_this$App = _this$App.Services) === null || _this$App === void 0 || (_this$App = _this$App.TenantService) === null || _this$App === void 0 ? void 0 : _this$App.getCurrentTenant();
|
|
29
32
|
// Gracefully reconnect if tenant was not found
|
|
30
33
|
if (!currentTenant) {
|
|
34
|
+
// TODO: maybe set offline
|
|
31
35
|
console.error("Beacon WebSocket error: Tenant was not found!");
|
|
32
36
|
this.reconnectBeaconWebSocket();
|
|
33
37
|
return;
|
|
@@ -35,7 +39,7 @@ class AttentionRequiredService extends _asab_webui_components.Service {
|
|
|
35
39
|
var BeaconServiceClient = this.App.createWebSocket('asab-remote-control', "/beacon/".concat(currentTenant, "/ws"));
|
|
36
40
|
this.beaconWebSocket = BeaconServiceClient;
|
|
37
41
|
this.beaconWebSocket.onopen = () => {
|
|
38
|
-
|
|
42
|
+
this.connectionStatus('online');
|
|
39
43
|
console.log('Beacon WebSocket connection established.');
|
|
40
44
|
};
|
|
41
45
|
this.beaconWebSocket.onmessage = message => {
|
|
@@ -51,10 +55,12 @@ class AttentionRequiredService extends _asab_webui_components.Service {
|
|
|
51
55
|
this.beaconWebSocket.onerror = error => {
|
|
52
56
|
console.error("Beacon WebSocket error:", error);
|
|
53
57
|
console.error("Beacon WebSocket is attempting to reconnect...");
|
|
58
|
+
this.connectionStatus('offline');
|
|
54
59
|
this.distributeData({});
|
|
55
60
|
this.reconnectBeaconWebSocket();
|
|
56
61
|
};
|
|
57
62
|
this.beaconWebSocket.onclose = () => {
|
|
63
|
+
this.connectionStatus('offline');
|
|
58
64
|
/*
|
|
59
65
|
WebSocket connection is closed by the browser automatically when user
|
|
60
66
|
leaves the application (not the screen).
|
|
@@ -99,13 +105,24 @@ class AttentionRequiredService extends _asab_webui_components.Service {
|
|
|
99
105
|
|
|
100
106
|
// Method for distributing the data into Application store
|
|
101
107
|
distributeData(data) {
|
|
102
|
-
var
|
|
103
|
-
var
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
var next = this.transformData(data);
|
|
109
|
+
var initial = this.prevBeacon === null;
|
|
110
|
+
var nextEmpty = _isEmptyObject(next);
|
|
111
|
+
var prevEmpty = _isEmptyObject(this.prevBeacon);
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
We dont want to repetitivelly dispatch empty beacons to the AppStore
|
|
115
|
+
because it is causing unwanted re-rendering of the Application
|
|
116
|
+
*/
|
|
117
|
+
if (initial || !nextEmpty || nextEmpty && !prevEmpty) {
|
|
118
|
+
var _this$App2, _this$App2$dispatch;
|
|
119
|
+
(_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, {
|
|
120
|
+
type: _actions.SET_ATTENTION_REQUIRED_BEACON,
|
|
121
|
+
beacon: next
|
|
122
|
+
});
|
|
123
|
+
// Update previous snapshot after dispatch
|
|
124
|
+
this.prevBeacon = next;
|
|
125
|
+
}
|
|
109
126
|
}
|
|
110
127
|
|
|
111
128
|
// Transform and group beacon data
|
|
@@ -142,5 +159,35 @@ class AttentionRequiredService extends _asab_webui_components.Service {
|
|
|
142
159
|
return acc;
|
|
143
160
|
}, {});
|
|
144
161
|
}
|
|
162
|
+
// Method for publishing the connection status and displaying offline indication
|
|
163
|
+
connectionStatus(status) {
|
|
164
|
+
var _this$App3;
|
|
165
|
+
if ((_this$App3 = this.App) !== null && _this$App3 !== void 0 && _this$App3.PubSub) {
|
|
166
|
+
var _this$App4, _this$App5;
|
|
167
|
+
// Distribute status
|
|
168
|
+
(_this$App4 = this.App) === null || _this$App4 === void 0 || (_this$App4 = _this$App4.PubSub) === null || _this$App4 === void 0 || _this$App4.publish('Application.status!', {
|
|
169
|
+
status
|
|
170
|
+
});
|
|
171
|
+
var headerService = (_this$App5 = this.App) === null || _this$App5 === void 0 || (_this$App5 = _this$App5.Services) === null || _this$App5 === void 0 ? void 0 : _this$App5.HeaderService;
|
|
172
|
+
if (headerService) {
|
|
173
|
+
if (this.prevStatus != status) {
|
|
174
|
+
if (status === 'offline') {
|
|
175
|
+
headerService === null || headerService === void 0 || headerService.addComponent({
|
|
176
|
+
component: _OfflineIndication.OfflineIndication,
|
|
177
|
+
order: 100
|
|
178
|
+
});
|
|
179
|
+
} else {
|
|
180
|
+
headerService === null || headerService === void 0 || headerService.removeComponent(_OfflineIndication.OfflineIndication);
|
|
181
|
+
}
|
|
182
|
+
this.prevStatus = status;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
145
187
|
}
|
|
146
|
-
|
|
188
|
+
|
|
189
|
+
// Method for identifying an empty object
|
|
190
|
+
exports.default = AttentionRequiredService;
|
|
191
|
+
function _isEmptyObject(o) {
|
|
192
|
+
return o != null && typeof o === 'object' && Object.keys(o).length === 0;
|
|
193
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Service } from 'asab_webui_components';
|
|
2
2
|
import { SET_ATTENTION_REQUIRED_BEACON } from '../../actions';
|
|
3
|
+
import { OfflineIndication } from './components/OfflineIndication.jsx';
|
|
3
4
|
|
|
4
5
|
// Service handling attention required
|
|
5
6
|
export default class AttentionRequiredService extends Service {
|
|
@@ -9,6 +10,8 @@ export default class AttentionRequiredService extends Service {
|
|
|
9
10
|
this.beaconWebSocket = null; // beacon websocket variable
|
|
10
11
|
this.reconnectTimeout = null; // timeout variable
|
|
11
12
|
this.reconnectInterval = 5000; // initial reconnection interval (5 seconds)
|
|
13
|
+
this.prevStatus = null; // initial status
|
|
14
|
+
this.prevBeacon = null; // initial beacon
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
// Start beacon websocket connection on initialization
|
|
@@ -22,6 +25,7 @@ export default class AttentionRequiredService extends Service {
|
|
|
22
25
|
const currentTenant = this.App?.Services?.TenantService?.getCurrentTenant();
|
|
23
26
|
// Gracefully reconnect if tenant was not found
|
|
24
27
|
if (!currentTenant) {
|
|
28
|
+
// TODO: maybe set offline
|
|
25
29
|
console.error("Beacon WebSocket error: Tenant was not found!");
|
|
26
30
|
this.reconnectBeaconWebSocket();
|
|
27
31
|
return;
|
|
@@ -31,7 +35,7 @@ export default class AttentionRequiredService extends Service {
|
|
|
31
35
|
this.beaconWebSocket = BeaconServiceClient;
|
|
32
36
|
|
|
33
37
|
this.beaconWebSocket.onopen = () => {
|
|
34
|
-
|
|
38
|
+
this.connectionStatus('online');
|
|
35
39
|
console.log('Beacon WebSocket connection established.');
|
|
36
40
|
};
|
|
37
41
|
|
|
@@ -49,11 +53,13 @@ export default class AttentionRequiredService extends Service {
|
|
|
49
53
|
this.beaconWebSocket.onerror = (error) => {
|
|
50
54
|
console.error("Beacon WebSocket error:", error);
|
|
51
55
|
console.error("Beacon WebSocket is attempting to reconnect...");
|
|
56
|
+
this.connectionStatus('offline');
|
|
52
57
|
this.distributeData({});
|
|
53
58
|
this.reconnectBeaconWebSocket();
|
|
54
59
|
};
|
|
55
60
|
|
|
56
61
|
this.beaconWebSocket.onclose = () => {
|
|
62
|
+
this.connectionStatus('offline');
|
|
57
63
|
/*
|
|
58
64
|
WebSocket connection is closed by the browser automatically when user
|
|
59
65
|
leaves the application (not the screen).
|
|
@@ -99,9 +105,23 @@ export default class AttentionRequiredService extends Service {
|
|
|
99
105
|
|
|
100
106
|
// Method for distributing the data into Application store
|
|
101
107
|
distributeData(data) {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
const next = this.transformData(data);
|
|
109
|
+
const initial = (this.prevBeacon === null);
|
|
110
|
+
const nextEmpty = _isEmptyObject(next);
|
|
111
|
+
const prevEmpty = _isEmptyObject(this.prevBeacon);
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
We dont want to repetitivelly dispatch empty beacons to the AppStore
|
|
115
|
+
because it is causing unwanted re-rendering of the Application
|
|
116
|
+
*/
|
|
117
|
+
if (initial || !nextEmpty || (nextEmpty && !prevEmpty)) {
|
|
118
|
+
this.App?.AppStore?.dispatch?.({
|
|
119
|
+
type: SET_ATTENTION_REQUIRED_BEACON,
|
|
120
|
+
beacon: next,
|
|
121
|
+
});
|
|
122
|
+
// Update previous snapshot after dispatch
|
|
123
|
+
this.prevBeacon = next;
|
|
124
|
+
}
|
|
105
125
|
}
|
|
106
126
|
|
|
107
127
|
// Transform and group beacon data
|
|
@@ -138,4 +158,32 @@ export default class AttentionRequiredService extends Service {
|
|
|
138
158
|
return acc;
|
|
139
159
|
}, {});
|
|
140
160
|
};
|
|
161
|
+
|
|
162
|
+
// Method for publishing the connection status and displaying offline indication
|
|
163
|
+
connectionStatus(status) {
|
|
164
|
+
if (this.App?.PubSub) {
|
|
165
|
+
// Distribute status
|
|
166
|
+
this.App?.PubSub?.publish('Application.status!', { status });
|
|
167
|
+
const headerService = this.App?.Services?.HeaderService;
|
|
168
|
+
if (headerService) {
|
|
169
|
+
if (this.prevStatus != status) {
|
|
170
|
+
if (status === 'offline') {
|
|
171
|
+
headerService?.addComponent({
|
|
172
|
+
component: OfflineIndication,
|
|
173
|
+
order: 100
|
|
174
|
+
});
|
|
175
|
+
} else {
|
|
176
|
+
headerService?.removeComponent(OfflineIndication);
|
|
177
|
+
}
|
|
178
|
+
this.prevStatus = status;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Method for identifying an empty object
|
|
187
|
+
function _isEmptyObject(o) {
|
|
188
|
+
return o != null && typeof o === 'object' && Object.keys(o).length === 0;
|
|
141
189
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asab_webui_shell",
|
|
3
|
-
"version": "27.1
|
|
3
|
+
"version": "27.2.1",
|
|
4
4
|
"license": "BSD-3-Clause",
|
|
5
5
|
"description": "TeskaLabs ASAB WebUI Shell Application",
|
|
6
6
|
"contributors": [
|
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
"rimraf": "^6.0.1"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"asab_webui_components": "^27.
|
|
42
|
+
"asab_webui_components": "^27.3.1",
|
|
43
43
|
"@babel/runtime": "^7.22.11",
|
|
44
44
|
"react": "^19.0.0",
|
|
45
45
|
"react-dom": "^19.0.0",
|
|
46
46
|
"axios": "^1.8.4",
|
|
47
|
-
"i18next": "^25.
|
|
48
|
-
"react-i18next": "^
|
|
47
|
+
"i18next": "^25.5.2",
|
|
48
|
+
"react-i18next": "^16.0.0",
|
|
49
49
|
"react-router": "^7.8.2",
|
|
50
50
|
"reactstrap": "^9.2.0"
|
|
51
51
|
},
|
|
File without changes
|
|
File without changes
|