Skip to content

Commit 6d446c9

Browse files
✨ [Frontend] PO Center: Pending Users (#7699)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent b46a1dd commit 6d446c9

File tree

9 files changed

+308
-20
lines changed

9 files changed

+308
-20
lines changed

services/static-webserver/client/source/class/osparc/data/Job.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ qx.Class.define("osparc.data.Job", {
2828
startedAt: jobData["startedAt"] ? new Date(jobData["startedAt"]) : null,
2929
endedAt: jobData["endedAt"] ? new Date(jobData["endedAt"]) : null,
3030
info: jobData["info"] || null,
31-
customMetadata: jobData["customMetadata"] || null,
31+
customMetadata: jobData["projectCustomMetadata"] || null,
3232
});
3333

3434
if (jobData["info"] && jobData["info"]["project_name"]) {

services/static-webserver/client/source/class/osparc/data/Resources.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,22 @@ qx.Class.define("osparc.data.Resources", {
10611061
method: "GET",
10621062
url: statics.API + "/admin/users:search?email={email}"
10631063
},
1064+
getPendingUsers: {
1065+
method: "GET",
1066+
url: statics.API + "/admin/users?status=PENDING"
1067+
},
1068+
approveUser: {
1069+
method: "POST",
1070+
url: statics.API + "/admin/users:approve"
1071+
},
1072+
rejectUser: {
1073+
method: "POST",
1074+
url: statics.API + "/admin/users:reject"
1075+
},
1076+
resendConfirmationEmail: {
1077+
method: "POST",
1078+
url: statics.API + "/admin/users:resendConfirmationEmail"
1079+
},
10641080
preRegister: {
10651081
method: "POST",
10661082
url: statics.API + "/admin/users:pre-register"

services/static-webserver/client/source/class/osparc/info/ServiceLarge.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,6 @@ qx.Class.define("osparc.info.ServiceLarge", {
457457
return resourcesLayout;
458458
},
459459

460-
__createRawMetadata: function() {
461-
const container = new qx.ui.container.Scroll();
462-
container.add(new osparc.ui.basic.JsonTreeWidget(this.getService(), "serviceDescriptionSettings"));
463-
return container;
464-
},
465-
466460
__openIconEditor: function() {
467461
const iconEditor = new osparc.widget.Renamer(this.getService()["icon"], null, this.tr("Edit Icon"));
468462
iconEditor.addListener("labelChanged", e => {

services/static-webserver/client/source/class/osparc/jobs/SubRunsTable.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ qx.Class.define("osparc.jobs.SubRunsTable", {
175175
if (logDownloadLink) {
176176
osparc.utils.Utils.downloadLink(logDownloadLink, "GET", rowData["nodeName"] + ".logs");
177177
} else {
178-
osparc.component.message.FlashMessenger.getInstance().logAsWarning(this.tr("No logs available"));
178+
osparc.FlashMessenger.logAs(this.tr("No logs available"), "WARNING");
179179
}
180180
break;
181181
}

services/static-webserver/client/source/class/osparc/metadata/ServicesInStudy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ qx.Class.define("osparc.metadata.ServicesInStudy", {
132132
i++;
133133
const node = workbench[nodeId];
134134

135-
const infoButton = new qx.ui.form.Button(null, "@MaterialIcons/info_outline/14");
135+
const infoButton = new qx.ui.form.Button(null, "@MaterialIcons/info_outline/16");
136136
infoButton.addListener("execute", () => {
137137
const metadata = osparc.store.Services.getMetadata(node["key"], node["version"]);
138138
if (metadata === null) {

services/static-webserver/client/source/class/osparc/po/POCenter.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,31 @@ qx.Class.define("osparc.po.POCenter", {
2626
});
2727
this.addWidgetToTabs(miniProfile);
2828

29-
this.__addUsersPage();
29+
this.__addActiveUsersPage();
30+
if (osparc.utils.Utils.isDevelopmentPlatform()) {
31+
this.__addPendingUsersPage();
32+
}
3033
this.__addPreRegistrationPage();
3134
this.__addInvitationsPage();
3235
this.__addProductPage();
3336
this.__addMsgTemplatesPage();
3437
},
3538

3639
members: {
37-
__addUsersPage: function() {
38-
const title = this.tr("Users");
40+
__addActiveUsersPage: function() {
41+
const title = this.tr("Active Users");
3942
const iconSrc = "@FontAwesome5Solid/user/22";
4043
const users = new osparc.po.Users();
4144
this.addTab(title, iconSrc, users);
4245
},
4346

47+
__addPendingUsersPage: function() {
48+
const title = this.tr("Pending Users");
49+
const iconSrc = "@FontAwesome5Solid/user-plus/22";
50+
const usersPending = new osparc.po.UsersPending();
51+
this.addTab(title, iconSrc, usersPending);
52+
},
53+
4454
__addPreRegistrationPage: function() {
4555
const title = this.tr("Pre-Registration");
4656
const iconSrc = "@FontAwesome5Solid/address-card/22";

services/static-webserver/client/source/class/osparc/po/POCenterWindow.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ qx.Class.define("osparc.po.POCenterWindow", {
2121
construct: function() {
2222
this.base(arguments, "po-center", this.tr("PO Center"));
2323

24-
const width = 800;
24+
const width = 900;
2525
const height = 600;
2626
this.set({
2727
width,
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2024 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Pedro Crespo-Valero (pcrespov)
15+
* Odei Maiz (odeimaiz)
16+
17+
************************************************************************ */
18+
19+
qx.Class.define("osparc.po.UsersPending", {
20+
extend: osparc.po.BaseView,
21+
22+
statics: {
23+
getPendingUsers: function() {
24+
return new Promise(resolve => {
25+
resolve({
26+
data: [{
27+
name: "John Doe",
28+
29+
date: "2025-01-01 00:00:00.702394",
30+
status: "PENDING",
31+
info: {
32+
"institution": "ETH Zurich",
33+
"department": "Department of Physics",
34+
"position": "PhD Student",
35+
"country": "Switzerland",
36+
"city": "Zurich",
37+
},
38+
}, {
39+
name: "Jane Doe",
40+
41+
date: "2025-01-01 00:01:00.702394",
42+
status: "REJECTED",
43+
info: {
44+
"institution": "ETH Zurich",
45+
"department": "Department of Physics",
46+
"position": "PhD Student",
47+
"country": "Switzerland",
48+
"city": "Zurich",
49+
},
50+
}, {
51+
name: "Alice Smith",
52+
53+
date: "2025-01-01 00:02:00.702394",
54+
status: "APPROVED",
55+
info: {
56+
"institution": "ETH Zurich",
57+
"department": "Department of Physics",
58+
"position": "PhD Student",
59+
"country": "Switzerland",
60+
"city": "Zurich",
61+
},
62+
}]
63+
});
64+
});
65+
},
66+
67+
createApproveButton: function(email) {
68+
const button = new osparc.ui.form.FetchButton(qx.locale.Manager.tr("Approve"));
69+
button.addListener("execute", () => {
70+
button.setFetching(true);
71+
const params = {
72+
data: {
73+
email,
74+
},
75+
};
76+
osparc.data.Resources.fetch("poUsers", "approveUser", params)
77+
.then(() => {
78+
osparc.FlashMessenger.logAs(qx.locale.Manager.tr("User approved"), "INFO");
79+
})
80+
.catch(err => osparc.FlashMessenger.logError(err))
81+
.finally(() => button.setFetching(false));
82+
});
83+
return button;
84+
},
85+
86+
createRejectButton: function(email) {
87+
const button = new osparc.ui.form.FetchButton(qx.locale.Manager.tr("Reject"));
88+
button.addListener("execute", () => {
89+
button.setFetching(true);
90+
const params = {
91+
data: {
92+
email,
93+
},
94+
};
95+
osparc.data.Resources.fetch("poUsers", "rejectUser", params)
96+
.then(() => {
97+
osparc.FlashMessenger.logAs(qx.locale.Manager.tr("User denied"), "INFO");
98+
})
99+
.catch(err => osparc.FlashMessenger.logError(err))
100+
.finally(() => button.setFetching(false));
101+
});
102+
return button;
103+
},
104+
105+
createResendEmailButton: function(email) {
106+
const button = new osparc.ui.form.FetchButton(qx.locale.Manager.tr("Resend Email"));
107+
button.addListener("execute", () => {
108+
button.setFetching(true);
109+
const params = {
110+
data: {
111+
email,
112+
},
113+
};
114+
osparc.data.Resources.fetch("poUsers", "resendConfirmationEmail", params)
115+
.then(() => {
116+
osparc.FlashMessenger.logAs(qx.locale.Manager.tr("Email sent"), "INFO");
117+
})
118+
.catch(err => osparc.FlashMessenger.logError(err))
119+
.finally(() => button.setFetching(false));
120+
});
121+
return button;
122+
},
123+
124+
createInfoButton: function(infoMetadata) {
125+
const infoButton = new qx.ui.form.Button(null, "@MaterialIcons/info_outline/16");
126+
infoButton.addListener("execute", () => {
127+
const container = new qx.ui.container.Scroll();
128+
container.add(new osparc.ui.basic.JsonTreeWidget(infoMetadata, "pendingUserInfo"));
129+
osparc.ui.window.Window.popUpInWindow(container, qx.locale.Manager.tr("User Info"));
130+
});
131+
return infoButton;
132+
},
133+
},
134+
135+
members: {
136+
_createChildControlImpl: function(id) {
137+
let control;
138+
switch (id) {
139+
case "pending-users-container":
140+
control = new qx.ui.container.Scroll();
141+
this._add(control, {
142+
flex: 1
143+
});
144+
break;
145+
case "pending-users-layout": {
146+
const grid = new qx.ui.layout.Grid(15, 5);
147+
control = new qx.ui.container.Composite(grid);
148+
this.getChildControl("pending-users-container").add(control);
149+
break;
150+
}
151+
}
152+
return control || this.base(arguments, id);
153+
},
154+
155+
_buildLayout: function() {
156+
this.getChildControl("pending-users-container");
157+
158+
this.__populatePendingUsersLayout();
159+
},
160+
161+
__addHeader: function() {
162+
const pendingUsersLayout = this.getChildControl("pending-users-layout");
163+
164+
pendingUsersLayout.add(new qx.ui.basic.Label(this.tr("Name")).set({
165+
font: "text-14"
166+
}), {
167+
row: 0,
168+
column: 0,
169+
});
170+
171+
pendingUsersLayout.add(new qx.ui.basic.Label(this.tr("Email")).set({
172+
font: "text-14"
173+
}), {
174+
row: 0,
175+
column: 1,
176+
});
177+
178+
pendingUsersLayout.add(new qx.ui.basic.Label(this.tr("Date")).set({
179+
font: "text-14"
180+
}), {
181+
row: 0,
182+
column: 2,
183+
});
184+
185+
pendingUsersLayout.add(new qx.ui.basic.Label(this.tr("Info")).set({
186+
font: "text-14"
187+
}), {
188+
row: 0,
189+
column: 3,
190+
});
191+
192+
pendingUsersLayout.add(new qx.ui.basic.Label(this.tr("Status")).set({
193+
font: "text-14"
194+
}), {
195+
row: 0,
196+
column: 4,
197+
});
198+
199+
pendingUsersLayout.add(new qx.ui.basic.Label(this.tr("Action")).set({
200+
font: "text-14"
201+
}), {
202+
row: 0,
203+
column: 5,
204+
});
205+
},
206+
207+
__addRows: function(pendingUsers) {
208+
const pendingUsersLayout = this.getChildControl("pending-users-layout");
209+
210+
let row = 1;
211+
pendingUsers.forEach(pendingUser => {
212+
pendingUsersLayout.add(new qx.ui.basic.Label(pendingUser.name), {
213+
row,
214+
column: 0,
215+
});
216+
pendingUsersLayout.add(new qx.ui.basic.Label(pendingUser.email), {
217+
row,
218+
column: 1,
219+
});
220+
pendingUsersLayout.add(new qx.ui.basic.Label(osparc.utils.Utils.formatDateAndTime(new Date(pendingUser.date))), {
221+
row,
222+
column: 2,
223+
});
224+
const infoButton = this.self().createInfoButton(pendingUser.info);
225+
pendingUsersLayout.add(infoButton, {
226+
row,
227+
column: 3,
228+
});
229+
pendingUsersLayout.add(new qx.ui.basic.Label(pendingUser.status.toLowerCase()), {
230+
row,
231+
column: 4,
232+
});
233+
const buttonsLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(5));
234+
pendingUsersLayout.add(buttonsLayout, {
235+
row,
236+
column: 5,
237+
});
238+
239+
switch (pendingUser.status) {
240+
case "PENDING": {
241+
const approveButton = this.self().createApproveButton(pendingUser.email);
242+
buttonsLayout.add(approveButton);
243+
const rejectButton = this.self().createRejectButton(pendingUser.email);
244+
buttonsLayout.add(rejectButton);
245+
break;
246+
}
247+
case "REJECTED": {
248+
const approveButton = this.self().createApproveButton(pendingUser.email);
249+
buttonsLayout.add(approveButton);
250+
break;
251+
}
252+
case "APPROVED": {
253+
const resendEmailButton = this.self().createResendEmailButton(pendingUser.email);
254+
buttonsLayout.add(resendEmailButton);
255+
break;
256+
}
257+
}
258+
row++;
259+
});
260+
},
261+
262+
__populatePendingUsersLayout: function() {
263+
// osparc.data.Resources.fetch("poUsers", "getPendingUsers", params)
264+
this.self().getPendingUsers()
265+
.then(pendingUsers => {
266+
const pendingUsersLayout = this.getChildControl("pending-users-layout");
267+
pendingUsersLayout.removeAll();
268+
this.__addHeader();
269+
this.__addRows(pendingUsers["data"]);
270+
})
271+
.catch(err => osparc.FlashMessenger.logError(err));
272+
}
273+
}
274+
});

services/static-webserver/client/source/class/osparc/product/Utils.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,7 @@ qx.Class.define("osparc.product.Utils", {
6060

6161
getTemplateAlias: function(options = {}) {
6262
let alias = null;
63-
if (this.getProductName().includes("s4l")) {
64-
if (options.plural) {
65-
alias = qx.locale.Manager.tr("tutorials");
66-
} else {
67-
alias = qx.locale.Manager.tr("tutorial");
68-
}
69-
} else if (options.plural) {
63+
if (options.plural) {
7064
alias = qx.locale.Manager.tr("templates");
7165
} else {
7266
alias = qx.locale.Manager.tr("template");

0 commit comments

Comments
 (0)