Skip to content

Commit e67bcaf

Browse files
committed
Fixes eslint warnings
1 parent f05d6b6 commit e67bcaf

File tree

18 files changed

+222
-246
lines changed

18 files changed

+222
-246
lines changed

.github/workflows/actions.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
- uses: actions/checkout@v6
3232
- uses: actions/setup-node@v6
3333
with:
34-
node-version: 20
34+
node-version: 24.11.0
3535
- name: Yarn Audit client
3636
run: yarn audit --level high --groups dependencies
3737
working-directory: client

.github/workflows/deploy.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ jobs:
7676
server-password: MAVEN_PASSWORD
7777
if: ${{!( endsWith(steps.versioncheck.outputs.version, '-SNAPSHOT')) }}
7878

79+
- name: Node
80+
uses: actions/setup-node@v6
81+
with:
82+
node-version: 24.11.0
83+
7984
- name: Deploy with Maven
8085
run: mvn --batch-mode deploy -DskipTests
8186
env:

client/build.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
rm -Rf public/bundle*
33
rm -Rf target/*
44
rm -Rf dist/*
5+
rm -Rf build/*
56
source $NVM_DIR/nvm.sh
67
nvm use
7-
yarn install --force && CI=true yarn test && yarn lint && yarn build
8+
yarn install --force
9+
CI=true yarn test
10+
yarn lint ./src
11+
yarn build

client/eslint.config.mjs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,38 @@
11
import js from "@eslint/js";
22
import globals from "globals";
33
import pluginReact from "eslint-plugin-react";
4+
import react from "eslint-plugin-react";
45
import reactHooks from 'eslint-plugin-react-hooks';
5-
import { defineConfig } from "eslint/config";
6+
import {defineConfig} from "eslint/config";
67

78
export default defineConfig([
8-
{
9-
files: ["**/*.{js,mjs,cjs,jsx}"],
10-
plugins: {
11-
js ,
12-
'react-hooks': reactHooks
9+
{
10+
files: ["**/*.{js,mjs,cjs,jsx}"],
11+
plugins: {
12+
js,
13+
'react-hooks': reactHooks,
14+
react
15+
},
16+
extends: ["js/recommended"],
17+
languageOptions: {globals: globals.browser},
18+
settings: {
19+
react: {
20+
version: '19.1.1', // or your exact version
21+
},
22+
},
23+
1324
},
14-
extends: ["js/recommended"],
15-
languageOptions: { globals: globals.browser }
16-
},
17-
pluginReact.configs.flat.recommended, // React config first
18-
reactHooks.configs.flat.recommended,
19-
{
20-
rules: {
21-
"react/prop-types": "off",
22-
"react/no-children-prop": "off",
23-
'react-hooks/exhaustive-deps': 'warn',
24-
"react/react-in-jsx-scope" : "off",
25-
"react-hooks/set-state-in-effect": "warn",
26-
"react-hooks/immutability":"off"
25+
pluginReact.configs.flat.recommended, // React config first
26+
reactHooks.configs.flat.recommended,
27+
{
28+
rules: {
29+
"react/prop-types": "off",
30+
"react/no-children-prop": "off",
31+
'react-hooks/exhaustive-deps': 'warn',
32+
"react/react-in-jsx-scope": "off",
33+
"react-hooks/set-state-in-effect": "warn",
34+
"react-hooks/immutability": "off"
35+
},
2736
},
28-
},
2937

3038
]);

