@gridsuite/commons-ui 0.61.1 → 0.62.0
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 +6 -7
- package/dist/components/TopBar/AboutDialog.js +16 -12
- package/dist/index.d.ts +1 -0
- package/dist/utils/AuthService.d.ts +19 -10
- package/dist/utils/AuthService.js +28 -84
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,13 +33,12 @@ you need to follow the steps below:
|
|
|
33
33
|
- Update to the new version in [package.json](https://github.com/gridsuite/commons-ui/blob/main/package.json) (example `0.6.0`)
|
|
34
34
|
- Build it: `npm install`
|
|
35
35
|
- Commit the package.json and package-lock.json files, push to a branch, make a PR, have it reviewed and merged to main.
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
- [Publish the package](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages#publishing-scoped-public-packages): `npm publish`
|
|
36
|
+
- [Make a release](https://github.com/gridsuite/commons-ui/releases/new) on GitHub by creating a new tag on the last commit. On the release creation page:
|
|
37
|
+
- In "Choose a tag": type the tag you want to create (ex.: v0.6.0) and select "create new tag"
|
|
38
|
+
- In "Target": click on "recent commit" tab and select your release commit
|
|
39
|
+
- Click on "Generate release note"
|
|
40
|
+
- Click on "Publish release"
|
|
41
|
+
- It will trigger a job that will publish the release on NPM
|
|
43
42
|
|
|
44
43
|
#### License Headers and dependencies checking
|
|
45
44
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect,
|
|
2
|
+
import { useState, useEffect, useCallback } from "react";
|
|
3
3
|
import { useTheme, Dialog, useMediaQuery, DialogTitle, Collapse, Alert, Box, Fade, CircularProgress, Typography, DialogContent, Accordion, AccordionSummary, AccordionDetails, Grid, DialogActions, Button, Tooltip, Zoom, Stack, tooltipClasses } from "@mui/material";
|
|
4
4
|
import { LoadingButton } from "@mui/lab";
|
|
5
5
|
import { Refresh, ExpandMore, Gavel, Apps, WidgetsOutlined, DnsOutlined, QuestionMark } from "@mui/icons-material";
|
|
@@ -115,18 +115,15 @@ const AboutDialog = ({
|
|
|
115
115
|
}, [open, globalVersionPromise]);
|
|
116
116
|
const [loadingAdditionalModules, setLoadingAdditionalModules] = useState(false);
|
|
117
117
|
const [modules, setModules] = useState(null);
|
|
118
|
-
const currentApp = useMemo(
|
|
119
|
-
() => ({
|
|
120
|
-
name: !!logo && appName || `Grid${appName}`,
|
|
121
|
-
type: "app",
|
|
122
|
-
version: appVersion,
|
|
123
|
-
gitTag: appGitTag,
|
|
124
|
-
license: appLicense
|
|
125
|
-
}),
|
|
126
|
-
[logo, appName, appVersion, appGitTag, appLicense]
|
|
127
|
-
);
|
|
128
118
|
useEffect(() => {
|
|
129
119
|
if (open) {
|
|
120
|
+
const currentApp = {
|
|
121
|
+
name: `Grid${appName}`,
|
|
122
|
+
type: "app",
|
|
123
|
+
version: appVersion,
|
|
124
|
+
gitTag: appGitTag,
|
|
125
|
+
license: appLicense
|
|
126
|
+
};
|
|
130
127
|
(additionalModulesPromise ? Promise.resolve(setLoadingAdditionalModules(true)).then(
|
|
131
128
|
() => additionalModulesPromise()
|
|
132
129
|
) : Promise.reject(new Error("no getter"))).then(
|
|
@@ -136,7 +133,14 @@ const AboutDialog = ({
|
|
|
136
133
|
setModules([currentApp, ...values]);
|
|
137
134
|
}).finally(() => setLoadingAdditionalModules(false));
|
|
138
135
|
}
|
|
139
|
-
}, [
|
|
136
|
+
}, [
|
|
137
|
+
open,
|
|
138
|
+
additionalModulesPromise,
|
|
139
|
+
appName,
|
|
140
|
+
appVersion,
|
|
141
|
+
appGitTag,
|
|
142
|
+
appLicense
|
|
143
|
+
]);
|
|
140
144
|
const handleClose = useCallback(() => {
|
|
141
145
|
if (onClose) {
|
|
142
146
|
onClose();
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export { ElementType } from './utils/ElementType';
|
|
|
35
35
|
export type { ElementAttributes, Option, Equipment } from './utils/types';
|
|
36
36
|
export { EQUIPMENT_TYPE, EquipmentType, getEquipmentsInfosForSearchBar, equipmentStyles, } from './utils/EquipmentType';
|
|
37
37
|
export { initializeAuthenticationDev, initializeAuthenticationProd, logout, dispatchUser, getPreLoginPath, } from './utils/AuthService';
|
|
38
|
+
export type * from './utils/AuthService';
|
|
38
39
|
export { getFileIcon } from './utils/ElementIcon';
|
|
39
40
|
export { DEFAULT_CELL_PADDING, DEFAULT_HEADER_HEIGHT, DEFAULT_ROW_HEIGHT, } from './components/MuiVirtualizedTable/MuiVirtualizedTable';
|
|
40
41
|
export { DARK_THEME, LIGHT_THEME, LANG_SYSTEM, LANG_ENGLISH, LANG_FRENCH, } from './components/TopBar/TopBar';
|
|
@@ -3,18 +3,27 @@ import { Dispatch } from 'react';
|
|
|
3
3
|
import { User, UserManager } from 'oidc-client';
|
|
4
4
|
|
|
5
5
|
type UserValidationFunc = (user: User) => Promise<boolean>;
|
|
6
|
+
type IdpSettingsGetter = () => Promise<IdpSettings>;
|
|
7
|
+
export type IdpSettings = {
|
|
8
|
+
authority: string;
|
|
9
|
+
client_id: string;
|
|
10
|
+
redirect_uri: string;
|
|
11
|
+
post_logout_redirect_uri: string;
|
|
12
|
+
silent_redirect_uri: string;
|
|
13
|
+
scope: string;
|
|
14
|
+
maxExpiresIn?: number;
|
|
15
|
+
};
|
|
6
16
|
type CustomUserManager = UserManager & {
|
|
7
|
-
authorizationCodeFlowEnabled?: boolean;
|
|
8
17
|
idpSettings?: {
|
|
9
18
|
maxExpiresIn?: number;
|
|
10
19
|
};
|
|
11
20
|
};
|
|
12
|
-
declare function initializeAuthenticationDev(dispatch: Dispatch<unknown>, isSilentRenew: boolean, validateUser: UserValidationFunc, isSigninCallback: boolean): Promise<UserManager>;
|
|
13
|
-
declare function initializeAuthenticationProd(dispatch: Dispatch<unknown>, isSilentRenew: boolean,
|
|
14
|
-
declare function login(location: Location, userManagerInstance: UserManager): Promise<void>;
|
|
15
|
-
declare function logout(dispatch: Dispatch<unknown>, userManagerInstance: UserManager): Promise<void | undefined>;
|
|
16
|
-
declare function dispatchUser(dispatch: Dispatch<unknown>, userManagerInstance: CustomUserManager, validateUser: UserValidationFunc): Promise<void | undefined>;
|
|
17
|
-
declare function getPreLoginPath(): string | null;
|
|
18
|
-
declare function handleSigninCallback(dispatch: Dispatch<unknown>, navigate: NavigateFunction, userManagerInstance: UserManager): void;
|
|
19
|
-
declare function handleSilentRenewCallback(userManagerInstance: UserManager): void;
|
|
20
|
-
export {
|
|
21
|
+
export declare function initializeAuthenticationDev(dispatch: Dispatch<unknown>, isSilentRenew: boolean, validateUser: UserValidationFunc, isSigninCallback: boolean): Promise<UserManager>;
|
|
22
|
+
export declare function initializeAuthenticationProd(dispatch: Dispatch<unknown>, isSilentRenew: boolean, idpSettingsGetter: IdpSettingsGetter, validateUser: UserValidationFunc, isSigninCallback: boolean): Promise<CustomUserManager>;
|
|
23
|
+
export declare function login(location: Location, userManagerInstance: UserManager): Promise<void>;
|
|
24
|
+
export declare function logout(dispatch: Dispatch<unknown>, userManagerInstance: UserManager): Promise<void | undefined>;
|
|
25
|
+
export declare function dispatchUser(dispatch: Dispatch<unknown>, userManagerInstance: CustomUserManager, validateUser: UserValidationFunc): Promise<void | undefined>;
|
|
26
|
+
export declare function getPreLoginPath(): string | null;
|
|
27
|
+
export declare function handleSigninCallback(dispatch: Dispatch<unknown>, navigate: NavigateFunction, userManagerInstance: UserManager): void;
|
|
28
|
+
export declare function handleSilentRenewCallback(userManagerInstance: UserManager): void;
|
|
29
|
+
export {};
|
|
@@ -6,7 +6,7 @@ window.OIDCLog = Log;
|
|
|
6
6
|
const hackAuthorityKey = "oidc.hack.authority";
|
|
7
7
|
const oidcHackReloadedKey = "gridsuite-oidc-hack-reloaded";
|
|
8
8
|
const pathKey = "powsybl-gridsuite-current-path";
|
|
9
|
-
function
|
|
9
|
+
function isIssuerError(error) {
|
|
10
10
|
return error.message.includes("Invalid issuer in token");
|
|
11
11
|
}
|
|
12
12
|
function extractIssuerToSessionStorage(error) {
|
|
@@ -33,19 +33,15 @@ function handleSigninSilent(dispatch, userManager) {
|
|
|
33
33
|
if (user == null || getIdTokenExpiresIn(user) < 0) {
|
|
34
34
|
return userManager.signinSilent().catch((error) => {
|
|
35
35
|
dispatch(setShowAuthenticationRouterLogin(true));
|
|
36
|
-
|
|
37
|
-
const errorIssuerImplicitFlow = error.message === "authority mismatch on settings vs. signin state";
|
|
38
|
-
if (errorIssuerCodeFlow) {
|
|
36
|
+
if (isIssuerError(error)) {
|
|
39
37
|
extractIssuerToSessionStorage(error);
|
|
40
|
-
}
|
|
41
|
-
if (errorIssuerCodeFlow || errorIssuerImplicitFlow) {
|
|
42
38
|
reload();
|
|
43
39
|
}
|
|
44
40
|
});
|
|
45
41
|
}
|
|
46
42
|
});
|
|
47
43
|
}
|
|
48
|
-
function initializeAuthenticationDev(dispatch, isSilentRenew, validateUser, isSigninCallback) {
|
|
44
|
+
async function initializeAuthenticationDev(dispatch, isSilentRenew, validateUser, isSigninCallback) {
|
|
49
45
|
let userManager = new UserManagerMock(
|
|
50
46
|
{}
|
|
51
47
|
);
|
|
@@ -55,76 +51,25 @@ function initializeAuthenticationDev(dispatch, isSilentRenew, validateUser, isSi
|
|
|
55
51
|
handleSigninSilent(dispatch, userManager);
|
|
56
52
|
}
|
|
57
53
|
}
|
|
58
|
-
return
|
|
54
|
+
return userManager;
|
|
59
55
|
}
|
|
60
56
|
const accessTokenExpiringNotificationTime = 60;
|
|
61
|
-
function initializeAuthenticationProd(dispatch, isSilentRenew,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const regexstate = /state=[^&]*/;
|
|
65
|
-
const regexexpires = /expires_in=[^&]*/;
|
|
66
|
-
let authority;
|
|
67
|
-
if (window.location.hash) {
|
|
68
|
-
const matched_id_token = window.location.hash.match(regextoken);
|
|
69
|
-
const matched_state = window.location.hash.match(regexstate);
|
|
70
|
-
if (matched_id_token != null && matched_state != null) {
|
|
71
|
-
const id_token = matched_id_token[0].split("=")[1];
|
|
72
|
-
const state = matched_state[0].split("=")[1];
|
|
73
|
-
const strState = localStorage.getItem("oidc." + state);
|
|
74
|
-
if (strState != null) {
|
|
75
|
-
const decoded = jwtDecode(id_token);
|
|
76
|
-
authority = decoded.iss;
|
|
77
|
-
const storedState = JSON.parse(strState);
|
|
78
|
-
console.debug(
|
|
79
|
-
"Replacing authority in storedState. Before: ",
|
|
80
|
-
storedState.authority,
|
|
81
|
-
"after: ",
|
|
82
|
-
authority
|
|
83
|
-
);
|
|
84
|
-
storedState.authority = authority;
|
|
85
|
-
localStorage.setItem(
|
|
86
|
-
"oidc." + state,
|
|
87
|
-
JSON.stringify(storedState)
|
|
88
|
-
);
|
|
89
|
-
if (authority !== void 0) {
|
|
90
|
-
sessionStorage.setItem(hackAuthorityKey, authority);
|
|
91
|
-
}
|
|
92
|
-
const matched_expires = window.location.hash.match(regexexpires);
|
|
93
|
-
if (matched_expires != null) {
|
|
94
|
-
const expires_in = parseInt(
|
|
95
|
-
matched_expires[0].split("=")[1]
|
|
96
|
-
);
|
|
97
|
-
window.location.hash = window.location.hash.replace(
|
|
98
|
-
matched_expires[0],
|
|
99
|
-
"expires_in=" + computeMinExpiresIn(
|
|
100
|
-
expires_in,
|
|
101
|
-
id_token,
|
|
102
|
-
idpSettings2.maxExpiresIn
|
|
103
|
-
)
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
authority = authority || sessionStorage.getItem(hackAuthorityKey) || idpSettings2.authority;
|
|
110
|
-
const responseSettings = authorizationCodeFlowEnabled ? { response_type: "code" } : {
|
|
111
|
-
response_type: "id_token token",
|
|
112
|
-
response_mode: "fragment"
|
|
113
|
-
};
|
|
57
|
+
async function initializeAuthenticationProd(dispatch, isSilentRenew, idpSettingsGetter, validateUser, isSigninCallback) {
|
|
58
|
+
const idpSettings = await idpSettingsGetter();
|
|
59
|
+
try {
|
|
114
60
|
const settings = {
|
|
115
|
-
authority,
|
|
116
|
-
client_id:
|
|
117
|
-
redirect_uri:
|
|
118
|
-
post_logout_redirect_uri:
|
|
119
|
-
silent_redirect_uri:
|
|
120
|
-
scope:
|
|
61
|
+
authority: sessionStorage.getItem(hackAuthorityKey) || idpSettings.authority,
|
|
62
|
+
client_id: idpSettings.client_id,
|
|
63
|
+
redirect_uri: idpSettings.redirect_uri,
|
|
64
|
+
post_logout_redirect_uri: idpSettings.post_logout_redirect_uri,
|
|
65
|
+
silent_redirect_uri: idpSettings.silent_redirect_uri,
|
|
66
|
+
scope: idpSettings.scope,
|
|
121
67
|
automaticSilentRenew: !isSilentRenew,
|
|
122
68
|
accessTokenExpiringNotificationTime,
|
|
123
|
-
|
|
69
|
+
response_type: "code"
|
|
124
70
|
};
|
|
125
71
|
let userManager = new UserManager(settings);
|
|
126
|
-
userManager.idpSettings =
|
|
127
|
-
userManager.authorizationCodeFlowEnabled = authorizationCodeFlowEnabled;
|
|
72
|
+
userManager.idpSettings = idpSettings;
|
|
128
73
|
if (!isSilentRenew) {
|
|
129
74
|
handleUser(dispatch, userManager, validateUser);
|
|
130
75
|
if (!isSigninCallback) {
|
|
@@ -132,11 +77,11 @@ function initializeAuthenticationProd(dispatch, isSilentRenew, idpSettings, vali
|
|
|
132
77
|
}
|
|
133
78
|
}
|
|
134
79
|
return userManager;
|
|
135
|
-
}
|
|
80
|
+
} catch (error) {
|
|
136
81
|
console.debug("error when importing the idp settings", error);
|
|
137
82
|
dispatch(setShowAuthenticationRouterLogin(true));
|
|
138
83
|
throw error;
|
|
139
|
-
}
|
|
84
|
+
}
|
|
140
85
|
}
|
|
141
86
|
function computeMinExpiresIn(expiresIn, idToken, maxExpiresIn) {
|
|
142
87
|
const now = Date.now() / 1e3;
|
|
@@ -171,6 +116,7 @@ function login(location, userManagerInstance) {
|
|
|
171
116
|
}
|
|
172
117
|
function logout(dispatch, userManagerInstance) {
|
|
173
118
|
sessionStorage.removeItem(hackAuthorityKey);
|
|
119
|
+
sessionStorage.removeItem(oidcHackReloadedKey);
|
|
174
120
|
return userManagerInstance.getUser().then((user) => {
|
|
175
121
|
if (user) {
|
|
176
122
|
return userManagerInstance.signoutRedirect({
|
|
@@ -221,17 +167,15 @@ function dispatchUser(dispatch, userManagerInstance, validateUser) {
|
|
|
221
167
|
console.debug(
|
|
222
168
|
"User has been successfully loaded from store."
|
|
223
169
|
);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
);
|
|
234
|
-
}
|
|
170
|
+
reloadTimerOnExpiresIn(
|
|
171
|
+
user,
|
|
172
|
+
userManagerInstance,
|
|
173
|
+
computeMinExpiresIn(
|
|
174
|
+
user.expires_in,
|
|
175
|
+
user.id_token,
|
|
176
|
+
(_b = userManagerInstance.idpSettings) == null ? void 0 : _b.maxExpiresIn
|
|
177
|
+
)
|
|
178
|
+
);
|
|
235
179
|
return dispatch(setLoggedUser(user));
|
|
236
180
|
}).catch((e) => {
|
|
237
181
|
var _a;
|
|
@@ -259,7 +203,7 @@ function navigateToPreLoginPath(navigate) {
|
|
|
259
203
|
function handleSigninCallback(dispatch, navigate, userManagerInstance) {
|
|
260
204
|
let reloadAfterNavigate = false;
|
|
261
205
|
userManagerInstance.signinRedirectCallback().catch(function(e) {
|
|
262
|
-
if (
|
|
206
|
+
if (isIssuerError(e)) {
|
|
263
207
|
extractIssuerToSessionStorage(e);
|
|
264
208
|
reloadAfterNavigate = true;
|
|
265
209
|
} else {
|