Skip to content

Commit 6bf9fa0

Browse files
committed
WIP for Connection Request
1 parent 8c4cb42 commit 6bf9fa0

11 files changed

Lines changed: 287 additions & 138 deletions

File tree

client/src/App.jsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,20 @@ const App = () => {
4545

4646
const [loading, setLoading] = useState(true);
4747
const [isAuthenticated, setIsAuthenticated] = useState(false);
48-
const impersonator= useAppStore(state => state.impersonator);
48+
const impersonator = useAppStore(state => state.impersonator);
4949
const navigate = useNavigate();
5050
const currentLocation = useLocation();
5151

5252
const refreshUser = () => {
53-
me().then(user => {
54-
const currentOrganization = useAppStore.getState().currentOrganization
55-
const newMenuItems = menuItemsForUser(user, currentOrganization);
56-
useAppStore.setState(() => ({
57-
user: user,
58-
menuItems: newMenuItems
59-
}))
60-
})
53+
me()
54+
.then(user => {
55+
const currentOrganization = useAppStore.getState().currentOrganization
56+
const newMenuItems = menuItemsForUser(user, currentOrganization);
57+
useAppStore.setState(() => ({
58+
user: user,
59+
menuItems: newMenuItems
60+
}))
61+
})
6162
}
6263

6364
useEffect(() => {
@@ -136,13 +137,14 @@ const App = () => {
136137
<Route path="/system/:tab?" element={<System/>}/>
137138
<Route path="/profile" element={<Profile setIsAuthenticated={setIsAuthenticated}/>}/>
138139
<Route path="/external/:app?" element={<ExternalApplication/>}/>
139-
<Route path="/application-detail/:manageType/:manageId" element={<ApplicationDetail anonymous={false}/>}/>
140+
<Route path="/application-detail/:manageType/:manageId"
141+
element={<ApplicationDetail anonymous={false} refreshUser={refreshUser}/>}/>
140142
<Route path="/refresh-route/:path" element={<RefreshRoute/>}/>
141143
<Route path="/feedback" element={<Feedback/>}/>
142144
<Route path="/idp/:organizationId" element={<MyOrganization refreshUser={refreshUser}/>}/>
143145
<Route path="/authentication-switch" element={<AuthenticationSwitch/>}/>
144-
<Route path="/accessible-apps" element={<ApplicationOverview accessible={true} />}/>
145-
<Route path="/catalogue" element={<ApplicationOverview accessible={false} />}/>
146+
<Route path="/accessible-apps" element={<ApplicationOverview accessible={true}/>}/>
147+
<Route path="/catalogue" element={<ApplicationOverview accessible={false}/>}/>
146148
<Route path="*" element={<NotFound/>}/>
147149
</Routes>
148150
</div>
@@ -160,7 +162,8 @@ const App = () => {
160162
<Route path="/connect" element={<Connect/>}/>
161163
<Route path="/applications" element={<Applications/>}/>
162164
<Route path="/login-info" element={<LoginInfo/>}/>
163-
<Route path="/application-detail/:manageType/:manageId" element={<ApplicationDetail anonymous={true}/>}/>
165+
<Route path="/application-detail/:manageType/:manageId"
166+
element={<ApplicationDetail anonymous={true}/>}/>
164167
<Route path="/authentication-switch" element={<AuthenticationSwitch/>}/>
165168
<Route path="/*" element={<LoginRedirect/>}/>
166169
</Routes>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "react";
2+
3+
import "./InfoBlock.scss"
4+
5+
export const InfoBlock = ({children, className = ""}) => {
6+
7+
return (
8+
<div className={`info-block ${className}`}>
9+
{children}
10+
</div>
11+
);
12+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
@use "../styles/vars" as *;
2+
@use "../index";
3+
4+
.info-block {
5+
border-radius: 10px;
6+
border: 1px solid var(--sl-color-green-200);
7+
padding: 24px;
8+
display: flex;
9+
flex-direction: column;
10+
align-items: flex-start;
11+
gap: 10px;
12+
background-color: var(--sl-color-green-100);
13+
14+
h3 {
15+
margin-bottom: 15px;
16+
}
17+
18+
h5 {
19+
margin-top: 8px;
20+
}
21+
22+
p.strong {
23+
font-weight: 600;
24+
}
25+
26+
.sds--divider {
27+
margin: auto 0 10px 0;
28+
29+
&.largest {
30+
margin-top: 20px;
31+
}
32+
}
33+
34+
.sds--btn.sds--btn--ghost--light {
35+
background-color: black;
36+
color: white;
37+
38+
&:hover {
39+
background-color: white;
40+
color: black;
41+
}
42+
}
43+
44+
&.grey {
45+
background-color: var(--sl-color-grey-100);
46+
border: 1px solid var(--sds--color--gray--300);
47+
}
48+
49+
&.full-row {
50+
grid-column: 1 / -1;
51+
background: white;
52+
border: 1px solid var(--sds--color--gray--200);
53+
}
54+
55+
}
56+

client/src/icons/no_access.svg

Lines changed: 4 additions & 0 deletions
Loading

client/src/locale/en.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ const en = {
184184
team: "My Team",
185185
joins: "Join Requests",
186186
invitations: "Invitations",
187+
access: "Access",
188+
information: "App information"
187189
},
188190
joinRequest: {
189191
info: "Je hebt geen toegang tot de omgeving van <strong>{{name}}</strong>. Je kunt toegang vragen aan de beheerder.",
@@ -977,6 +979,7 @@ const en = {
977979
name: "App",
978980
vendor: "Vendor",
979981
connectRequested: "Requested",
982+
connectionMade: "Connected",
980983
status: "Status",
981984
created: "Date connected",
982985
searchPlaceHolder: "Search...",
@@ -996,9 +999,6 @@ const en = {
996999
surfLink: "https://surf.nl",
9971000
select_locale: "Select your preferred language"
9981001
},
999-
appAccess: {
1000-
roleBasedAccess: "🥸 Toegang verloopt op basis van uitnodiging voor een rol"
1001-
},
10021002
profile: {
10031003
title: "Profile",
10041004
info: "Your account was created on {{createdAt}}",
@@ -1029,7 +1029,7 @@ const en = {
10291029
requestConnection: "Koppeling met deze applicatie moet worden aangevraagd",
10301030
requestConnectionInfo: "De leverancier van deze applicatie ontvangt en beoordeelt de aanvraag. ",
10311031
access: {
1032-
all:"Iedereen van de {{orgName}} heeft direct automatisch toegang",
1032+
all: "Iedereen van de {{orgName}} heeft direct automatisch toegang",
10331033
some: "Pas toegangsregels toe"
10341034
},
10351035
memberRequestInfo: [
@@ -1043,7 +1043,23 @@ const en = {
10431043
makeConnection: "Application access has been set",
10441044
requestConnection: "Application access is requested"
10451045
}
1046+
},
1047+
appAccess: {
1048+
title: "Central Access",
1049+
users: "User from {{name}}",
1050+
config: "⚡️Configureer automatische toegang op basis van kenmerken",
1051+
accessFor: "There is access for:",
1052+
everyBody: "Everybody from {{name}}",
1053+
noAccessFor: "Geen toegang voor:",
1054+
noOneGroups: "There are no groups excluded from access",
1055+
outSideUsers: "Users from outside",
1056+
roleBasedAccess: "🥸 Toegang verloopt op basis van uitnodiging voor een rol",
1057+
noOneRole: "There are users yet from outside with a role",
1058+
roleManagement: "To role management",
1059+
decentralAccess: "Decentral Access",
1060+
noDecentralAccess: "This application <span class='red'>is not used</span> by collaborative groups."
10461061
}
1062+
10471063
}
10481064

10491065
export default en;

client/src/pages/ApplicationDetail.jsx

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@ import React, {useEffect, useState} from "react";
33
import {connectServiceProviderToIdentityProvider, publicServiceProviderByDetail} from "../api/index.js";
44
import I18n from "../locale/I18n.js";
55
import {useNavigate, useParams} from "react-router-dom";
6-
import {Button, ButtonIconPlacement, ButtonType, Loader, RadioOptions, RadioOptionsOrientation} from "@surfnet/sds";
6+
import {
7+
Button,
8+
ButtonIconPlacement,
9+
ButtonType,
10+
Chip,
11+
ChipType,
12+
Loader,
13+
RadioOptions,
14+
RadioOptionsOrientation
15+
} from "@surfnet/sds";
716
import StudentPng from "../icons/student2.png";
817
import PlaceHolderImage from "@surfnet/sds/icons/placeholder-image.svg";
918
import ArrowLeftIcon from "@surfnet/sds/icons/functional-icons/arrow-left-2.svg";
@@ -21,6 +30,7 @@ import ConfirmationDialog from "../components/ConfirmationDialog.jsx";
2130
import {authorities} from "../utils/Permissions.js";
2231
import InputField from "../components/InputField.jsx";
2332
import {mainMenuItems} from "../utils/MenuItems.js";
33+
import {TabHeader} from "../components/TabHeader.jsx";
2434

2535
const confirmationModalOptions = {
2636
makeConnection: "makeConnection",
@@ -30,7 +40,9 @@ const confirmationModalOptions = {
3040
requestDisconnectConnection: "requestDisconnectConnection",
3141
}
3242

33-
const ApplicationDetail = ({anonymous}) => {
43+
const tabNames = ["access", "information"]
44+
45+
const ApplicationDetail = ({anonymous, refreshUser}) => {
3446

3547
const {arp, privacy, user, setFlash} = useAppStore(useShallow(state => ({
3648
arp: state.arp,
@@ -40,8 +52,10 @@ const ApplicationDetail = ({anonymous}) => {
4052
})));
4153

4254
const navigate = useNavigate();
43-
const {manageType, manageId} = useParams();
55+
const [refresh, setRefresh] = useState(-1);
56+
const {manageType, manageId, tab = "access"} = useParams();
4457

58+
const [currentTab, setCurrentTab] = useState(tab);
4559
const [loading, setLoading] = useState(true);
4660
const [serviceProvider, setServiceProvider] = useState([]);
4761
const [showAttributes, setShowAttributes] = useState(false);
@@ -83,7 +97,7 @@ const ApplicationDetail = ({anonymous}) => {
8397
breadcrumbPaths: [
8498
{path: "/home", value: I18n.t("breadCrumb.access"), menuItemName: mainMenuItems.home},
8599
{
86-
path: isAccessible ? "/accessibleApps" : "/catalogue",
100+
path: isAccessible ? "/accessible-apps" : "/catalogue",
87101
value: I18n.t(`navigation.${isAccessible ? "accessibleApps" : "catalogue"}`)
88102
},
89103
{value: providerName(I18n.locale, res)}
@@ -101,7 +115,7 @@ const ApplicationDetail = ({anonymous}) => {
101115
.catch(() => {
102116
navigate("/404");
103117
});
104-
}, [user]);// eslint-disable-line react-hooks/exhaustive-deps
118+
}, [user, refresh]);// eslint-disable-line react-hooks/exhaustive-deps
105119

106120
if (loading) {
107121
return <Loader/>
@@ -238,10 +252,52 @@ const ApplicationDetail = ({anonymous}) => {
238252

239253
const {open, cancel, action, question, title, okButton} = confirmation;
240254

255+
const renderCurrentTab = () => {
256+
switch (currentTab) {
257+
case "access": {
258+
return renderAccessApp();
259+
}
260+
case "information": {
261+
return <span>TODO</span>;
262+
}
263+
default:
264+
throw new Error(`Unknown tab; ${currentTab}`)
265+
}
266+
}
267+
268+
const tabChanged = name => {
269+
setCurrentTab(name);
270+
}
271+
272+
const renderAccessApp = () => {
273+
return <span>TODO renderAccessApp</span>;
274+
}
275+
241276
const renderAccessibleApp = () => {
242277
return (
243278
<>
244-
<p>readOnly {readOnly.toString()}</p>
279+
<div className="application-detail-header-container">
280+
<TabHeader tab={currentTab}
281+
setTab={tabChanged}
282+
tabNames={tabNames}
283+
>
284+
<div className="application-card-container">
285+
<div className="application-card">
286+
{metaData["logo:0:url"] && <img src={metaData["logo:0:url"]} alt=""/>}
287+
{!metaData["logo:0:url"] && <PlaceHolderImage/>}
288+
<div className="provider-details">
289+
<h3>{providerName(I18n.locale, serviceProvider)}</h3>
290+
<p>{providerDescription(I18n.locale, serviceProvider)}</p>
291+
</div>
292+
</div>
293+
<Chip type={readOnly ? ChipType.Status_error : ChipType.Status_info}
294+
label={I18n.t(`accessibleApps.${readOnly ? "connectRequested" : "connectionMade"}`)}/>
295+
</div>
296+
</TabHeader>
297+
</div>
298+
<div className="application-detail-page">
299+
{renderCurrentTab()}
300+
</div>
245301
</>
246302
)
247303
}

client/src/pages/ApplicationDetail.scss

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ div.application-detail-container {
1616
background-color: var(--sds--color--gray--background);
1717
border-radius: 6px;
1818
}
19+
1920
h3 {
2021
margin-bottom: 20px;
2122
}
@@ -48,6 +49,36 @@ div.application-detail-container {
4849
}
4950
}
5051

52+
.application-card-container {
53+
display: flex;
54+
align-items: flex-start;
55+
gap: 25px;
56+
}
57+
58+
.application-card {
59+
display: flex;
60+
background: white;
61+
border: 1px solid #EAECF0;
62+
border-radius: 10px;
63+
gap: 15px;
64+
padding: 30px;
65+
width: 70%;
66+
@media (max-width: $medium) {
67+
width: 100%;
68+
}
69+
70+
img, svg {
71+
width: 80px;
72+
height: 80px;
73+
}
74+
}
75+
76+
.application-detail-page {
77+
background-color: white;
78+
height: 100%;
79+
padding: 25px 50px;
80+
}
81+
5182
.inner-application-detail-container {
5283
width: 100%;
5384
background-color: white;

client/src/pages/ApplicationOverview.jsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,13 @@ const ApplicationOverview = ({accessible}) => {
171171
{
172172
key: "name",
173173
header: I18n.t("accessibleApps.name"),
174-
mapper: entity => <div className="app-name">
175-
{entity.name}{entity.connectionRequest && <Chip type={ChipType.Status_error}
176-
label={I18n.t("accessibleApps.connectRequested")}/>}</div>
174+
mapper: entity => entity.name
175+
},
176+
{
177+
key: "connectionRequest",
178+
header: "",
179+
mapper: entity => entity.connectionRequest && <Chip type={ChipType.Status_error}
180+
label={I18n.t("accessibleApps.connectRequested")}/>
177181
},
178182
{
179183
key: "vendor",
@@ -184,6 +188,12 @@ const ApplicationOverview = ({accessible}) => {
184188
key: "created",
185189
header: I18n.t("accessibleApps.created"),
186190
mapper: entity => formatLongDate(entity.created, true, false)
191+
},
192+
{
193+
key: "space",
194+
nonSortable: true,
195+
header: "",
196+
mapper: () => null
187197
}
188198
];
189199

0 commit comments

Comments
 (0)