Skip to content

Commit

Permalink
WIp for new design
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Sep 21, 2023
1 parent 22ab694 commit 0026f9d
Show file tree
Hide file tree
Showing 21 changed files with 156 additions and 95 deletions.
11 changes: 5 additions & 6 deletions client/src/components/Entities.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,6 @@ export const Entities = ({
const filterClassName = !hideTitle && filters ? "filters-with-title" : `${modelName}-search-filters`;
return (
<section className="entities-search">
{showNew &&
<Button onClick={newEntity}
className={`${hideTitle && !filters ? "no-title" : ""}`}
txt={newLabel || I18n.t(`${modelName}.new`)}/>
}
{!hideTitle && <h2>{title || `${I18n.t(`${modelName}.title`)} (${entities.length})`}</h2>}
<div className={filterClassName}>{filters}</div>
<div className={`search ${showNew ? "" : "standalone"}`}>
Expand All @@ -106,8 +101,12 @@ export const Entities = ({
</div>
</div>
</div>}

</div>
{showNew &&
<Button onClick={newEntity}
className={`${hideTitle && !filters ? "no-title" : ""}`}
txt={newLabel || I18n.t(`${modelName}.new`)}/>
}
</section>
);
};
Expand Down
8 changes: 7 additions & 1 deletion client/src/components/Entities.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@
align-items: center;
padding: 32px 0 28px 0;
min-height: 40px;
justify-content: space-between;
justify-content: flex-end;

@media (max-width: $medium) {
flex-direction: column;
align-items: normal;
}

button {
margin-left: 25px;
}

h2 {
margin-right: auto;
@media (max-width: $medium) {
margin-bottom: 15px
}
Expand Down Expand Up @@ -139,6 +144,7 @@

&.logo {
width: 85px;
height: auto;
}

svg.fa-caret-up, svg.fa-caret-down {
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/UnitHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ export const UnitHeader = ({
</div>
<div className="obj-name">
{obj.name && <h1>{obj.name}</h1>}
{obj.application &&
<span className="name">{providerInfo(obj.application.data.metaDataFields["name:en"])}</span>}
{obj.applicationName &&
<span className="name">{obj.applicationName}</span>}
{(obj.description && displayDescription) &&
<MoreLessText txt={obj.description}/>
}
Expand Down
1 change: 1 addition & 0 deletions client/src/components/UnitHeader.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
max-height: 300px;
max-width: 300px;
border-radius: 5px;
margin-bottom: auto;
}

&.small {
Expand Down
10 changes: 8 additions & 2 deletions client/src/locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,18 @@ const en = {
expiryDays: "Expiry days"
},
roles: {
title: "Roles",
title: "Access Roles",
applicationName:"Application",
accessRole:"Name",
name: "Name",
namePlaceHolder: "The name of the role",
shortName: "Short name",
landingPage: "Website",
userRoleCount: "# Users",
landingPagePlaceHolder: "https://landingpage.com",
defaultExpiryDays: "Expiry days",
endDate: "End date",
noEndDate: "No end date",
authority: "Authority",
yourRole: "Your role",
description: "Description",
Expand Down Expand Up @@ -140,7 +144,8 @@ const en = {
searchPlaceHolder: "Search for user roles...",
noResults: "No user roles where found",
notAllowed: "You're not allowed to delete this user role because of missing roles",
updateConfirmation: "Are you sure you want to change the end date of role {{roleName}} for {{userName}}",
updateConfirmation: "Are you sure you want to change the end date of role {{roleName}} for {{userName}}",
updateConfirmationRemoveEndDate: "Are you sure you want to remove the end date of role {{roleName}} for {{userName}}",
updateFlash: "The end date for role {{roleName}} has been updated",
deleteConfirmation: "Are you sure you want to remove this role from this user(s)?",
deleteFlash: "User role(s) have been removed",
Expand All @@ -163,6 +168,7 @@ const en = {
newInvite: "New invite",
newGuest: "Invite guest",
invitees: "Invitees",
intendedRoles: "Roles",
inviteesPlaceholder: "Invitee email addresses",
requiredEmail: "At least one email is required",
requiredRole: "At least one role is required for an invitation",
Expand Down
6 changes: 3 additions & 3 deletions client/src/pages/Role.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ export const Role = () => {
setRole(res[0]);
setLoading(false);
const newTabs = [
<Page key="maintainers"
isUserAllowed(AUTHORITIES.MANAGER, user) ? <Page key="maintainers"
name="maintainers"
label={I18n.t("tabs.userRoles")}
Icon={UserLogo}>
<UserRoles role={res[0]}
guests={false}
userRoles={res[1].filter(userRole => userRole.authority !== "GUEST")}/>
</Page>,
</Page> : null,
<Page key="guests"
name="guests"
label={I18n.t("tabs.guestRoles")}
Expand All @@ -72,7 +72,7 @@ export const Role = () => {
preloadedInvitations={res[2]}/>
</Page>
];
setTabs(newTabs);
setTabs(newTabs.filter(tab => tab !== null));
})
.catch(() => navigate("/"))

Expand Down
2 changes: 1 addition & 1 deletion client/src/tabs/Invitations.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ export const Invitations = ({role, preloadedInvitations, standAlone = false}) =>
},
{
key: "intendedRoles",
header: I18n.t("roles.title"),
header: I18n.t("invitations.intendedRoles"),
mapper: invitation => invitation.intendedRoles
},
{
Expand Down
86 changes: 36 additions & 50 deletions client/src/tabs/Roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ import {useAppStore} from "../stores/AppStore";
import React, {useEffect, useState} from "react";
import {Entities} from "../components/Entities";
import I18n from "../locale/I18n";
import {Chip, Loader, Tooltip} from "@surfnet/sds";
import {Chip, Loader} from "@surfnet/sds";
import {useNavigate} from "react-router-dom";
import {AUTHORITIES, isUserAllowed, markAndFilterRoles} from "../utils/UserRole";
import {rolesByApplication, searchRoles} from "../api";
import {isEmpty, stopEvent} from "../utils/Utils";
import debounce from "lodash.debounce";
import {dateFromEpoch} from "../utils/Date";
import {ReactComponent as RoleIcon} from "@surfnet/sds/icons/illustrative-icons/hierarchy.svg";
import {chipTypeForUserRole} from "../utils/Authority";

export const Roles = () => {
Expand Down Expand Up @@ -77,32 +75,25 @@ export const Roles = () => {
</div>)
}

const landingPage = role => {
const url = role.isUserRole ? role.role.landingPage : role.landingPage;
if (isEmpty(url)) {
return "";
}
return <a href={url} rel="noreferrer" target="_blank">{url}</a>
}

const columns = [
{
nonSortable: true,
key: "icon",
key: "logo",
header: "",
mapper: role => <div className="role-icon">
<Tooltip standalone={true}
children={<RoleIcon/>}
tip={I18n.t("tooltips.roleIcon",
{
name: role.name,
createdAt: dateFromEpoch(role.isUserRole ? role.createdAt : role.auditable.createdAt)
})}/>
</div>
mapper: role => {
return <div className="role-icon">
<img src={role.application.data.metaDataFields["logo:0:url"]} alt="logo"/>
</div>
}
},
{
key: "applicationName",
header: I18n.t("roles.applicationName"),
mapper: role => <span>{role.applicationName}</span>
},
{
key: "name",
header: I18n.t("roles.name"),
header: I18n.t("roles.accessRole"),
mapper: role => <span>{role.name}</span>
},
{
Expand All @@ -113,20 +104,14 @@ export const Roles = () => {
{
key: "authority",
header: I18n.t("roles.authority"),
mapper: role => <Chip type={chipTypeForUserRole(role.authority)}
label={role.isUserRole ? I18n.t(`access.${role.authority}`) :
I18n.t("roles.noMember")}/>
},
{
key: "defaultExpiryDays",
header: I18n.t("users.expiryDays"),
mapper: role => role.isUserRole ? role.role.defaultExpiryDays : role.defaultExpiryDays
mapper: role => <Chip type={chipTypeForUserRole(role.authority)}
label={role.isUserRole ? I18n.t(`access.${role.authority}`) :
I18n.t("roles.noMember")}/>
},
{
key: "landingPage",
header: I18n.t("roles.landingPage"),
hasLink: true,
mapper: role => landingPage(role)
key: "userRoleCount",
header: I18n.t("roles.userRoleCount"),
mapper: role => role.userRoleCount
}

];
Expand All @@ -140,22 +125,23 @@ export const Roles = () => {

return (
<div className={"mod-roles"}>
<Entities entities={isSuperUser ? roles : roles.filter(role => !(role.isUserRole && role.authority === "GUEST"))}
modelName="roles"
showNew={isManager}
newLabel={I18n.t("roles.new")}
newEntityPath={"/role/new"}
defaultSort="name"
columns={columns}
searchAttributes={["name", "description", "landingPage"]}
customNoEntities={I18n.t(`roles.noResults`)}
loading={false}
inputFocus={true}
hideTitle={true}
filters={moreToShow && moreResultsAvailable()}
customSearch={roleSearchRequired && isSuperUser ? search : null}
rowLinkMapper={isUserAllowed(AUTHORITIES.INVITER, user) ? openRole : null}
busy={searching}/>
<Entities
entities={isSuperUser ? roles : roles.filter(role => !(role.isUserRole && role.authority === "GUEST"))}
modelName="roles"
showNew={isManager}
newLabel={I18n.t("roles.new")}
newEntityPath={"/role/new"}
defaultSort="name"
columns={columns}
searchAttributes={["name", "description", "applicationName"]}
customNoEntities={I18n.t(`roles.noResults`)}
loading={false}
inputFocus={true}
hideTitle={false}
filters={moreToShow && moreResultsAvailable()}
customSearch={roleSearchRequired && isSuperUser ? search : null}
rowLinkMapper={isUserAllowed(AUTHORITIES.INVITER, user) ? openRole : null}
busy={searching}/>
</div>
);

Expand Down
11 changes: 6 additions & 5 deletions client/src/tabs/Roles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ div.mod-roles {

thead {
th {
&.applicationName {
width: 15%;
}

&.name {
width: 15%;
}
Expand All @@ -19,19 +23,16 @@ div.mod-roles {
text-align: center;
}

&.defaultExpiryDays {
&.userRoleCount {
width: 15%;
text-align: center;
}

&.landingPage {
width: 25%;
}
}
}

tbody {
td.authority, td.defaultExpiryDays {
td.authority, td.defaultExpiryDays, td.userRoleCount {
text-align: center;
}

Expand Down
14 changes: 9 additions & 5 deletions client/src/tabs/UserRoles.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const UserRoles = ({role, guests, userRoles}) => {
setConfirmation({
cancel: () => setConfirmationOpen(false),
action: () => doUpdateEndDate(userRole, newEndDate, false),
question: I18n.t("userRoles.updateConfirmation", {
question: I18n.t(`userRoles.${isEmpty(newEndDate) ? "updateConfirmationRemoveEndDate":"updateConfirmation"}`, {
roleName: userRole.role.name,
userName: userRole.userInfo.name
}),
Expand Down Expand Up @@ -125,14 +125,18 @@ export const UserRoles = ({role, guests, userRoles}) => {
};

const displayEndDate = userRole => {
if (allowedToRenewUserRole(user, userRole) && userRole.endDate) {
if (allowedToRenewUserRole(user, userRole)) {
return (
<div className={"date-field-container"}>
{!userRole.endDate &&
<span className="no-end-date">
{I18n.t("roles.noEndDate")}
</span>}
<DateField
minDate={futureDate(1)}
value={new Date(userRole.endDate * 1000)}
value={userRole.endDate ? new Date(userRole.endDate * 1000) : null}
onChange={date => doUpdateEndDate(userRole, date, true)}
allowNull={false}
allowNull={true}
showYearDropdown={true}
/>
</div>
Expand Down Expand Up @@ -231,7 +235,7 @@ export const UserRoles = ({role, guests, userRoles}) => {
modelName="userRoles"
defaultSort="name"
columns={columns}
newLabel={I18n.t(guests ? "invitations.newGuest": "invitations.new")}
newLabel={I18n.t(guests ? "invitations.newGuest" : "invitations.new")}
showNew={true}
newEntityFunc={() => navigate("/invitation/new", {state: role.id})}
customNoEntities={I18n.t(`userRoles.noResults`)}
Expand Down
8 changes: 8 additions & 0 deletions client/src/tabs/UserRoles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@

.date-field-container {
display: flex;
position: relative;

.date-field {
margin-left: auto;
}

.no-end-date {
position: absolute;
z-index: 99;
top: 10px;
right: 130px;
}
}

table.userRoles {
Expand Down
11 changes: 11 additions & 0 deletions client/src/utils/Manage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {isEmpty} from "./Utils";
import I18n from "../locale/I18n";

export const singleProviderToOption = provider => {

Expand All @@ -15,6 +16,16 @@ export const providersToOptions = providers => {
return providers.map(provider => singleProviderToOption(provider));
}

export const deriveApplicationAttributes = role => {
const application = role.application;
if (!isEmpty(application)) {
const metaData = application.data.metaDataFields;
role.applicationName = metaData[`name:${I18n.locale}`] || metaData["name:en"]
role.applicationOrganizationName = metaData[`OrganizationName:${I18n.locale}`] || metaData["OrganizationName:en"];
role.logo = metaData["logo:0:url"] ;
}
}


export const providerInfo = provider => {
if (isEmpty(provider)) {
Expand Down
Loading

0 comments on commit 0026f9d

Please sign in to comment.