codenotch-react 1.0.22 → 1.0.24

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/auml.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import { SpaRenderStatus } from '@echino/echino.ui.framework/components/SpaBuilder/common/ISpaRenderProps';
3
+ interface IRenderAumlProps {
4
+ auml: string;
5
+ }
6
+ interface IRenderAumlState {
7
+ loaded: boolean;
8
+ inspectorEnabled: boolean;
9
+ }
10
+ export declare class RenderAuml extends React.Component<IRenderAumlProps, IRenderAumlState> {
11
+ _refreshTokenTimer: NodeJS.Timeout | undefined;
12
+ constructor(props: IRenderAumlProps);
13
+ componentDidMount(): void;
14
+ componentWillUnmount(): void;
15
+ progress(s: SpaRenderStatus): void;
16
+ getLogo(): React.JSX.Element;
17
+ getMode(theme: boolean | undefined): "dark" | "light";
18
+ retrieveInputs(): {
19
+ [k: string]: string;
20
+ };
21
+ getTimeToTokenExpiration(): number | null;
22
+ getTimeToNewTokenExpiration(expirationDateTime: string): number;
23
+ msToTime(ms: number): string;
24
+ parseJwt(token: string): any;
25
+ render(): React.JSX.Element;
26
+ refreshExpiredToken(): Promise<void>;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=auml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auml.d.ts","sourceRoot":"","sources":["../src/auml.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,eAAe,EAAE,MAAM,0EAA0E,CAAC;AAS3G,UAAU,gBAAgB;IACtB,IAAI,EAAE,MAAM,CAAC;CAChB;AACD,UAAU,gBAAgB;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AAED,qBAAa,UAAW,SAAQ,KAAK,CAAC,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAE/E,kBAAkB,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;gBAEnC,KAAK,EAAE,gBAAgB;IAqBnC,iBAAiB;IAmCjB,oBAAoB;IAQpB,QAAQ,CAAC,CAAC,EAAE,eAAe;IAO3B,OAAO;IAYP,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS;IAclC,cAAc;;;IAMd,wBAAwB,IAAI,MAAM,GAAG,IAAI;IAoCzC,2BAA2B,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM;IAO/D,QAAQ,CAAC,EAAE,EAAE,MAAM;IAmBnB,QAAQ,CAAC,KAAK,EAAE,MAAM;IAUtB,MAAM;IAiDA,mBAAmB;CAqC5B"}
package/dist/auml.js ADDED
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RenderAuml = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const SpaRenderWithBrowserRouter_1 = require("@echino/echino.ui.framework/components/SpaBuilder/SpaRender/SpaRenderWithBrowserRouter");
9
+ class RenderAuml extends react_1.default.Component {
10
+ constructor(props) {
11
+ super(props);
12
+ this.state = {
13
+ loaded: false,
14
+ inspectorEnabled: false
15
+ };
16
+ // Add a function that we can call from the browser console, allowing us to debug the page
17
+ //TODO we may not want to do that for prod pages
18
+ //@ts-ignore
19
+ window.toggleInspector = () => {
20
+ this.setState({
21
+ inspectorEnabled: !this.state.inspectorEnabled
22
+ }, () => console.log(`Auml inspector is now ${this.state.inspectorEnabled ? 'enabled' : 'disabled'}`));
23
+ };
24
+ }
25
+ componentDidMount() {
26
+ try {
27
+ // Setup a method to refresh our access token when it expires
28
+ if (this._refreshTokenTimer) {
29
+ clearTimeout(this._refreshTokenTimer);
30
+ }
31
+ if (!user) {
32
+ console.log("No user found, will not refresh the token");
33
+ return;
34
+ }
35
+ let timeToExpireMs = this.getTimeToTokenExpiration();
36
+ if (timeToExpireMs === null) {
37
+ console.log("No identity token found, attempting refreshing the token in 5 minutes");
38
+ this._refreshTokenTimer = setTimeout(() => this.refreshExpiredToken(), 5 * 60 * 1000);
39
+ return;
40
+ }
41
+ if (timeToExpireMs <= 0) {
42
+ // Refresh it immediatelty
43
+ this.refreshExpiredToken();
44
+ }
45
+ else {
46
+ this._refreshTokenTimer = setTimeout(() => this.refreshExpiredToken(), timeToExpireMs);
47
+ }
48
+ }
49
+ catch (err) {
50
+ console.warn("Could not setup token refresh timer: " + err);
51
+ }
52
+ }
53
+ componentWillUnmount() {
54
+ // Cleanup the refresh of the token
55
+ if (this._refreshTokenTimer) {
56
+ clearTimeout(this._refreshTokenTimer);
57
+ }
58
+ }
59
+ progress(s) {
60
+ //console.log('progessStatus ', s);
61
+ if (s === 'completed') {
62
+ this.setState({ loaded: true });
63
+ }
64
+ }
65
+ getLogo() {
66
+ //@ts-ignore
67
+ let tenant = global.tenant;
68
+ if (tenant.logoUrl) {
69
+ return react_1.default.createElement("img", { src: tenant.logoUrl, alt: tenant.displayName });
70
+ }
71
+ else {
72
+ return react_1.default.createElement("div", { className: 'app-loading-title' }, tenant.displayName);
73
+ }
74
+ }
75
+ getMode(theme) {
76
+ if (theme !== undefined) {
77
+ return theme ? 'dark' : 'light';
78
+ }
79
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
80
+ return 'dark';
81
+ }
82
+ return 'light';
83
+ }
84
+ // Get input from the query parameters in the url
85
+ retrieveInputs() {
86
+ return Object.fromEntries(new URLSearchParams(window.location.search).entries());
87
+ }
88
+ getTimeToTokenExpiration() {
89
+ // The identity token is the only one we have access here on the client
90
+ // We use it to know when the access token (which we can't read) will expire
91
+ let identityToken = null;
92
+ let identityTokenKey = `${tenant.name}IdToken=`;
93
+ let cookies = document.cookie.split(';');
94
+ for (let c of cookies) {
95
+ if (c.trim().startsWith(identityTokenKey)) {
96
+ identityToken = c.trim().slice(identityTokenKey.length);
97
+ break;
98
+ }
99
+ }
100
+ if (identityToken === null) {
101
+ return null; // token not found
102
+ }
103
+ let identityTokenParsed = this.parseJwt(identityToken);
104
+ let expires = identityTokenParsed.exp; // Timestamp in second since Unix epoch
105
+ let timeToExpiresMs = expires * 1000 - new Date().getTime();
106
+ let timeToExpireStr = this.msToTime(timeToExpiresMs);
107
+ console.log(`Token will expire at ${new Date(expires * 1000).toISOString()} (in ${timeToExpireStr}), setting up a timer to refresh it`);
108
+ // Refresh it a bit before the expiration (5 min)
109
+ timeToExpiresMs -= 5 * 60 * 1000;
110
+ return timeToExpiresMs;
111
+ }
112
+ getTimeToNewTokenExpiration(expirationDateTime) {
113
+ let timeToExpiresMs = new Date(expirationDateTime).getTime() - new Date().getTime();
114
+ // Refresh it a bit before the expiration (5 min)
115
+ timeToExpiresMs -= 5 * 60 * 1000;
116
+ return timeToExpiresMs;
117
+ }
118
+ msToTime(ms) {
119
+ let seconds = Math.floor((ms / 1000) % 60), minutes = Math.floor((ms / (1000 * 60)) % 60), hours = Math.floor((ms / (1000 * 60 * 60)) % 24);
120
+ let timeString = seconds + " seconds";
121
+ if (minutes > 0) {
122
+ timeString = minutes + " minutes " + timeString;
123
+ }
124
+ if (hours > 0) {
125
+ timeString = hours + " hours " + timeString;
126
+ }
127
+ return timeString;
128
+ }
129
+ parseJwt(token) {
130
+ var base64Url = token.split('.')[1];
131
+ var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
132
+ var jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function (c) {
133
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
134
+ }).join(''));
135
+ return JSON.parse(jsonPayload);
136
+ }
137
+ render() {
138
+ //var clusterUrl = this.figureOutClusterUrl();
139
+ let inputs = this.retrieveInputs();
140
+ let theme = undefined;
141
+ if (inputs["_theme"]) {
142
+ theme = inputs["_theme"].toLowerCase() === "dark";
143
+ }
144
+ let aumlManifest = null;
145
+ try {
146
+ let appManifestObj = JSON.parse(appManifest);
147
+ aumlManifest = appManifestObj.auml;
148
+ }
149
+ catch { }
150
+ return (react_1.default.createElement("div", { className: "app" },
151
+ react_1.default.createElement(SpaRenderWithBrowserRouter_1.SpaRenderWithBrowserRouter, { appDescription: this.props.auml, tenant: tenant, serviceName: serviceName, packageVersions: packageVersions, user: user, languages: languages, onProgress: (s) => this.progress(s), input: inputs, theme: theme, manifest: aumlManifest, inspectorEnabled: this.state.inspectorEnabled, children: [] }),
152
+ !this.state.loaded &&
153
+ react_1.default.createElement("div", { className: `app-loading ${this.getMode(theme)}` },
154
+ this.getLogo(),
155
+ react_1.default.createElement("i", { className: "fas fa-circle-notch fa-spin" }))));
156
+ }
157
+ async refreshExpiredToken() {
158
+ console.log("Token will expire soon, requesting a new one...");
159
+ // Using the refresh token we ask for a new access token using /portal/login/refresh
160
+ // If the refresh token has also expired, we will be redirected to the login page
161
+ let redirectUrl = window.location.href; // Where to send us back in case we need to be redirected to the login page
162
+ let url = `${tenant.clusterUrl}/portal/login/refresh?redirectUrl=${encodeURIComponent(redirectUrl)}`;
163
+ let response = await fetch(url); // For this request to work, we need to have a refresh token in the cookies
164
+ if (response.ok) {
165
+ // Setup next refresh
166
+ let timeToExpireMs;
167
+ try {
168
+ let newTokenExpiration = await response.text();
169
+ timeToExpireMs = this.getTimeToNewTokenExpiration(newTokenExpiration);
170
+ }
171
+ catch {
172
+ timeToExpireMs = 2 * 60 * 60 * 1000; // refresh in 2 hours
173
+ }
174
+ console.log(`Refresh request ok, next refresh in ${this.msToTime(timeToExpireMs)}`);
175
+ this._refreshTokenTimer = setTimeout(() => this.refreshExpiredToken(), timeToExpireMs);
176
+ }
177
+ else {
178
+ let content = await response.text();
179
+ console.error("Could not refresh the token", content);
180
+ console.log("Retrying refreshing the token in 5 minutes...");
181
+ this._refreshTokenTimer = setTimeout(() => this.refreshExpiredToken(), 5 * 60 * 1000);
182
+ }
183
+ }
184
+ }
185
+ exports.RenderAuml = RenderAuml;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codenotch-react",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "author": "Codenotch SA",
@@ -13,9 +13,13 @@
13
13
  "files": [
14
14
  "dist/**/*"
15
15
  ],
16
+ "dependencies": {
17
+ "@echino/echino.ui.framework": "1.1.42"
18
+ },
16
19
  "devDependencies": {
17
20
  "@types/node": "^25.3.2",
18
21
  "@types/react": "^16.14.69",
22
+ "@echino/echino.ui.sdk": "^0.3.188",
19
23
  "typescript": "^5.9.3"
20
24
  },
21
25
  "peerDependencies": {