client/src/locale/en.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ const en = {
247247
requestedAuthnContext: "ACR value",
248248
requestedAuthnContextPlaceHolder: "Choose a ACR value for user stepup...",
249249
requestedAuthnContextWarning: "To enforce the selected ACR also on the application(s) {{applications}} associated " +
250-
"with the role(s) {{roles}}, additional configuration is needed on the eduID identity provider. " +
250+
"with the role(s) {{roles}}, additional configuration is needed on the eduID Identity Provider. " +
251251
"Please contact <a href=\"mailto:support@surfconext.nl\">support@surfconext.nl</a> to request this change.",
252252
new: "Invite role manager or inviter",
253253
newInvitation: "Invite inviter",

client/src/pages/App.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const App = () => {
3636
const {user, impersonator, authenticated, reload} = useAppStore(state => state);
3737

3838
useEffect(() => {
39-
setLoading(true);
4039
csrf().then(token => {
4140
useAppStore.setState(() => ({csrfToken: token.token}));
4241
configuration()

client/src/pages/Home.jsx

Lines changed: 48 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {Users} from "../tabs/Users";
1010
import {Page} from "../components/Page";
1111
import {Roles} from "../tabs/Roles";
1212
import {AUTHORITIES, highestAuthority} from "../utils/UserRole";
13-
import {Loader} from "@surfnet/sds";
1413
import {Tokens} from "../tabs/Tokens";
1514
import {ApplicationUsers} from "../tabs/ApplicationUsers";
1615
import Applications from "../tabs/Applications";
@@ -19,93 +18,72 @@ import {isEmpty} from "../utils/Utils";
1918
export const Home = () => {
2019
const {tab = "roles"} = useParams();
2120
const [currentTab, setCurrentTab] = useState(tab);
22-
const [tabs, setTabs] = useState([]);
2321
const [winking, setWinking] = useState(false);
24-
const [loading, setLoading] = useState(true);
2522

2623
const user = useAppStore((state) => state.user)
2724
const navigate = useNavigate();
2825

26+
const tabs = [
27+
<Page key="roles"
28+
name="roles"
29+
label={I18n.t("tabs.roles")}>
30+
<Roles/>
31+
</Page>,
32+
(user && user.superUser) ?
33+
<Page key="users"
34+
name="users"
35+
label={I18n.t("tabs.users")}>
36+
<Users/>
37+
</Page> : null,
38+
(user && user.superUser) ?
39+
<Page key="applications"
40+
name="applications"
41+
label={I18n.t("tabs.applications")}>
42+
<Applications/>
43+
</Page> : null,
44+
(user && !user.superUser && user.institutionAdmin && user.organizationGUID && !isEmpty(user.applications)) ?
45+
<Page key="applicationUsers"
46+
name="applicationUsers"
47+
label={I18n.t("tabs.applicationUsers")}>
48+
<ApplicationUsers/>
49+
</Page> : null,
50+
(user && !user.superUser && user.institutionAdmin && user.organizationGUID && !isEmpty(user.applications)) ?
51+
<Page key="applications"
52+
name="applications"
53+
label={I18n.t("tabs.applications")}>
54+
<Applications/>
55+
</Page> : null,
56+
(user && (user.superUser || (user.institutionAdmin && user.organizationGUID))) ?
57+
<Page key="tokens"
58+
name="tokens"
59+
label={I18n.t("tabs.tokens")}>
60+
<Tokens/>
61+
</Page> : null
62+
].filter(t => t !== null);
63+
2964
useEffect(() => {
30-
if (user) {
31-
if (highestAuthority(user) === AUTHORITIES.INVITER) {
32-
navigate("/inviter");
33-
return;
34-
}
35-
useAppStore.setState({
36-
breadcrumbPath: [
37-
{path: "/home", value: I18n.t("tabs.home")},
38-
{value: I18n.t(`tabs.${currentTab}`)}
39-
]
40-
});
41-
}
42-
const newTabs = [
43-
<Page key="roles"
44-
name="roles"
45-
label={I18n.t("tabs.roles")}
46-
>
47-
<Roles/>
48-
</Page>
49-
];
50-
if (user && user.superUser) {
51-
newTabs.push(
52-
<Page key="users"
53-
name="users"
54-
label={I18n.t("tabs.users")}
55-
>
56-
<Users/>
57-
</Page>);
58-
newTabs.push(
59-
<Page key="applications"
60-
name="applications"
61-
label={I18n.t("tabs.applications")}
62-
>
63-
<Applications/>
64-
</Page>
65-
);
66-
}
67-
if (user && !user.superUser && user.institutionAdmin && user.organizationGUID && !isEmpty(user.applications)) {
68-
newTabs.push(
69-
<Page key="applicationUsers"
70-
name="applicationUsers"
71-
label={I18n.t("tabs.applicationUsers")}
72-
>
73-
<ApplicationUsers/>
74-
</Page>);
75-
newTabs.push(
76-
<Page key="applications"
77-
name="applications"
78-
label={I18n.t("tabs.applications")}
79-
>
80-
<Applications/>
81-
</Page>
82-
);
65+
if (highestAuthority(user) === AUTHORITIES.INVITER) {
66+
navigate("/inviter");
8367
}
84-
if (user && (user.superUser || (user.institutionAdmin && user.organizationGUID))) {
85-
newTabs.push(
86-
<Page key="tokens"
87-
name="tokens"
88-
label={I18n.t("tabs.tokens")}>
89-
<Tokens/>
90-
</Page>);
91-
}
92-
setTabs(newTabs);
93-
setLoading(false);
94-
}, [currentTab, user]);// eslint-disable-line react-hooks/exhaustive-deps
68+
69+
}, [user]);
9570

9671
const tabChanged = (name) => {
9772
setCurrentTab(name);
9873
navigate(`/home/${name}`);
74+
useAppStore.setState({
75+
breadcrumbPath: [
76+
{path: "/home", value: I18n.t("tabs.home")},
77+
{value: I18n.t(`tabs.${currentTab}`)}
78+
]
79+
});
9980
}
10081

10182
const winkOwl = () => {
10283
setWinking(true);
10384
setTimeout(() => setWinking(false), 850);
10485
}
10586

106-
if (loading) {
107-
return <Loader/>
108-
}
10987
return (
11088
<div className="home">
11189
<div className="mod-home-container">

client/src/pages/InvitationForm.jsx

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useEffect, useState} from "react";
1+
import React, {useEffect, useMemo, useState} from "react";
22
import {useLocation, useNavigate} from "react-router-dom";
33
import {useAppStore} from "../stores/AppStore";
44
import I18n from "../locale/I18n";
@@ -13,7 +13,6 @@ import {
1313
import UserIcon from "@surfnet/sds/icons/functional-icons/id-2.svg";
1414
import UpIcon from "@surfnet/sds/icons/functional-icons/arrow-up-2.svg";
1515
import DownIcon from "@surfnet/sds/icons/functional-icons/arrow-down-2.svg";
16-
import WarningIcon from "@surfnet/sds/icons/functional-icons/alert-triangle.svg";
1716
import {
1817
eduidIdentityProvider,
1918
newInvitation,
@@ -106,6 +105,37 @@ export const InvitationForm = () => {
106105
useAppStore.setState({breadcrumbPath: breadcrumbPath});
107106
}, [user]);// eslint-disable-line react-hooks/exhaustive-deps
108107

108+
const acrWarning = useMemo(() => {
109+
if (isEmpty(invitation.requestedAuthnContext) || isEmpty(eduIDIdP) || isEmpty(selectedRoles)) {
110+
return null;
111+
}
112+
//Filter out the roles that are linked to applications that are not present in the mfaEntities of the eduIDIdp
113+
//or where the MFA level does not equal the requestedAuthnContext. If the requestedAuthnContext === TransparentAuthnContext,
114+
//then we skip the warning
115+
const mfaEntities = eduIDIdP.mfaEntities;
116+
const acrValue = acrValues[invitation.requestedAuthnContext];
117+
const missingEntities = selectedRoles.reduce((acc, role) => {
118+
const missingMfaApps = role.applicationMaps
119+
.filter(app => {
120+
const mfa = mfaEntities.find(mfa => mfa.name === app.entityid);
121+
return isEmpty(mfa) || (mfa.level !== acrValue && mfa.level !== acrValues.TransparentAuthnContext);
122+
});
123+
if (!isEmpty(missingMfaApps)) {
124+
acc.applications = acc.applications.concat(missingMfaApps.map(app => app[`name:${I18n.locale}`] || app["name:en"]));
125+
acc.roles.push(role.name)
126+
}
127+
return acc;
128+
}, {applications: [], roles: []})
129+
if (isEmpty(missingEntities.roles)) {
130+
return null;
131+
}
132+
const roleNames = splitListSemantically(missingEntities.roles, I18n.t("forms.and"));
133+
const applicationNames = splitListSemantically(missingEntities.applications, I18n.t("forms.and"));
134+
return DOMPurify.sanitize(I18n.t("invitations.requestedAuthnContextWarning",
135+
{roles: roleNames, applications: applicationNames}));
136+
137+
},
138+
[invitation.requestedAuthnContext, eduIDIdP, selectedRoles, acrValues])
109139

110140
const setInitialRole = markedRoles => {
111141
const urlSearchParams = new URLSearchParams(window.location.search);
@@ -255,37 +285,6 @@ export const InvitationForm = () => {
255285
}
256286
}
257287

258-
const renderACRWarnings = () => {
259-
if (isEmpty(invitation.requestedAuthnContext) || isEmpty(eduIDIdP) || isEmpty(selectedRoles)) {
260-
return null;
261-
}
262-
//Filter out the roles that are linked to applications that are not present in the mfaEntities of the eduIDIdp
263-
//or where the MFA level does not equal the requestedAuthnContext. If the requestedAuthnContext === TransparentAuthnContext,
264-
//then we skip the warning
265-
const mfaEntities = eduIDIdP.mfaEntities;
266-
const acrValue = acrValues[invitation.requestedAuthnContext];
267-
const missingEntities = selectedRoles.reduce((acc, role) => {
268-
const missingMfaApps = role.applicationMaps
269-
.filter(app => {
270-
const mfa = mfaEntities.find(mfa => mfa.name === app.entityid);
271-
return isEmpty(mfa) || (mfa.level !== acrValue && mfa.level !== acrValues.TransparentAuthnContext);
272-
});
273-
if (!isEmpty(missingMfaApps)) {
274-
acc.applications = acc.applications.concat(missingMfaApps.map(app => app[`name:${I18n.locale}`] || app["name:en"]));
275-
acc.roles.push(role.name)
276-
}
277-
return acc;
278-
}, {applications: [], roles: []})
279-
if (isEmpty(missingEntities.roles)) {
280-
return null;
281-
}
282-
const roleNames = splitListSemantically(missingEntities.roles, I18n.t("forms.and"));
283-
const applicationNames = splitListSemantically(missingEntities.applications, I18n.t("forms.and"));
284-
const html = DOMPurify.sanitize(I18n.t("invitations.requestedAuthnContextWarning",
285-
{roles: roleNames, applications: applicationNames}));
286-
return <p className="warning" dangerouslySetInnerHTML={{__html: html}}/>
287-
}
288-
289288
const authorityChanged = option => {
290289
setInvitation({
291290
...invitation,
@@ -478,7 +477,8 @@ export const InvitationForm = () => {
478477
clearable={true}
479478
onChange={requestedAuthnContextChanged}
480479
>
481-
{renderACRWarnings()}
480+
{acrWarning &&
481+
<p className="warning" dangerouslySetInnerHTML={{__html: acrWarning}}/>}
482482
</SelectField>}
483483

484484
{(invitation.intendedAuthority !== AUTHORITIES.GUEST && !isInviter &&

0 commit comments

Comments
 (0)