diff --git a/client/src/components/RoleCard.jsx b/client/src/components/RoleCard.jsx
index a309a670..106191eb 100644
--- a/client/src/components/RoleCard.jsx
+++ b/client/src/components/RoleCard.jsx
@@ -5,12 +5,19 @@ import I18n from "../locale/I18n";
import {MoreLessText} from "./MoreLessText";
import {Button, Card, CardType, Checkbox, Chip, ChipType} from "@surfnet/sds";
import {useNavigate} from "react-router-dom";
-import {isEmpty} from "../utils/Utils";
+import {isEmpty, splitListSemantically} from "../utils/Utils";
+import {roleName} from "../utils/Manage";
+import {ReactComponent as MultipleIcon} from "../icons/multi-role.svg";
export const RoleCard = ({role, index, invitationSelected, invitationSelectCallback, isNew = false}) => {
const navigate = useNavigate();
- const application = role.isUserRole ? role.role.application : role.application;
- const logo = application.logo;
+
+ const applications = role.isUserRole ? role.role.applicationMaps : role.applicationMaps;
+ const multiApp = applications.length === 1;
+ const application = applications[0];
+ const logo = multiApp ? application.logo :
+ const name = multiApp ? splitListSemantically(applications.map(app => roleName(app)), I18n.t("forms.and")) :
+ roleName(application);
const children =
@@ -21,7 +28,7 @@ export const RoleCard = ({role, index, invitationSelected, invitationSelectCallb
}
- {application[`name:${I18n.locale}`]} ({application[`OrganizationName:${I18n.locale}`]})
+ {name}
{role.name}
diff --git a/client/src/components/RoleCard.scss b/client/src/components/RoleCard.scss
index a90d737f..58034235 100644
--- a/client/src/components/RoleCard.scss
+++ b/client/src/components/RoleCard.scss
@@ -66,7 +66,7 @@
}
}
- img.provider, svg.provider {
+ img.provider, svg.provider, svg.multi-role {
height: 90px;
width: auto;
margin: 0 35px auto 0;
diff --git a/client/src/pages/Invitation.js b/client/src/pages/Invitation.js
index fccd560b..5634bbdb 100644
--- a/client/src/pages/Invitation.js
+++ b/client/src/pages/Invitation.js
@@ -115,7 +115,12 @@ export const Invitation = ({authenticated}) => {
}
const organisationName = role => {
- return ` (${role.application["OrganizationName:en"]})`;
+ if (role.applicationMaps.length === 1) {
+ const name = role.applicationMaps[0][`OrganizationName:${I18n.locale}`] || role.applicationMaps[0]["OrganizationName:en"];
+ return ` (${name})`;
+ }
+ const set = new Set(role.applicationMaps.map(app => app[`OrganizationName:${I18n.locale}`] || app["OrganizationName:en"]));
+ return ` (${splitListSemantically([...set], I18n.t("forms.and"))})`
}
const renderLoginStep = () => {
diff --git a/client/src/pages/Role.js b/client/src/pages/Role.js
index 7d13a3b4..7481f171 100644
--- a/client/src/pages/Role.js
+++ b/client/src/pages/Role.js
@@ -58,7 +58,7 @@ export const Role = () => {
}
Promise.all([roleByID(id, false), userRolesByRoleId(id), invitationsByRoleId(id)])
.then(res => {
- deriveApplicationAttributes(res[0], I18n.locale, I18n.t("roles.multiple"))
+ deriveApplicationAttributes(res[0], I18n.locale, I18n.t("roles.multiple"), I18n.t("forms.and"))
setRole(res[0]);
setUserRole(res[1].find(userRole => userRole.role.id === res[0].id && userRole.userInfo.id === user.id));
const newTabs = [
diff --git a/client/src/tabs/Applications.js b/client/src/tabs/Applications.js
index 9c3f12bc..3d60bc9a 100644
--- a/client/src/tabs/Applications.js
+++ b/client/src/tabs/Applications.js
@@ -118,7 +118,7 @@ const Applications = () => {
searchAttributes={["name", "provider", "provisioning"]}
rowLinkMapper={isUserAllowed(AUTHORITIES.INVITER, user) ? openRole : null}
inputFocus={true}
- rowClassNameResolver={entity => entity.applications.length > 1 ? "multi-role" : ""}>
+ rowClassNameResolver={entity => (entity.applications || []).length > 1 ? "multi-role" : ""}>
diff --git a/client/src/tabs/Roles.js b/client/src/tabs/Roles.js
index 833d2b85..167f2c7e 100644
--- a/client/src/tabs/Roles.js
+++ b/client/src/tabs/Roles.js
@@ -220,7 +220,7 @@ export const Roles = () => {
filters={filter(filterOptions, filterValue)}
customSearch={roleSearchRequired && isSuperUser ? search : null}
rowLinkMapper={isUserAllowed(AUTHORITIES.INVITER, user) ? openRole : null}
- rowClassNameResolver={entity => entity.applications.length > 1 ? "multi-role" : ""}
+ rowClassNameResolver={entity => (entity.applications || []) .length > 1 ? "multi-role" : ""}
busy={searching}/>
);
diff --git a/client/src/utils/Manage.js b/client/src/utils/Manage.js
index 509e8728..2b27cd28 100644
--- a/client/src/utils/Manage.js
+++ b/client/src/utils/Manage.js
@@ -1,5 +1,6 @@
-import {isEmpty} from "./Utils";
+import {isEmpty, splitListSemantically} from "./Utils";
import {ReactComponent as MultipleIcon} from "../icons/multi-role.svg";
+import I18n from "../locale/I18n";
export const singleProviderToOption = provider => {
const organisation = provider["OrganizationName:en"];
@@ -15,11 +16,17 @@ export const singleProviderToOption = provider => {
};
}
+export const roleName = app => {
+ const name = app[`name:${I18n.locale}`] || app["name:en"]
+ const orgName = app[`OrganizationName:${I18n.locale}`] || app["OrganizationName:en"]
+ return `${name} (${orgName})`;
+}
+
export const providersToOptions = providers => {
return providers.map(provider => singleProviderToOption(provider));
}
-export const deriveApplicationAttributes = (role, locale, multiple) => {
+export const deriveApplicationAttributes = (role, locale, multiple, separator) => {
const applications = role.applicationMaps;
if (!isEmpty(applications)) {
if (applications.length === 1) {
@@ -28,9 +35,9 @@ export const deriveApplicationAttributes = (role, locale, multiple) => {
role.logo = applications[0].logo;
} else {
role.applicationName = multiple;
- role.applicationOrganizationName = applications
- .map(app => app[`OrganizationName:${locale}`] || app["OrganizationName:en"])
- .join(", ")
+ const orgNames = new Set(applications
+ .map(app => app[`OrganizationName:${locale}`] || app["OrganizationName:en"]));
+ role.applicationOrganizationName = splitListSemantically([...orgNames], separator);
role.logo = ;
}
}
diff --git a/client/src/utils/UserRole.js b/client/src/utils/UserRole.js
index ced617c5..ebc2ab6c 100644
--- a/client/src/utils/UserRole.js
+++ b/client/src/utils/UserRole.js
@@ -1,5 +1,6 @@
import {isEmpty} from "./Utils";
import {deriveApplicationAttributes} from "./Manage";
+import I18n from "../locale/I18n";
export const INVITATION_STATUS = {
OPEN: "OPEN",
@@ -104,13 +105,13 @@ export const markAndFilterRoles = (user, allRoles, locale, multiple) => {
role.isUserRole = false;
role.label = role.name;
role.value = role.id;
- deriveApplicationAttributes(role, locale, multiple);
+ deriveApplicationAttributes(role, locale, multiple, I18n.t("forms.and"));
});
const userRoles = user.userRoles;
userRoles.forEach(userRole => {
userRole.isUserRole = true;
const role = userRole.role;
- deriveApplicationAttributes(role, locale, multiple);
+ deriveApplicationAttributes(role, locale, multiple, I18n.t("forms.and"));
userRole.name = role.name;
userRole.label = role.name;
userRole.value = role.id;
diff --git a/welcome/src/components/RoleCard.jsx b/welcome/src/components/RoleCard.jsx
index 66543a87..e4be39e5 100644
--- a/welcome/src/components/RoleCard.jsx
+++ b/welcome/src/components/RoleCard.jsx
@@ -4,17 +4,24 @@ import Logo from "./Logo";
import I18n from "../locale/I18n";
import {MoreLessText} from "./MoreLessText";
import {Button, Card, CardType, Chip, ChipType} from "@surfnet/sds";
-import {isEmpty, sanitizeURL} from "../utils/Utils";
-
+import {isEmpty, sanitizeURL, splitListSemantically} from "../utils/Utils";
+import {ReactComponent as MultipleIcon} from "../icons/multi-role.svg";
+import {roleName} from "../utils/Manage";
export const RoleCard = ({role, index, isNew = false, skipLaunch= false}) => {
- const application = role.application;
+ const applications = role.applicationMaps;
+ const multiApp = applications.length === 1;
+ const application = applications[0];
+ const logo = multiApp ? application.logo :
+ const name = multiApp ? splitListSemantically(applications.map(app => roleName(app)), I18n.t("forms.and")) :
+ roleName(application);
+
const children =
-
+
- {application[`name:${I18n.locale}`]} ({application[`OrganizationName:${I18n.locale}`]})
+ {name}
{role.name}
diff --git a/welcome/src/icons/multi-role.svg b/welcome/src/icons/multi-role.svg
new file mode 100644
index 00000000..feafbf55
--- /dev/null
+++ b/welcome/src/icons/multi-role.svg
@@ -0,0 +1,5 @@
+
diff --git a/welcome/src/locale/en.js b/welcome/src/locale/en.js
index 93fd2346..24ac7bd5 100644
--- a/welcome/src/locale/en.js
+++ b/welcome/src/locale/en.js
@@ -44,6 +44,9 @@ const en = {
rolesInfo: "You have access to the following applications.",
expiryDays: "Expiry days"
},
+ roles: {
+ multiple: "Multiple applications",
+ },
forms: {
ok: "Ok",
and: "and",
diff --git a/welcome/src/locale/nl.js b/welcome/src/locale/nl.js
index 65cc0a95..71f34e4a 100644
--- a/welcome/src/locale/nl.js
+++ b/welcome/src/locale/nl.js
@@ -44,6 +44,9 @@ const nl = {
rolesInfo: "Je bezit de volgende rollen.",
expiryDays: "Verloopdagen"
},
+ roles: {
+ multiple: "Meedere applicaties",
+ },
forms: {
ok: "Ok",
and: "en",
diff --git a/welcome/src/pages/Invitation.js b/welcome/src/pages/Invitation.js
index 4d753880..bc878939 100644
--- a/welcome/src/pages/Invitation.js
+++ b/welcome/src/pages/Invitation.js
@@ -136,7 +136,8 @@ export const Invitation = ({authenticated}) => {
const renderLoginStep = () => {
let html = DOMPurify.sanitize(I18n.t("invitationAccept.invited", {
type: I18n.t("invitationAccept.role"),
- roles: splitListSemantically(invitation.roles.map(invitationRole => `${invitationRole.role.name}${organisationName(invitationRole)}`), I18n.t("forms.and")),
+ roles: splitListSemantically(invitation.roles
+ .map(invitationRole => `${invitationRole.role.name}${organisationName(invitationRole.role.applicationMaps)}`), I18n.t("forms.and")),
inviter: invitation.inviter.name,
plural: invitation.roles.length === 1 ? I18n.t("invitationAccept.role") : I18n.t("invitationAccept.roles"),
email: invitation.inviter.email
diff --git a/welcome/src/utils/Manage.js b/welcome/src/utils/Manage.js
index ba8cf287..ca3b78f4 100644
--- a/welcome/src/utils/Manage.js
+++ b/welcome/src/utils/Manage.js
@@ -1,3 +1,17 @@
-export const organisationName = invitationRole => {
- return ` (${invitationRole.role.application["OrganizationName:en"]})`;
+import I18n from "../locale/I18n";
+import {splitListSemantically} from "./Utils";
+
+export const organisationName = apps => {
+ if (apps.length === 1) {
+ return ` (${apps[0]["OrganizationName:en"]})`;
+ } else {
+ const set = new Set(apps.map(app => app["OrganizationName:en"]).sort());
+ return splitListSemantically([...set], I18n.t("forms.and"));
+ }
+}
+
+export const roleName = app => {
+ const name = app[`name:${I18n.locale}`] || app["name:en"]
+ const orgName = app[`OrganizationName:${I18n.locale}`] || app["OrganizationName:en"]
+ return `${name} (${orgName})`;
}