Skip to content

Commit

Permalink
Multiple manage entities for role - client side
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Nov 27, 2023
1 parent da48db5 commit bf679b8
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 22 deletions.
4 changes: 3 additions & 1 deletion client/src/components/Entities.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const Entities = ({
newEntityPath,
newEntityFunc,
defaultSort,
rowClassNameResolver,
searchAutoFocus = false,
busy = false
}) => {
Expand Down Expand Up @@ -145,8 +146,9 @@ export const Entities = ({
}

const entityRow = (entity, index) => {
const additionalClassName = isEmpty(rowClassNameResolver) ? "" : rowClassNameResolver(entity);
return <tr key={`tr_${entity.id}_${index}`}
className={`${typeof rowLinkMapper === "function" ? "clickable" : ""} ${onHover ? "hoverable" : ""}`}>
className={`${typeof rowLinkMapper === "function" ? "clickable" : ""} ${onHover ? "hoverable" : ""} ${additionalClassName}`}>
{columns.map((column, i) =>
<td key={`td_${column.key}_${i}`}
onClick={e => (column.key !== "check" && !column.hasLink) ?
Expand Down
10 changes: 10 additions & 0 deletions client/src/components/Entities.scss
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@
cursor: pointer;
}

&.multi-role {
color: var(--sds--color--green--500)
}

.action-icons-container {
display: flex;
align-items: center;
Expand Down Expand Up @@ -252,6 +256,12 @@
height: auto;
margin-right: 5px;
}

svg.multi-role {
height: 36px;
width: auto;
margin-left: 15px;
}
}

.sds--chips span {
Expand Down
2 changes: 1 addition & 1 deletion client/src/icons/multi-role.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion client/src/pages/RoleForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const RoleForm = () => {
setRole({...role, applications: [providerOption]})
} else {
breadcrumbPath.push({path: `/roles/${res[0].id}`, value: name});
setManagementOption([singleProviderToOption(res[0].application)]);
setManagementOption(providersToOptions(res[0].applicationMaps));
}
breadcrumbPath.push({value: I18n.t(`roles.${newRole ? "new" : "edit"}`, {name: name})});
useAppStore.setState({breadcrumbPath: breadcrumbPath});
Expand Down
31 changes: 22 additions & 9 deletions client/src/tabs/Applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, {useEffect, useState} from "react";
import {Entities} from "../components/Entities";
import I18n from "../locale/I18n";
import {Loader} from "@surfnet/sds";
import {ReactComponent as MultipleIcon} from "../icons/multi-role.svg";
import {applications, rolesByApplication} from "../api";
import {isEmpty, splitListSemantically, stopEvent} from "../utils/Utils";
import {AUTHORITIES, isUserAllowed} from "../utils/UserRole";
Expand All @@ -26,9 +27,9 @@ const Applications = () => {
const providers = res[0].providers;
const provisionings = res[0].provisionings;
res[1].forEach(role => {
role.logo = providerLogoById(role.manageId, providers);
role.provider = providerById(role.manageId, providers);
role.provisioning = provisioningsByProviderId(role.manageId, provisionings);
role.logo = providerLogoById(role.applicationMaps, providers);
role.provider = providerById(role.applicationMaps, providers);
role.provisioning = provisioningsByProviderId(role.applicationMaps, provisionings);
})
setRoles(res[1]);
setLoading(false);
Expand All @@ -51,21 +52,30 @@ const Applications = () => {
}
};

const providerById = (manageId, allProviders) => {
const providerById = (manageMaps, allProviders) => {
if (manageMaps.length > 1) {
return I18n.t("roles.multiple");
}
const manageId = manageMaps[0].id
const provider = allProviders.find(provider => provider.id === manageId) || providerInfo(null);
const organisation = provider["OrganizationName:en"];
const organisationValue = isEmpty(organisation) ? "" : ` (${organisation})`;
return `${provider["name:en"]}${organisationValue}`;
}

const providerLogoById = (manageId, allProviders) => {
const providerLogoById = (manageMaps, allProviders) => {
if (manageMaps.length > 1) {
return <MultipleIcon/>
}
const manageId = manageMaps[0].id
const provider = allProviders.find(provider => provider.id === manageId) || providerInfo(null);
return provider.logo;
}

const provisioningsByProviderId = (manageId, allProvisionings) => {
const provisioningsByProviderId = (manageMaps, allProvisionings) => {
const manageIdentifiers = manageMaps.map(m => m.id);
const providers = allProvisionings
.filter(provisioning => provisioning.applications.some(app => app.id === manageId))
.filter(provisioning => provisioning.applications.some(app => manageIdentifiers.includes( app.id)))
.map(provider => `${provider["name:en"]} (${provider.provisioning_type})`);
return splitListSemantically(providers, I18n.t("forms.and"));
}
Expand All @@ -75,7 +85,9 @@ const Applications = () => {
key: "logo",
header: "",
nonSortable: true,
mapper: role => <img src={role.logo} alt="logo"/>
mapper: role => <div className="role-icon">
{typeof role.logo === "string" ? <img src={role.logo} alt="logo"/> : role.logo}
</div>
},
{
key: "name",
Expand Down Expand Up @@ -105,7 +117,8 @@ const Applications = () => {
customNoEntities={I18n.t(`roles.noResults`)}
searchAttributes={["name", "provider", "provisioning"]}
rowLinkMapper={isUserAllowed(AUTHORITIES.INVITER, user) ? openRole : null}
inputFocus={true}>
inputFocus={true}
rowClassNameResolver={entity => entity.applications.length > 1 ? "multi-role" : ""}>
</Entities>

</div>
Expand Down
8 changes: 4 additions & 4 deletions client/src/tabs/Roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,11 @@ export const Roles = () => {
{
nonSortable: true,
key: "logo",

header: "",
mapper: role => {
return <div className="role-icon">
{typeof role.logo === "string" ? <img src={role.logo} alt="logo"/> :role.logo}
mapper: role => <div className="role-icon">
{typeof role.logo === "string" ? <img src={role.logo} alt="logo"/> : role.logo}
</div>
}
},
{
key: "applicationName",
Expand Down Expand Up @@ -221,6 +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" : ""}
busy={searching}/>
</div>
);
Expand Down
1 change: 0 additions & 1 deletion client/src/tabs/Roles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ div.mod-roles {
td.authority, td.defaultExpiryDays, td.userRoleCount {
text-align: center;
}

}
}

Expand Down
10 changes: 6 additions & 4 deletions client/src/utils/Manage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import {ReactComponent as MultipleIcon} from "../icons/multi-role.svg";
export const singleProviderToOption = provider => {
const organisation = provider["OrganizationName:en"];
const organisationValue = isEmpty(organisation) ? "" : ` (${organisation})`;
const manageType = provider.type ? provider.type.toUpperCase() : provider.manageType;
const manageId = provider.id || provider.manageId;
return {
value: provider.id,
value: manageId,
label: `${provider["name:en"]}${organisationValue}`,
type: provider.type.toUpperCase(),
manageType: provider.type.toUpperCase(),
manageId: provider.id
type: manageType,
manageType: manageType,
manageId: manageId
};
}

Expand Down
4 changes: 4 additions & 0 deletions client/src/utils/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export function isEmpty(obj) {
if (typeof obj === "string") {
return obj.trim().length === 0;
}
if (obj && obj.getTime) {
// eslint-disable-next-line
return obj.getTime() !== obj.getTime();
}
if (typeof obj === "object") {
return Object.keys(obj).length === 0;
}
Expand Down
2 changes: 1 addition & 1 deletion server/src/main/java/access/voot/VootController.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public ResponseEntity<List<Map<String, String>>> getGroupMemberships(@PathVariab
private Map<String, String> parseUserRole(UserRole userRole) {
Map<String, String> res = new HashMap<>();
Role role = userRole.getRole();
String urn = role.isTeamsOrigin() ? GroupURN.teamsUrnFromRole(teamsNameContext, role) : GroupURN.urnFromRole(groupUrnPrefix, userRole.getRole());
String urn = role.isTeamsOrigin() ? GroupURN.teamsUrnFromRole(teamsNameContext, role) : GroupURN.urnFromRole(groupUrnPrefix, role);
res.put("urn", urn);
res.put("name", role.getName());
return res;
Expand Down

0 comments on commit bf679b8

Please sign in to comment.