Skip to content

Commit

Permalink
Differentiate between card per app and card per role
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Dec 20, 2023
1 parent f404600 commit 2150ee1
Show file tree
Hide file tree
Showing 23 changed files with 186 additions and 135 deletions.
61 changes: 61 additions & 0 deletions client/src/components/InvitationRoleCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from "react";
import "./RoleCard.scss";
import Logo from "./Logo";
import I18n from "../locale/I18n";
import {MoreLessText} from "./MoreLessText";
import {Button, Card, CardType, Checkbox, Chip, ChipType} from "@surfnet/sds";
import {isEmpty, splitListSemantically} from "../utils/Utils";
import {roleName} from "../utils/Manage";
import {ReactComponent as MultipleIcon} from "../icons/multi-role.svg";
import {useNavigate} from "react-router-dom";

export const InvitationRoleCard = ({
role,
applicationMaps,
index,
invitationSelected,
invitationSelectCallback,
isNew = false
}) => {
const navigate = useNavigate();

const multiApp = applicationMaps.length > 1;
const application = applicationMaps[0];
const logo = multiApp ?<MultipleIcon/> : application.logo;
const name = multiApp ? splitListSemantically(applicationMaps.map(app => roleName(app, I18n.locale)), I18n.t("forms.and")) :
roleName(application, I18n.locale);

const children =
<div key={index} className="user-role">
{!isEmpty(invitationSelected) &&
<Checkbox name={`invitationSelected-${index}-${role.value}`}
value={invitationSelected}
onChange={e => invitationSelectCallback(e, role.value)}/>
}

<Logo src={logo} alt={"provider"} className={"provider"}/>
<section className={"user-role-info"}>
<p>{name}</p>
<h3>{role.name}</h3>
<MoreLessText txt={role.description} cutOffNumber={80}/>
</section>
{isEmpty(invitationSelected) && <div className={"launch"}>
<Button txt={I18n.t("inviter.details")} onClick={() => navigate(`/roles/${role.id}`)}/>
</div>}

</div>;

const inviterCard = invitationSelected ? "inviter-selected" : "inviter"
const className = `card-container ${isNew ? "is-new" : ""} ${inviterCard}`;
return (
<div className={className}>
{isNew &&
<Chip label={I18n.t("proceed.new")} type={ChipType.Status_error}/>
}
{isEmpty(inviterCard) && <Card key={index} cardType={CardType.Big} children={children}/>}
{!isEmpty(inviterCard) &&
<label htmlFor={`invitationSelected-${index}-${role.value}`}> <Card key={index} cardType={CardType.Big}
children={children}/></label>}
</div>
);
}
39 changes: 15 additions & 24 deletions client/src/components/RoleCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,38 @@ 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, splitListSemantically} from "../utils/Utils";
import {isEmpty} 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}) => {
export const RoleCard = ({
role,
applicationMap,
index,
isNew = false
}) => {
const navigate = useNavigate();

const applications = role.isUserRole ? role.role.applicationMaps : role.applicationMaps;
const multiApp = applications.length === 1;
const application = applications[0];
const logo = multiApp ? application.logo : <MultipleIcon/>
const name = multiApp ? splitListSemantically(applications.map(app => roleName(app, I18n.locale)), I18n.t("forms.and")) :
roleName(application, I18n.locale);

const children =
<div key={index} className="user-role" >
{!isEmpty(invitationSelected) &&
<Checkbox name={`invitationSelected-${index}-${role.value}`}
value={invitationSelected}
onChange={e => invitationSelectCallback(e, role.value)}/>
}
<Logo src={logo} alt={"provider"} className={"provider"}/>
<Logo src={applicationMap.logo} alt={"provider"} className={"provider"}/>
<section className={"user-role-info"}>
<p>{name}</p>
<h3>{role.name}</h3>
<p>{role.name}</p>
<h3>{roleName(applicationMap, I18n.locale)}</h3>
<MoreLessText txt={role.description} cutOffNumber={80}/>
</section>
{isEmpty(invitationSelected) && <div className={"launch"}>
<div className={"launch"}>
<Button txt={I18n.t("inviter.details")} onClick={() => navigate(`/roles/${role.id}`)}/>
</div>}
</div>

</div>;
const inviterCard = isEmpty(invitationSelected) ? "" : (invitationSelected ? "inviter-selected" : "inviter")
const className = `card-container ${isNew ? "is-new" : ""} ${inviterCard}`;

const className = `card-container ${isNew ? "is-new" : ""}`;
return (
<div className={className}>
{isNew &&
<Chip label={I18n.t("proceed.new")} type={ChipType.Status_error}/>
}
{isEmpty(inviterCard) && <Card key={index} cardType={CardType.Big} children={children}/>}
{!isEmpty(inviterCard) && <label htmlFor={`invitationSelected-${index}-${role.value}`}> <Card key={index} cardType={CardType.Big} children={children}/></label>}
<Card key={index} cardType={CardType.Big} children={children}/>
</div>
);
}
40 changes: 0 additions & 40 deletions client/src/components/RoleMetaData.jsx

This file was deleted.

Empty file.
10 changes: 9 additions & 1 deletion client/src/components/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,15 @@ export const User = ({user, other, config}) => {

const renderUserRole = (userRole, index) => {
const role = userRole.role;
return <RoleCard role={role} index={index} key={index}/>
return (
<React.Fragment key={index}>
{role.applicationMaps.map((applicationMap, i) =>
<RoleCard role={role}
key={i}
applicationMap={applicationMap}
index={i}/>)}
</React.Fragment>
)
}

const filterApplication = application => {
Expand Down
33 changes: 21 additions & 12 deletions client/src/pages/InvitationForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import SelectField from "../components/SelectField";
import {DateField} from "../components/DateField";
import EmailField from "../components/EmailField";
import {displayExpiryDate, futureDate} from "../utils/Date";
import {RoleCard} from "../components/RoleCard";
import SwitchField from "../components/SwitchField";
import {InvitationRoleCard} from "../components/InvitationRoleCard";

export const InvitationForm = () => {
const location = useLocation();
Expand Down Expand Up @@ -181,6 +181,19 @@ export const InvitationForm = () => {

}

const renderUserRole = (role, index, invitationSelected, invitationSelectCallback) => {
const applicationMaps = role.isUserRole ? role.role.applicationMaps : role.applicationMaps;
return (
<InvitationRoleCard role={role}
index={index}
applicationMaps={applicationMaps}
key={index}
invitationSelected={invitationSelected}
invitationSelectCallback={invitationSelectCallback}
/>
)
}

const renderForm = isInviter => {
const disabledSubmit = !initial && !isValid();
const authorityOptions = allowedAuthoritiesForInvitation(user, selectedRoles)
Expand All @@ -192,17 +205,13 @@ export const InvitationForm = () => {
{I18n.t("invitations.inviterRoles")}
<Tooltip tip={I18n.t("tooltips.rolesTooltip")}/>
</span>
{roles.map((role, index) =>
<RoleCard role={role}
index={index}
key={index}
invitationSelected={selectedRoles.some(r => r.value === role.value)}
invitationSelectCallback={(e, value) => {
const checked = e.target.checked;
const roleSelected = roles.find(r => r.value === value);
const newSelectedRoles = checked ? selectedRoles.concat(roleSelected) : selectedRoles.filter(r => r.value !== roleSelected.value);
rolesChanged(newSelectedRoles);
}}/>)
{roles.map((role, index) => renderUserRole(role, index, selectedRoles.some(r => r.value === role.value),
(e, value) => {
const checked = e.target.checked;
const roleSelected = roles.find(r => r.value === value);
const newSelectedRoles = checked ? selectedRoles.concat(roleSelected) : selectedRoles.filter(r => r.value !== roleSelected.value);
rolesChanged(newSelectedRoles);
}))
}
{(!initial && isEmpty(selectedRoles)) &&
<ErrorIndicator msg={I18n.t("invitations.requiredRole")} adjustMargin={true}/>
Expand Down
20 changes: 15 additions & 5 deletions client/src/pages/Inviter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import {Button, Tooltip} from "@surfnet/sds";
import {useAppStore} from "../stores/AppStore";
import HappyLogo from "../icons/landing/undraw_startled_-8-p0r.svg";
import DOMPurify from "dompurify";
import {RoleCard} from "../components/RoleCard";
import {stopEvent} from "../utils/Utils";
import {useNavigate} from "react-router-dom";
import {InvitationRoleCard} from "../components/InvitationRoleCard";

export const Inviter = () => {

Expand All @@ -28,6 +28,19 @@ export const Inviter = () => {
navigate("/invitations")
}

const renderUserRole = (role, index) => {
const applicationMaps = role.applicationMaps;
return (
<InvitationRoleCard role={role}
index={index}
applicationMaps={applicationMaps}
key={index}
isNew={false}

/>
)
}

return (
<div className="mod-inviter">
<div className="inviter-container">
Expand All @@ -49,10 +62,7 @@ export const Inviter = () => {
</div>
</div>
<h3 className={"sub-info"}>{I18n.t("inviter.manage")}</h3>
{user.userRoles.map((userRole, index) => <RoleCard key={index}
role={userRole.role}
isNew={false}
index={index}/>)}
{user.userRoles.map((userRole, index) => renderUserRole(userRole.role, index))}
</div>
</div>);
};
2 changes: 1 addition & 1 deletion client/src/pages/Role.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export const Role = () => {
</div>
<div className={"meta-data-row"}>
<WebsiteIcon/>
<a href={role.landingPage}
<a href={role.applicationUsages[0].landingPage}
rel="noreferrer"
target="_blank">
<span className={"application-name"}>{`${role.applicationNames}`}</span>
Expand Down
9 changes: 6 additions & 3 deletions server/src/main/java/access/api/RoleController.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,15 @@ public ResponseEntity<Void> deleteRole(@PathVariable("id") Long id, @Parameter(h
}

private ResponseEntity<Role> saveOrUpdate(Role role, User user) {
if (StringUtils.hasText(role.getLandingPage()) && !urlFormatValidator.isValid(role.getLandingPage())) {
throw new InvalidInputException();
}
if (CollectionUtils.isEmpty(role.getApplicationUsages())) {
throw new InvalidInputException();
}
role.getApplicationUsages().forEach(applicationUsage -> {
if (StringUtils.hasText(applicationUsage.getLandingPage()) && !urlFormatValidator.isValid(applicationUsage.getLandingPage())) {
throw new InvalidInputException();
}
});

manage.addManageMetaData(List.of(role));
List<String> manageIdentifiers = role.applicationsUsed().stream().map(Application::getManageId).toList();
UserPermissions.assertManagerRole(manageIdentifiers, user);
Expand Down
9 changes: 7 additions & 2 deletions server/src/main/java/access/manage/Manage.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,13 @@ default List<Role> addManageMetaData(List<Role> roles) {
.collect(Collectors.toMap(map -> (String) map.get("id"), map -> map));
//Add the metadata to the role
roles.forEach(role -> role.setApplicationMaps(
role.applicationsUsed().stream()
.map(application -> transformProvider(remoteApplications.get(application.getManageId()))).toList()));
role.getApplicationUsages().stream()
.map(applicationUsage -> {
Map<String, Object> applicationMap = transformProvider(remoteApplications.get(applicationUsage.getApplication().getManageId()));
applicationMap.put("landingPage", applicationUsage.getLandingPage());
return applicationMap;
})
.toList()));
return roles;
}

Expand Down
8 changes: 1 addition & 7 deletions server/src/main/java/access/model/Role.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ public class Role implements Serializable, Provisionable {
@Column(name = "description")
private String description;

@Column(name = "landing_page")
private String landingPage;

@Column(name = "urn")
private String urn;

Expand Down Expand Up @@ -86,19 +83,17 @@ public class Role implements Serializable, Provisionable {

public Role(String name,
String description,
String landingPage,
Set<ApplicationUsage> applicationUsages,
Integer defaultExpiryDays,
boolean enforceEmailEquality,
boolean eduIDOnly) {
this(name, GroupURN.sanitizeRoleShortName(name), description, landingPage, applicationUsages,
this(name, GroupURN.sanitizeRoleShortName(name), description, applicationUsages,
defaultExpiryDays, enforceEmailEquality, eduIDOnly, Collections.emptyList());
}

public Role(@NotNull String name,
@NotNull String shortName,
String description,
String landingPage,
Set<ApplicationUsage> applicationUsages,
Integer defaultExpiryDays,
boolean enforceEmailEquality,
Expand All @@ -107,7 +102,6 @@ public Role(@NotNull String name,
this.name = name;
this.shortName = shortName;
this.description = description;
this.landingPage = landingPage;
this.defaultExpiryDays = defaultExpiryDays;
this.enforceEmailEquality = enforceEmailEquality;
this.eduIDOnly = eduIDOnly;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `roles` DROP `landing_page`;
Loading

0 comments on commit 2150ee1

Please sign in to comment.