@openremote/or-app 1.8.0-snapshot.20250725074716 → 1.8.0-snapshot.20250725120001
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/README.md +87 -87
- package/images/logo-mobile.svg +7 -7
- package/images/logo.svg +15 -15
- package/lib/app.js +38 -1
- package/lib/index.js +538 -67
- package/lib/or-header.js +496 -298
- package/lib/page-offline.js +109 -49
- package/lib/types.js +25 -1
- package/package.json +16 -16
- package/typedoc.js +2 -2
package/lib/index.js
CHANGED
|
@@ -1,76 +1,547 @@
|
|
|
1
|
-
var __decorate
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
import { css, html, LitElement, unsafeCSS } from "lit";
|
|
17
|
+
import { customElement, property, query, state } from "lit/decorators.js";
|
|
18
|
+
import { router } from "./types";
|
|
19
|
+
import "@openremote/or-translate";
|
|
20
|
+
import "@openremote/or-mwc-components/or-mwc-menu";
|
|
21
|
+
import "@openremote/or-mwc-components/or-mwc-snackbar";
|
|
22
|
+
import "./or-header";
|
|
23
|
+
import "@openremote/or-icon";
|
|
24
|
+
import { updateMetadata } from "pwa-helpers/metadata";
|
|
25
|
+
import i18next from "i18next";
|
|
26
|
+
import manager, { DefaultColor2, DefaultColor3, DefaultColor4, normaliseConfig, ORError, OREvent, Util } from "@openremote/core";
|
|
27
|
+
import { DEFAULT_LANGUAGES } from "./or-header";
|
|
28
|
+
import { OrMwcDialog, showDialog, showErrorDialog } from "@openremote/or-mwc-components/or-mwc-dialog";
|
|
29
|
+
import { OrMwcSnackbar } from "@openremote/or-mwc-components/or-mwc-snackbar";
|
|
30
|
+
import { setOffline, setVisibility, updatePage, updateRealm } from "./app";
|
|
31
|
+
import { InputType } from "@openremote/or-mwc-components/or-mwc-input";
|
|
32
|
+
import { pageOfflineProvider } from "./page-offline";
|
|
33
|
+
export const DefaultLogo = require("../images/logo.svg");
|
|
34
|
+
export const DefaultMobileLogo = require("../images/logo-mobile.svg");
|
|
35
|
+
export const DefaultFavIcon = require("../images/favicon.ico");
|
|
36
|
+
export * from "./app";
|
|
37
|
+
export * from "./or-header";
|
|
38
|
+
export * from "./types";
|
|
39
|
+
export { DEFAULT_LANGUAGES };
|
|
40
|
+
export function getDefaultManagerConfig() {
|
|
41
|
+
return normaliseConfig(DEFAULT_MANAGER_CONFIG);
|
|
42
|
+
}
|
|
43
|
+
const DEFAULT_MANAGER_CONFIG = {
|
|
44
|
+
managerUrl: (MANAGER_URL || ""),
|
|
45
|
+
keycloakUrl: (KEYCLOAK_URL || ""),
|
|
46
|
+
auth: "KEYCLOAK" /* Auth.KEYCLOAK */,
|
|
47
|
+
autoLogin: true,
|
|
48
|
+
realm: undefined,
|
|
49
|
+
consoleAutoEnable: true,
|
|
50
|
+
loadTranslations: ["or"]
|
|
51
|
+
};
|
|
52
|
+
let OrApp = class OrApp extends LitElement {
|
|
53
|
+
// language=CSS
|
|
54
|
+
static get styles() {
|
|
55
|
+
return css `
|
|
56
|
+
:host {
|
|
57
|
+
--or-app-color2: ${unsafeCSS(DefaultColor2)};
|
|
58
|
+
--or-app-color3: ${unsafeCSS(DefaultColor3)};
|
|
59
|
+
--or-app-color4: ${unsafeCSS(DefaultColor4)};
|
|
60
|
+
--or-console-primary-color: #4D9D2A;
|
|
61
|
+
color: ${unsafeCSS(DefaultColor3)};
|
|
62
|
+
fill: ${unsafeCSS(DefaultColor3)};
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
|
|
65
|
+
height: 100vh; /* Fallback */
|
|
66
|
+
height: 100dvh; /* Stretch to dynamic viewport height */
|
|
67
|
+
display: flex;
|
|
68
|
+
flex: 1;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.main-content {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex: 1;
|
|
75
|
+
box-sizing: border-box;
|
|
76
|
+
background-color: var(--or-app-color2);
|
|
77
|
+
overflow: auto;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.no-scroll {
|
|
81
|
+
overflow: hidden;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
main > * {
|
|
85
|
+
display: flex;
|
|
86
|
+
flex: 1;
|
|
87
|
+
position: relative;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.desktop-hidden {
|
|
91
|
+
display: none !important;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media only screen and (max-width: 780px) {
|
|
95
|
+
.desktop-hidden {
|
|
96
|
+
display: inline-block !important;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* HEADER STYLES */
|
|
101
|
+
or-header a > or-icon {
|
|
102
|
+
margin-right: 10px;
|
|
103
|
+
}
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
constructor(store) {
|
|
107
|
+
super();
|
|
108
|
+
this._initialised = false;
|
|
109
|
+
this._offline = false;
|
|
110
|
+
this._showOfflineFallback = false;
|
|
111
|
+
this._onEvent = (ev) => this._handleEvent(ev);
|
|
112
|
+
this._onVisibilityChanged = (ev) => this._handleVisibilityChange(ev);
|
|
113
|
+
this._store = store;
|
|
114
|
+
// Set this element as the host for dialogs
|
|
115
|
+
OrMwcDialog.DialogHostElement = this;
|
|
116
|
+
OrMwcSnackbar.DialogHostElement = this;
|
|
117
|
+
}
|
|
118
|
+
getState() {
|
|
119
|
+
return this._store.getState();
|
|
120
|
+
}
|
|
121
|
+
// Using HTML 'visibilitychange' listener to see whether the Manager is visible for the user.
|
|
122
|
+
// TODO; Add an ConsoleProvider that listens to background/foreground changes, and dispatch the respective OREvent. This will improve responsiveness of logic attached to it.
|
|
123
|
+
// For example used for triggering reconnecting logic once the UI becomes visible again.
|
|
124
|
+
_handleVisibilityChange(ev) {
|
|
125
|
+
var _a;
|
|
126
|
+
if (document.visibilityState === "visible") {
|
|
127
|
+
this._store.dispatch((setVisibility(true)));
|
|
128
|
+
// When the manager appears on Mobile devices, but the connection is OFFLINE,
|
|
129
|
+
// we reset the timer to the {appConfig.offlineTimeout} seconds. This is because we saw issues with reopening the app,
|
|
130
|
+
// and seeing a connection interval of 30+ seconds. We now give the user the benefit of the doubt, by resetting the timer.
|
|
131
|
+
if (((_a = manager.console) === null || _a === void 0 ? void 0 : _a.isMobile) && this._offline) {
|
|
132
|
+
this._startOfflineFallbackTimer(true);
|
|
16
133
|
}
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
134
|
+
// Always try reconnecting (just in case we are disconnected)
|
|
135
|
+
manager.reconnect();
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
this._store.dispatch((setVisibility(false)));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
connectedCallback() {
|
|
142
|
+
super.connectedCallback();
|
|
143
|
+
this._storeUnsubscribe = this._store.subscribe(() => this.stateChanged(this.getState()));
|
|
144
|
+
document.addEventListener("visibilitychange", this._onVisibilityChanged);
|
|
145
|
+
this.stateChanged(this.getState());
|
|
146
|
+
}
|
|
147
|
+
disconnectedCallback() {
|
|
148
|
+
this._storeUnsubscribe();
|
|
149
|
+
document.removeEventListener("visibilityChange", this._onVisibilityChanged);
|
|
150
|
+
manager.removeListener(this._onEvent);
|
|
151
|
+
super.disconnectedCallback();
|
|
152
|
+
}
|
|
153
|
+
firstUpdated(_changedProperties) {
|
|
154
|
+
super.firstUpdated(_changedProperties);
|
|
155
|
+
const managerConfig = this.managerConfig ? Object.assign(Object.assign({}, DEFAULT_MANAGER_CONFIG), this.managerConfig) : DEFAULT_MANAGER_CONFIG;
|
|
156
|
+
if (!managerConfig.realm) {
|
|
157
|
+
// Use realm query parameter if no specific realm provided
|
|
158
|
+
managerConfig.realm = Util.getQueryParameter("realm");
|
|
159
|
+
}
|
|
160
|
+
if (!managerConfig.defaultLanguage) {
|
|
161
|
+
managerConfig.defaultLanguage = Util.getBrowserLanguage();
|
|
162
|
+
}
|
|
163
|
+
managerConfig.skipFallbackToBasicAuth = true; // We do this so we can load styling config before displaying basic login
|
|
164
|
+
managerConfig.basicLoginProvider = (u, p) => this.doBasicLogin(u, p);
|
|
165
|
+
console.info("Initialising the manager");
|
|
166
|
+
manager.init(managerConfig).then((success) => __awaiter(this, void 0, void 0, function* () {
|
|
167
|
+
if (!success && manager.error === ORError.AUTH_FAILED && (!managerConfig.auth || managerConfig.auth === "KEYCLOAK" /* Auth.KEYCLOAK */)) {
|
|
168
|
+
this.doAppConfigInit();
|
|
169
|
+
// Fallback to basic auth now styling is loaded
|
|
170
|
+
managerConfig.auth = "BASIC" /* Auth.BASIC */;
|
|
171
|
+
success = yield manager.init(managerConfig);
|
|
24
172
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
173
|
+
if (success) {
|
|
174
|
+
this.doAppConfigInit();
|
|
175
|
+
if (!this.appConfig) {
|
|
176
|
+
showErrorDialog("appError.noConfig", document.body);
|
|
177
|
+
console.error("No AppConfig supplied");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (!this._config) {
|
|
181
|
+
showErrorDialog("appError.noConfig", document.body);
|
|
182
|
+
console.error("No default AppConfig or realm specific config provided so cannot render");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (!this._store) {
|
|
186
|
+
showErrorDialog("appError.noReduxStore", document.body);
|
|
187
|
+
console.error("No Redux store supplied");
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (!this.appConfig.pages || Object.keys(this.appConfig.pages).length === 0) {
|
|
191
|
+
showErrorDialog("appError.noPages", document.body);
|
|
192
|
+
console.error("No page providers");
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
// Load available realm info
|
|
196
|
+
const response = yield manager.rest.api.RealmResource.getAccessible();
|
|
197
|
+
this._realms = response.data;
|
|
198
|
+
let realm = undefined;
|
|
199
|
+
// Set current display realm if super user
|
|
200
|
+
if (manager.isSuperUser()) {
|
|
201
|
+
// Look in session storage
|
|
202
|
+
realm = window.sessionStorage.getItem("realm");
|
|
203
|
+
if (realm && !this._realms.some(r => r.name === realm)) {
|
|
204
|
+
realm = undefined;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
this._store.dispatch(updateRealm(realm || manager.getRealm() || "master"));
|
|
208
|
+
this._initialised = true;
|
|
209
|
+
// Register listener to change global state based on certain events
|
|
210
|
+
manager.addListener(this._onEvent);
|
|
211
|
+
// Create route listener to set header active item (this must be done before any routes added)
|
|
212
|
+
const headerUpdater = (activeMenu) => {
|
|
213
|
+
this._activeMenu = activeMenu;
|
|
214
|
+
};
|
|
215
|
+
router.hooks({
|
|
216
|
+
before(done, match) {
|
|
217
|
+
headerUpdater(match ? match.url.split('/')[0] : undefined);
|
|
218
|
+
done();
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// Configure routes
|
|
222
|
+
this.appConfig.pages.forEach((pageProvider, index) => {
|
|
223
|
+
if (pageProvider.routes) {
|
|
224
|
+
pageProvider.routes.forEach((route) => {
|
|
225
|
+
router.on(route, (match) => {
|
|
226
|
+
this._store.dispatch(updatePage({ page: pageProvider.name, params: match.data }));
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
if (this.appConfig.pages.length > 0) {
|
|
232
|
+
router.notFound(() => {
|
|
233
|
+
this._store.dispatch(updatePage(this.appConfig.pages[0].name));
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
router.resolve();
|
|
34
237
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
display: none !important;
|
|
238
|
+
else {
|
|
239
|
+
showErrorDialog(manager.isError ? "managerError." + manager.error : "");
|
|
38
240
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
updated(changedProps) {
|
|
244
|
+
var _a, _b;
|
|
245
|
+
super.updated(changedProps);
|
|
246
|
+
if (!this._initialised) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// If either page or 'offline'-status is changed, it should update to the correct page,
|
|
250
|
+
// by appending the page to the HTML content
|
|
251
|
+
if (changedProps.has("_page") || changedProps.has("_offline") || changedProps.has("_showOfflineFallback")) {
|
|
252
|
+
if (this._mainElem) {
|
|
253
|
+
const pageProvider = this.appConfig.pages.find((page) => page.name === this._page);
|
|
254
|
+
const showOfflineFallback = (this._showOfflineFallback && !(pageProvider === null || pageProvider === void 0 ? void 0 : pageProvider.allowOffline));
|
|
255
|
+
const offlinePage = this._mainElem.querySelector('#offline-page');
|
|
256
|
+
// If page has changed, replace the previous content with the new page.
|
|
257
|
+
// However, if no page is present yet, append it to the page.
|
|
258
|
+
if (changedProps.has('_page') && pageProvider) {
|
|
259
|
+
const currentPage = this._mainElem.firstElementChild;
|
|
260
|
+
if (currentPage) {
|
|
261
|
+
const newPage = pageProvider.pageCreator();
|
|
262
|
+
if (showOfflineFallback) {
|
|
263
|
+
newPage.style.setProperty('display', 'none'); // hide the new page while offline overlay page is shown
|
|
264
|
+
newPage.setAttribute('loadedDuringOffline', 'true'); // mark the page as "loaded during offline", since the content is either empty or invalid
|
|
265
|
+
}
|
|
266
|
+
this._mainElem.replaceChild(newPage, currentPage); // replace content
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
this._mainElem.appendChild(pageProvider.pageCreator());
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// CASE: "Offline overlay page is present, but should not be shown"
|
|
273
|
+
if (offlinePage && !showOfflineFallback) {
|
|
274
|
+
this._mainElem.removeChild(offlinePage); // remove offline overlay
|
|
275
|
+
const elem = this._mainElem.firstElementChild;
|
|
276
|
+
elem === null || elem === void 0 ? void 0 : elem.style.removeProperty('display'); // show the current page again (back to the foreground)
|
|
277
|
+
if (elem === null || elem === void 0 ? void 0 : elem.onRefresh) {
|
|
278
|
+
elem.onRefresh(); // If custom onRefresh() is set by the page, run that function.
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// CASE: "Offline overlay page is NOT present, but needs to be there"
|
|
282
|
+
// It either shows the default offline fallback page, or a custom one defined in the AppConfig.
|
|
283
|
+
else if (!offlinePage && showOfflineFallback) {
|
|
284
|
+
const newOfflinePage = ((_a = this.appConfig) === null || _a === void 0 ? void 0 : _a.offlinePage) ? this.appConfig.offlinePage.pageCreator() : pageOfflineProvider(this._store).pageCreator();
|
|
285
|
+
(_b = this._mainElem.firstElementChild) === null || _b === void 0 ? void 0 : _b.style.setProperty('display', 'none'); // Hide the current page (to the background)
|
|
286
|
+
newOfflinePage.id = "offline-page";
|
|
287
|
+
this._mainElem.appendChild(newOfflinePage);
|
|
43
288
|
}
|
|
44
289
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
290
|
+
this.updateWindowTitle();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
shouldUpdate(changedProps) {
|
|
294
|
+
var _a, _b;
|
|
295
|
+
if (changedProps.has("_realm")) {
|
|
296
|
+
this._config = this._getConfig();
|
|
297
|
+
if (this._realm) {
|
|
298
|
+
manager.displayRealm = this._realm;
|
|
299
|
+
window.sessionStorage.setItem("realm", this._realm);
|
|
49
300
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
${e}
|
|
53
|
-
${this._config.header?i`
|
|
54
|
-
<or-header .activeMenu="${this._activeMenu}" .store="${this._store}" .realm="${this._realm}" .realms="${this._realms}" .logo="${this._config.logo}" .logoMobile="${this._config.logoMobile}" .config="${this._config.header}"></or-header>
|
|
55
|
-
`:""}
|
|
56
|
-
|
|
57
|
-
<!-- Main content -->
|
|
58
|
-
<main role="main" class="main-content d-none"></main>
|
|
59
|
-
|
|
60
|
-
<slot></slot>
|
|
61
|
-
`}stateChanged(e){this._realm=e.app.realm,this._page=e.app.page,this._offline=e.app.offline}_handleEvent(e){e===u.OFFLINE?(this._offline||this._store.dispatch(A(!0)),this._startOfflineFallbackTimer()):e===u.ONLINE&&this._offline&&(this._showOfflineFallback=!1,this._completeOfflineFallbackTimer(),this._store.dispatch(A(!1)))}_startOfflineFallbackTimer(e=!1){var i;if(e)this._completeOfflineFallbackTimer(!0);else if(this._offlineFallbackDeferred||this._showOfflineFallback)return;let t=new v.Deferred,o=!1;t.promise.then(()=>{this._showOfflineFallback=this._offline}).finally(()=>{o=!0}),setTimeout(()=>{o||t.resolve()},(null==(i=this.appConfig)?void 0:i.offlineTimeout)||2e4),this._offlineFallbackDeferred=t}_completeOfflineFallbackTimer(e=!1){var i,t;e?null==(i=this._offlineFallbackDeferred)||i.reject():null==(t=this._offlineFallbackDeferred)||t.resolve(),this._offlineFallbackDeferred=void 0}logout(){h.logout()}setLanguage(e){h.language=e}showLanguageModal(){C(new b().setHeading("language").setDismissAction(null).setStyles(i`<style>.selected { color: ${o(g)} }</style>`).setActions(Object.entries(this.appConfig.languages||y).map(([e,t])=>({content:i`<span class="${e===h.language?"selected":""}">${c.t(t)}</span>`,actionName:e,action:()=>{h.language=e}}))))}doAppConfigInit(){this.appConfig=this.appConfig||(this.appConfigProvider?this.appConfigProvider(h):void 0),this.appConfig&&(this._config||(this._config=this._getConfig()))}doBasicLogin(e,t){let o=new v.Deferred,r=e,n=t,a=i`
|
|
62
|
-
#login-logo {
|
|
63
|
-
width: 24px;
|
|
64
|
-
height: 24px;
|
|
301
|
+
else {
|
|
302
|
+
window.sessionStorage.removeItem("realm");
|
|
65
303
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
304
|
+
}
|
|
305
|
+
if (changedProps.has("_config") && this._config) {
|
|
306
|
+
if (!this._config.logo) {
|
|
307
|
+
this._config.logo = DefaultLogo;
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
this._config.logo = ((_a = manager.managerUrl) !== null && _a !== void 0 ? _a : "") + this._config.logo;
|
|
311
|
+
}
|
|
312
|
+
if (!this._config.logoMobile) {
|
|
313
|
+
this._config.logoMobile = DefaultMobileLogo;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
this._config.logoMobile = ((_b = manager.managerUrl) !== null && _b !== void 0 ? _b : "") + this._config.logoMobile;
|
|
317
|
+
}
|
|
318
|
+
const favIcon = this._config && this._config.favicon ? (manager.managerUrl || "") + this._config.favicon : DefaultFavIcon;
|
|
319
|
+
let link = document.querySelector("link[rel~='icon']");
|
|
320
|
+
if (!link) {
|
|
321
|
+
link = document.createElement("link");
|
|
322
|
+
link.rel = "icon";
|
|
323
|
+
document.getElementsByTagName("head")[0].appendChild(link);
|
|
324
|
+
}
|
|
325
|
+
link.href = favIcon;
|
|
326
|
+
}
|
|
327
|
+
this.updateWindowTitle();
|
|
328
|
+
return super.shouldUpdate(changedProps);
|
|
329
|
+
}
|
|
330
|
+
render() {
|
|
331
|
+
if (!this._initialised) {
|
|
332
|
+
return html `<or-mwc-dialog id="app-modal"></or-mwc-dialog>`;
|
|
333
|
+
}
|
|
334
|
+
let consoleStyles;
|
|
335
|
+
if (manager.consoleAppConfig) {
|
|
336
|
+
const consoleAppConfig = manager.consoleAppConfig;
|
|
337
|
+
const primary = consoleAppConfig.primaryColor;
|
|
338
|
+
const secondary = consoleAppConfig.secondaryColor;
|
|
339
|
+
consoleStyles = html `<style>:host {--or-console-primary-color:${primary};--or-console-secondary-color:${secondary};}</style>`;
|
|
340
|
+
}
|
|
341
|
+
return html `
|
|
342
|
+
${this._config.styles ? typeof (this._config.styles) === "string" ? html `<style>${this._config.styles}</style>` : this._config.styles.strings : ``}
|
|
343
|
+
${consoleStyles}
|
|
344
|
+
${this._config.header ? html `
|
|
345
|
+
<or-header .activeMenu="${this._activeMenu}" .store="${this._store}" .realm="${this._realm}" .realms="${this._realms}" .logo="${this._config.logo}" .logoMobile="${this._config.logoMobile}" .config="${this._config.header}"></or-header>
|
|
346
|
+
` : ``}
|
|
347
|
+
|
|
348
|
+
<!-- Main content -->
|
|
349
|
+
<main role="main" class="main-content d-none"></main>
|
|
350
|
+
|
|
351
|
+
<slot></slot>
|
|
352
|
+
`;
|
|
353
|
+
}
|
|
354
|
+
stateChanged(state) {
|
|
355
|
+
this._realm = state.app.realm;
|
|
356
|
+
this._page = state.app.page;
|
|
357
|
+
this._offline = state.app.offline;
|
|
358
|
+
}
|
|
359
|
+
_handleEvent(event) {
|
|
360
|
+
if (event === OREvent.OFFLINE) {
|
|
361
|
+
if (!this._offline) {
|
|
362
|
+
this._store.dispatch((setOffline(true)));
|
|
363
|
+
}
|
|
364
|
+
this._startOfflineFallbackTimer(); // start fallback timer (if not done yet)
|
|
365
|
+
}
|
|
366
|
+
else if (event === OREvent.ONLINE) {
|
|
367
|
+
if (this._offline) {
|
|
368
|
+
this._showOfflineFallback = false;
|
|
369
|
+
this._completeOfflineFallbackTimer(); // complete fallback timer
|
|
370
|
+
this._store.dispatch((setOffline(false)));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Offline timer logic
|
|
375
|
+
//
|
|
376
|
+
// This will start a Deferred promise that keeps track of the 'wait before showing offline page' timer.
|
|
377
|
+
// - Resolving the promise updates the 'show offline fallback' variable based on OFFLINE state.
|
|
378
|
+
// - Rejecting the promise 'aborts the process' and skips that logic and does nothing.
|
|
379
|
+
//
|
|
380
|
+
// To explain; when the Manager reports "We're offline!" it will wait 10+ seconds before visually reporting the user that he/she is offline.
|
|
381
|
+
// However, if the user reconnects within that time period, we resolve this promise early. (which is why using Deferred is useful)
|
|
382
|
+
_startOfflineFallbackTimer(force = false) {
|
|
383
|
+
var _a;
|
|
384
|
+
if (force) {
|
|
385
|
+
this._completeOfflineFallbackTimer(true);
|
|
386
|
+
}
|
|
387
|
+
else if (this._offlineFallbackDeferred || this._showOfflineFallback) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const deferred = new Util.Deferred();
|
|
391
|
+
let finished = false;
|
|
392
|
+
deferred.promise.then(() => {
|
|
393
|
+
this._showOfflineFallback = this._offline;
|
|
394
|
+
}).finally(() => {
|
|
395
|
+
finished = true;
|
|
396
|
+
});
|
|
397
|
+
setTimeout(() => {
|
|
398
|
+
if (!finished) {
|
|
399
|
+
deferred.resolve();
|
|
400
|
+
} // resolve THIS timer if not done yet.
|
|
401
|
+
}, ((_a = this.appConfig) === null || _a === void 0 ? void 0 : _a.offlineTimeout) || 20000);
|
|
402
|
+
this._offlineFallbackDeferred = deferred;
|
|
403
|
+
}
|
|
404
|
+
// Completes and removes the 'show offline page' timer
|
|
405
|
+
// Resolving the timer updates the 'show offline fallback' variable based on OFFLINE state.
|
|
406
|
+
// if 'aborted' is TRUE it will skip that logic. See startOfflineTimer() for more details.
|
|
407
|
+
_completeOfflineFallbackTimer(aborted = false) {
|
|
408
|
+
var _a, _b;
|
|
409
|
+
if (aborted) {
|
|
410
|
+
(_a = this._offlineFallbackDeferred) === null || _a === void 0 ? void 0 : _a.reject();
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
(_b = this._offlineFallbackDeferred) === null || _b === void 0 ? void 0 : _b.resolve();
|
|
414
|
+
}
|
|
415
|
+
this._offlineFallbackDeferred = undefined;
|
|
416
|
+
}
|
|
417
|
+
logout() {
|
|
418
|
+
manager.logout();
|
|
419
|
+
}
|
|
420
|
+
setLanguage(lang) {
|
|
421
|
+
manager.language = lang;
|
|
422
|
+
}
|
|
423
|
+
showLanguageModal() {
|
|
424
|
+
showDialog(new OrMwcDialog()
|
|
425
|
+
.setHeading("language")
|
|
426
|
+
.setDismissAction(null)
|
|
427
|
+
.setStyles(html `<style>.selected { color: ${unsafeCSS(DefaultColor4)} }</style>`)
|
|
428
|
+
.setActions(Object.entries(this.appConfig.languages || DEFAULT_LANGUAGES).map(([key, value]) => {
|
|
429
|
+
return {
|
|
430
|
+
content: html `<span class="${(key === manager.language) ? 'selected' : ''}">${i18next.t(value)}</span>`,
|
|
431
|
+
actionName: key,
|
|
432
|
+
action: () => {
|
|
433
|
+
manager.language = key;
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
})));
|
|
437
|
+
}
|
|
438
|
+
doAppConfigInit() {
|
|
439
|
+
this.appConfig = this.appConfig || (this.appConfigProvider ? this.appConfigProvider(manager) : undefined);
|
|
440
|
+
if (!this.appConfig) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
if (!this._config) {
|
|
444
|
+
this._config = this._getConfig();
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
doBasicLogin(username, password) {
|
|
448
|
+
const deferred = new Util.Deferred();
|
|
449
|
+
let u = username;
|
|
450
|
+
let p = password;
|
|
451
|
+
// language=CSS
|
|
452
|
+
const styles = html `
|
|
453
|
+
#login-logo {
|
|
454
|
+
width: 24px;
|
|
455
|
+
height: 24px;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
#login_wrapper > or-mwc-input {
|
|
459
|
+
margin: 10px 0;
|
|
460
|
+
width: 100%;
|
|
461
|
+
}
|
|
462
|
+
`;
|
|
463
|
+
const dialog = showDialog(new OrMwcDialog()
|
|
464
|
+
.setStyles(html `<style>${styles}</style>`)
|
|
465
|
+
.setHeading(html `<img id="login-logo" src="${this._config.logoMobile || this._config.logo}" /></or-icon><or-translate value="login"></or-translate>`)
|
|
466
|
+
.setContent(html `
|
|
467
|
+
<div id="login_wrapper">
|
|
468
|
+
<or-mwc-input .label="${i18next.t("user")}" .type="${InputType.TEXT}" min="1" required .value="${username}" @or-mwc-input-changed="${(e) => u = e.detail.value}"></or-mwc-input>
|
|
469
|
+
<or-mwc-input .label="${i18next.t("password")}" .type="${InputType.PASSWORD}" min="1" required .value="${password}" @or-mwc-input-changed="${(e) => p = e.detail.value}"></or-mwc-input>
|
|
470
|
+
</div>
|
|
471
|
+
`)
|
|
472
|
+
.setActions([
|
|
473
|
+
{
|
|
474
|
+
actionName: "submit",
|
|
475
|
+
default: true,
|
|
476
|
+
action: () => {
|
|
477
|
+
deferred.resolve({
|
|
478
|
+
cancel: false,
|
|
479
|
+
username: u,
|
|
480
|
+
password: p
|
|
481
|
+
});
|
|
482
|
+
},
|
|
483
|
+
content: html `<or-mwc-input .type=${InputType.BUTTON} .label="${i18next.t("submit")}" raised></or-mwc-input>`
|
|
70
484
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
485
|
+
]), document.body); // Attach to document as or-app isn't visible until initialised
|
|
486
|
+
return deferred.promise;
|
|
487
|
+
}
|
|
488
|
+
updateWindowTitle() {
|
|
489
|
+
if (!this._initialised) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
const appTitle = this._config.appTitle || "";
|
|
493
|
+
let pageTitle = (i18next.isInitialized ? i18next.t(appTitle) : appTitle);
|
|
494
|
+
const pageElem = (this._mainElem ? this._mainElem.firstElementChild : undefined);
|
|
495
|
+
if (pageElem) {
|
|
496
|
+
pageTitle += (i18next.isInitialized ? " - " + i18next.t(pageElem.name) : " - " + pageElem.name);
|
|
497
|
+
}
|
|
498
|
+
updateMetadata({
|
|
499
|
+
title: pageTitle,
|
|
500
|
+
description: pageTitle
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
_getConfig() {
|
|
504
|
+
const defaultConfig = this.appConfig.realms ? this.appConfig.realms.default : {};
|
|
505
|
+
let realmConfig = this.appConfig.realms ? this.appConfig.realms[this._realm || ""] : undefined;
|
|
506
|
+
realmConfig = Util.mergeObjects(defaultConfig, realmConfig, false);
|
|
507
|
+
if (this.appConfig && this.appConfig.superUserHeader && manager.isSuperUser()) {
|
|
508
|
+
realmConfig.header = this.appConfig.superUserHeader;
|
|
509
|
+
}
|
|
510
|
+
return realmConfig;
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
__decorate([
|
|
514
|
+
property({ type: Object })
|
|
515
|
+
], OrApp.prototype, "appConfig", void 0);
|
|
516
|
+
__decorate([
|
|
517
|
+
property({ type: Object })
|
|
518
|
+
], OrApp.prototype, "managerConfig", void 0);
|
|
519
|
+
__decorate([
|
|
520
|
+
query("main")
|
|
521
|
+
], OrApp.prototype, "_mainElem", void 0);
|
|
522
|
+
__decorate([
|
|
523
|
+
state()
|
|
524
|
+
], OrApp.prototype, "_initialised", void 0);
|
|
525
|
+
__decorate([
|
|
526
|
+
state()
|
|
527
|
+
], OrApp.prototype, "_page", void 0);
|
|
528
|
+
__decorate([
|
|
529
|
+
state()
|
|
530
|
+
], OrApp.prototype, "_config", void 0);
|
|
531
|
+
__decorate([
|
|
532
|
+
state()
|
|
533
|
+
], OrApp.prototype, "_realm", void 0);
|
|
534
|
+
__decorate([
|
|
535
|
+
state()
|
|
536
|
+
], OrApp.prototype, "_offline", void 0);
|
|
537
|
+
__decorate([
|
|
538
|
+
state()
|
|
539
|
+
], OrApp.prototype, "_showOfflineFallback", void 0);
|
|
540
|
+
__decorate([
|
|
541
|
+
state()
|
|
542
|
+
], OrApp.prototype, "_activeMenu", void 0);
|
|
543
|
+
OrApp = __decorate([
|
|
544
|
+
customElement("or-app")
|
|
545
|
+
], OrApp);
|
|
546
|
+
export { OrApp };
|
|
547
|
+
//# sourceMappingURL=index.js.map
|