+ mapper: role => role.unknownInManage ?
:
{typeof role.logo === "string" ?
: role.logo}
},
{
key: "applicationName",
header: I18n.t("roles.applicationName"),
- mapper: role =>
{role.applicationName}
+ mapper: role => role.unknownInManage ?
{I18n.t("roles.unknownInManage")} :
+
{role.applicationName}
},
{
key: "name",
diff --git a/client/src/tabs/Roles.scss b/client/src/tabs/Roles.scss
index 4e46036f..1cba92c6 100644
--- a/client/src/tabs/Roles.scss
+++ b/client/src/tabs/Roles.scss
@@ -66,6 +66,15 @@ div.mod-roles {
td.authority, td.defaultExpiryDays, td.userRoleCount {
text-align: center;
}
+
+ .unknown-in-manage {
+ color: var(--sds--color--red--500);
+ font-weight: 600;
+ svg {
+ margin-left: 15px;
+ }
+ }
+
}
}
diff --git a/client/src/tabs/RolesUnknownInManage.js b/client/src/tabs/RolesUnknownInManage.js
new file mode 100644
index 00000000..b4f60973
--- /dev/null
+++ b/client/src/tabs/RolesUnknownInManage.js
@@ -0,0 +1,105 @@
+import "./RolesUnknownInManage.scss";
+import {useAppStore} from "../stores/AppStore";
+import React, {useEffect, useState} from "react";
+import {Entities} from "../components/Entities";
+import I18n from "../locale/I18n";
+import {Chip, Loader} from "@surfnet/sds";
+import {useNavigate} from "react-router-dom";
+import {AUTHORITIES, isUserAllowed} from "../utils/UserRole";
+import {rolesUnknownInManage} from "../api";
+import {stopEvent} from "../utils/Utils";
+import {chipTypeForUserRole} from "../utils/Authority";
+import {ReactComponent as AlertLogo} from "@surfnet/sds/icons/functional-icons/alert-circle.svg";
+import {deriveApplicationAttributes} from "../utils/Manage";
+
+export const RolesUnknownInManage = () => {
+ const navigate = useNavigate();
+ const user = useAppStore(state => state.user);
+
+ const [loading, setLoading] = useState(true);
+ const [roles, setRoles] = useState([]);
+
+ useEffect(() => {
+ if (isUserAllowed(AUTHORITIES.SUPER_USER, user)) {
+ rolesUnknownInManage()
+ .then(res => {
+ deriveApplicationAttributes(res, I18n.locale, I18n.t("roles.multiple"), I18n.t("forms.and"))
+ setRoles(res);
+ setLoading(false);
+ })
+ } else {
+ navigate("/404")
+ }
+ }, [user]);// eslint-disable-line react-hooks/exhaustive-deps
+
+
+ const openRole = (e, role) => {
+ const path = `/roles/${role.id}`
+ if (e.metaKey || e.ctrlKey) {
+ window.open(path, '_blank');
+ } else {
+ stopEvent(e);
+ navigate(path);
+ }
+ };
+
+ const columns = [
+ {
+ nonSortable: true,
+ key: "logo",
+ header: "",
+ mapper: () =>
+ },
+ {
+ key: "applicationName",
+ header: I18n.t("roles.applicationName"),
+ mapper: role =>
{I18n.t("roles.unknownInManage")}
+ },
+ {
+ key: "name",
+ header: I18n.t("roles.accessRole"),
+ mapper: role =>
{role.name}
+ },
+ {
+ key: "description",
+ header: I18n.t("roles.description"),
+ mapper: role =>
{role.description}
+ },
+ {
+ key: "authority",
+ header: I18n.t("roles.authority"),
+ mapper: role =>
+ },
+ {
+ key: "userRoleCount",
+ header: I18n.t("roles.userRoleCount"),
+ mapper: role => role.userRoleCount
+ }
+
+ ];
+
+ if (loading) {
+ return
+ }
+
+ return (
+
+ (entity.applications || []).length > 1 ? "multi-role" : ""}/>
+
+ );
+
+}
diff --git a/client/src/tabs/RolesUnknownInManage.scss b/client/src/tabs/RolesUnknownInManage.scss
new file mode 100644
index 00000000..f887a06d
--- /dev/null
+++ b/client/src/tabs/RolesUnknownInManage.scss
@@ -0,0 +1,50 @@
+@import "../styles/vars.scss";
+
+div.mod-unknown-roles {
+
+ table.unknown-roles {
+
+ thead {
+ th {
+ &.applicationName {
+ width: 15%;
+ }
+
+ &.name {
+ width: 15%;
+ }
+
+ &.description {
+ width: 25%;
+ }
+
+ &.authority {
+ width: 20%;
+ text-align: center;
+ }
+
+ &.userRoleCount {
+ width: 15%;
+ text-align: center;
+ }
+
+ }
+ }
+
+ tbody {
+ td.authority, td.defaultExpiryDays, td.userRoleCount {
+ text-align: center;
+ }
+
+ .unknown-in-manage {
+ color: var(--sds--color--red--500);
+ font-weight: 600;
+ svg {
+ margin-left: 15px;
+ }
+ }
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/client/src/utils/Manage.js b/client/src/utils/Manage.js
index b38adcea..bc4aa129 100644
--- a/client/src/utils/Manage.js
+++ b/client/src/utils/Manage.js
@@ -33,12 +33,19 @@ export const deriveApplicationAttributes = (role, locale, multiple, separator) =
const applications = role.applicationMaps;
if (!isEmpty(applications)) {
if (applications.length === 1) {
- role.applicationName = applications[0][`name:${locale}`] || applications[0]["name:en"];
+ const firstApplication = applications[0];
+ if (firstApplication.unknown) {
+ role.unknownInManage = true;
+ }
+ role.applicationName = firstApplication[`name:${locale}`] || firstApplication["name:en"];
role.applicationNames = role.applicationName;
- role.applicationOrganizationName = applications[0][`OrganizationName:${locale}`] || applications[0]["OrganizationName:en"];
- role.logo = applications[0].logo;
+ role.applicationOrganizationName = firstApplication[`OrganizationName:${locale}`] || firstApplication["OrganizationName:en"];
+ role.logo = firstApplication.logo;
} else {
role.applicationName = multiple;
+ if (applications.every(app => app.unknown)) {
+ role.unknownInManage = true;
+ }
const appNames = new Set(applications
.map(app => app[`name:${locale}`] || app["name:en"]));
role.applicationNames = splitListSemantically([...appNames], separator);
diff --git a/server/src/main/java/access/aggregation/AttributeAggregatorController.java b/server/src/main/java/access/aggregation/AttributeAggregatorController.java
index 74cab12e..98a959b9 100644
--- a/server/src/main/java/access/aggregation/AttributeAggregatorController.java
+++ b/server/src/main/java/access/aggregation/AttributeAggregatorController.java
@@ -7,6 +7,8 @@
import access.provision.scim.GroupURN;
import access.repository.UserRepository;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -26,6 +28,8 @@
@SecurityRequirement(name = ATTRIBUTE_AGGREGATION_SCHEME_NAME)
public class AttributeAggregatorController {
+ private static final Log LOG = LogFactory.getLog(AttributeAggregatorController.class);
+
private final UserRepository userRepository;
private final Manage manage;
private final String groupUrnPrefix;
@@ -42,9 +46,16 @@ public AttributeAggregatorController(UserRepository userRepository,
@PreAuthorize("hasRole('ATTRIBUTE_AGGREGATION')")
public ResponseEntity
>> getGroupMemberships(@PathVariable("unspecified_id") String unspecifiedId,
@RequestParam("SPentityID") String spEntityId) {
- Optional