Skip to content

Commit dcc4397

Browse files
odeimaizpcrespov
authored andcommitted
🎨 [Frontend] Feature: Hide username (ITISFoundation#7406)
Co-authored-by: Pedro Crespo-Valero <[email protected]>
1 parent 5d33fd1 commit dcc4397

File tree

5 files changed

+210
-40
lines changed

5 files changed

+210
-40
lines changed

‎services/static-webserver/client/source/class/osparc/data/model/User.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ qx.Class.define("osparc.data.model.User", {
3030

3131
const userId = ("id" in userData) ? parseInt(userData["id"]) : parseInt(userData["userId"]);
3232
const groupId = ("gid" in userData) ? parseInt(userData["gid"]) : parseInt(userData["groupId"]);
33-
const username = userData["userName"];
33+
const username = userData["userName"] || "-";
3434
const email = ("login" in userData) ? userData["login"] : userData["email"];
3535
let firstName = "";
3636
if (userData["first_name"]) {
@@ -60,7 +60,7 @@ qx.Class.define("osparc.data.model.User", {
6060
lastName,
6161
email,
6262
thumbnail,
63-
label: username,
63+
label: userData["userName"] || description,
6464
description,
6565
});
6666
},

‎services/static-webserver/client/source/class/osparc/desktop/WorkbenchView.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
442442
appearance: "form-button-outlined",
443443
label: this.tr("App Mode"),
444444
toolTipText: this.tr("Start App Mode"),
445-
icon: "@FontAwesome5Solid/play/14",
445+
icon: osparc.dashboard.CardBase.MODE_APP,
446446
marginRight: 10,
447447
marginTop: 7,
448448
...osparc.navigation.NavigationBar.BUTTON_OPTIONS
@@ -837,7 +837,7 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
837837

838838
const startAppBtn = this.__startAppButton = new qx.ui.form.Button().set({
839839
label: this.tr("Start"),
840-
icon: "@FontAwesome5Solid/play/14",
840+
icon: osparc.dashboard.CardBase.MODE_APP,
841841
toolTipText: this.tr("Start App Mode"),
842842
height: buttonsHeight
843843
});

‎services/static-webserver/client/source/class/osparc/desktop/account/ProfilePage.js‎

Lines changed: 115 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
3131

3232
this._setLayout(new qx.ui.layout.VBox(15));
3333

34+
this.__userProfileData = {};
35+
this.__userPrivacyData = {};
36+
3437
this.__fetchProfile();
3538

3639
this._add(this.__createProfileUser());
@@ -45,8 +48,11 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
4548
members: {
4649
__userProfileData: null,
4750
__userProfileModel: null,
51+
__userProfileRenderer: null,
52+
__updateProfileBtn: null,
4853
__userPrivacyData: null,
4954
__userPrivacyModel: null,
55+
__updatePrivacyBtn: null,
5056
__userProfileForm: null,
5157

5258
__fetchProfile: function() {
@@ -69,16 +75,29 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
6975
"expirationDate": data["expirationDate"] || null,
7076
});
7177
}
78+
this.__updateProfileBtn.setEnabled(false);
7279
},
7380

7481
__setDataToPrivacy: function(privacyData) {
7582
if (privacyData) {
7683
this.__userPrivacyData = privacyData;
7784
this.__userPrivacyModel.set({
85+
"hideUsername": "hideUsername" in privacyData ? privacyData["hideUsername"] : false,
7886
"hideFullname": "hideFullname" in privacyData ? privacyData["hideFullname"] : true,
7987
"hideEmail": "hideEmail" in privacyData ? privacyData["hideEmail"] : true,
8088
});
89+
90+
const visibleIcon = "@FontAwesome5Solid/eye/12";
91+
const hiddenIcon = "@FontAwesome5Solid/eye-slash/12";
92+
const icons = {
93+
0: this.__userPrivacyModel.getHideUsername() ? hiddenIcon : visibleIcon,
94+
1: this.__userPrivacyModel.getHideFullname() ? hiddenIcon : visibleIcon,
95+
2: this.__userPrivacyModel.getHideFullname() ? hiddenIcon : visibleIcon,
96+
3: this.__userPrivacyModel.getHideEmail() ? hiddenIcon : visibleIcon,
97+
};
98+
this.__userProfileRenderer.setIcons(icons);
8199
}
100+
this.__updatePrivacyBtn.setEnabled(false);
82101
},
83102

84103
__createProfileUser: function() {
@@ -105,12 +124,13 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
105124
readOnly: true
106125
});
107126

108-
const form = this.__userProfileForm = new qx.ui.form.Form();
109-
form.add(username, "Username", null, "username");
110-
form.add(firstName, "First Name", null, "firstName");
111-
form.add(lastName, "Last Name", null, "lastName");
112-
form.add(email, "Email", null, "email");
113-
box.add(new qx.ui.form.renderer.Single(form));
127+
const profileForm = this.__userProfileForm = new qx.ui.form.Form();
128+
profileForm.add(username, "Username", null, "username");
129+
profileForm.add(firstName, "First Name", null, "firstName");
130+
profileForm.add(lastName, "Last Name", null, "lastName");
131+
profileForm.add(email, "Email", null, "email");
132+
const singleWithIcon = this.__userProfileRenderer = new osparc.ui.form.renderer.SingleWithIcon(profileForm);
133+
box.add(singleWithIcon);
114134

115135
const expirationLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)).set({
116136
paddingLeft: 16,
@@ -167,21 +187,23 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
167187
namesValidator.add(firstName, qx.util.Validate.regExp(/[^\.\d]+/), this.tr("Avoid dots or numbers in text"));
168188
namesValidator.add(lastName, qx.util.Validate.regExp(/^$|[^\.\d]+/), this.tr("Avoid dots or numbers in text")); // allow also empty last name
169189

170-
const updateBtn = new qx.ui.form.Button("Update Profile").set({
190+
const updateProfileBtn = this.__updateProfileBtn = new qx.ui.form.Button().set({
191+
label: this.tr("Update Profile"),
171192
appearance: "form-button",
172193
alignX: "right",
173-
allowGrowX: false
194+
allowGrowX: false,
195+
enabled: false,
174196
});
175-
box.add(updateBtn);
197+
box.add(updateProfileBtn);
176198

177-
updateBtn.addListener("execute", () => {
199+
updateProfileBtn.addListener("execute", () => {
178200
if (!osparc.data.Permissions.getInstance().canDo("user.user.update", true)) {
179201
this.__resetUserData();
180202
return;
181203
}
182204

183205
const patchData = {};
184-
if (this.__userProfileData["username"] !== model.getUsername()) {
206+
if (this.__userProfileData["userName"] !== model.getUsername()) {
185207
patchData["userName"] = model.getUsername();
186208
}
187209
if (this.__userProfileData["first_name"] !== model.getFirstName()) {
@@ -211,61 +233,88 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
211233
}
212234
});
213235

236+
const profileFields = [
237+
username,
238+
firstName,
239+
lastName,
240+
]
241+
const valueChanged = () => {
242+
const anyChanged =
243+
username.getValue() !== this.__userProfileData["userName"] ||
244+
firstName.getValue() !== this.__userProfileData["first_name"] ||
245+
lastName.getValue() !== this.__userProfileData["last_name"];
246+
updateProfileBtn.setEnabled(anyChanged);
247+
};
248+
valueChanged();
249+
profileFields.forEach(privacyField => privacyField.addListener("changeValue", () => valueChanged()));
250+
214251
return box;
215252
},
216253

217254
__createPrivacySection: function() {
255+
// binding to a model
256+
const defaultModel = {
257+
"hideUsername": false,
258+
"hideFullname": true,
259+
"hideEmail": true,
260+
};
261+
262+
const privacyModel = this.__userPrivacyModel = qx.data.marshal.Json.createModel(defaultModel, true);
263+
218264
const box = osparc.ui.window.TabbedView.createSectionBox(this.tr("Privacy"));
219265
box.set({
220266
alignX: "left",
221267
maxWidth: 500
222268
});
223269

224-
const label = osparc.ui.window.TabbedView.createHelpLabel(this.tr("For Privacy reasons, you might want to hide your First and Last Names and/or the Email to other users"));
270+
const label = osparc.ui.window.TabbedView.createHelpLabel(this.tr("For Privacy reasons, you might want to hide some personal data."));
225271
box.add(label);
226272

273+
const hideUsername = new qx.ui.form.CheckBox().set({
274+
value: defaultModel.hideUsername
275+
});
227276
const hideFullname = new qx.ui.form.CheckBox().set({
228-
value: true
277+
value: defaultModel.hideFullname
229278
});
230279
const hideEmail = new qx.ui.form.CheckBox().set({
231-
value: true
280+
value: defaultModel.hideEmail
232281
});
233282

234-
const form = new qx.ui.form.Form();
235-
form.add(hideFullname, "Hide Full Name", null, "hideFullname");
236-
form.add(hideEmail, "Hide Email", null, "hideEmail");
237-
box.add(new qx.ui.form.renderer.Single(form));
238-
239-
// binding to a model
240-
const raw = {
241-
"hideFullname": true,
242-
"hideEmail": true,
243-
};
283+
const privacyForm = new qx.ui.form.Form();
284+
privacyForm.add(hideUsername, "Hide Username", null, "hideUsername");
285+
privacyForm.add(hideFullname, "Hide Full Name", null, "hideFullname");
286+
privacyForm.add(hideEmail, "Hide Email", null, "hideEmail");
287+
box.add(new qx.ui.form.renderer.Single(privacyForm));
244288

245-
const model = this.__userPrivacyModel = qx.data.marshal.Json.createModel(raw);
246-
const controller = new qx.data.controller.Object(model);
247-
controller.addTarget(hideFullname, "value", "hideFullname", true);
248-
controller.addTarget(hideEmail, "value", "hideEmail", true);
289+
const privacyModelCtrl = new qx.data.controller.Object(privacyModel);
290+
privacyModelCtrl.addTarget(hideUsername, "value", "hideUsername", true);
291+
privacyModelCtrl.addTarget(hideFullname, "value", "hideFullname", true);
292+
privacyModelCtrl.addTarget(hideEmail, "value", "hideEmail", true);
249293

250-
const privacyBtn = new qx.ui.form.Button("Update Privacy").set({
294+
const updatePrivacyBtn = this.__updatePrivacyBtn = new qx.ui.form.Button().set({
295+
label: this.tr("Update Privacy"),
251296
appearance: "form-button",
252297
alignX: "right",
253-
allowGrowX: false
298+
allowGrowX: false,
299+
enabled: false,
254300
});
255-
box.add(privacyBtn);
256-
privacyBtn.addListener("execute", () => {
301+
box.add(updatePrivacyBtn);
302+
updatePrivacyBtn.addListener("execute", () => {
257303
if (!osparc.data.Permissions.getInstance().canDo("user.user.update", true)) {
258304
this.__resetPrivacyData();
259305
return;
260306
}
261307
const patchData = {
262308
"privacy": {}
263309
};
264-
if (this.__userPrivacyData["hideFullname"] !== model.getHideFullname()) {
265-
patchData["privacy"]["hideFullname"] = model.getHideFullname();
310+
if (this.__userPrivacyData["hideUsername"] !== privacyModel.getHideUsername()) {
311+
patchData["privacy"]["hideUsername"] = privacyModel.getHideUsername();
312+
}
313+
if (this.__userPrivacyData["hideFullname"] !== privacyModel.getHideFullname()) {
314+
patchData["privacy"]["hideFullname"] = privacyModel.getHideFullname();
266315
}
267-
if (this.__userPrivacyData["hideEmail"] !== model.getHideEmail()) {
268-
patchData["privacy"]["hideEmail"] = model.getHideEmail();
316+
if (this.__userPrivacyData["hideEmail"] !== privacyModel.getHideEmail()) {
317+
patchData["privacy"]["hideEmail"] = privacyModel.getHideEmail();
269318
}
270319

271320
if (
@@ -298,6 +347,36 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
298347
}
299348
});
300349

350+
const optOutMessage = new qx.ui.basic.Atom().set({
351+
label: this.tr("If all searchable fields are hidden, you will not be findable."),
352+
icon: "@FontAwesome5Solid/exclamation-triangle/14",
353+
gap: 8,
354+
allowGrowX: false,
355+
});
356+
optOutMessage.getChildControl("icon").setTextColor("warning-yellow")
357+
box.add(optOutMessage);
358+
359+
const privacyFields = [
360+
hideUsername,
361+
hideFullname,
362+
hideEmail,
363+
]
364+
const valueChanged = () => {
365+
const anyChanged =
366+
hideUsername.getValue() !== this.__userPrivacyData["hideUsername"] ||
367+
hideFullname.getValue() !== this.__userPrivacyData["hideFullname"] ||
368+
hideEmail.getValue() !== this.__userPrivacyData["hideEmail"];
369+
updatePrivacyBtn.setEnabled(anyChanged);
370+
371+
if (privacyFields.every(privacyField => privacyField.getValue())) {
372+
optOutMessage.show();
373+
} else {
374+
optOutMessage.exclude();
375+
}
376+
};
377+
valueChanged();
378+
privacyFields.forEach(privacyField => privacyField.addListener("changeValue", () => valueChanged()));
379+
301380
return box;
302381
},
303382

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
qx.Class.define("osparc.ui.form.renderer.SingleWithIcon", {
19+
extend: qx.ui.form.renderer.Single,
20+
21+
construct: function(form, icons) {
22+
if (icons) {
23+
this.__icons = icons;
24+
} else {
25+
this.__icons = {};
26+
}
27+
28+
this.base(arguments, form);
29+
},
30+
31+
members: {
32+
__icons: null,
33+
34+
setIcons: function(icons) {
35+
this.__icons = icons;
36+
37+
this._onFormChange();
38+
},
39+
40+
// overridden
41+
addItems: function(items, names, title, itemOptions, headerOptions) {
42+
this.base(arguments, items, names, title, itemOptions, headerOptions);
43+
44+
// header
45+
let row = title === null ? 0 : 1;
46+
47+
for (let i = 0; i < items.length; i++) {
48+
if (i in this.__icons) {
49+
const image = new qx.ui.basic.Image(this.__icons[i]).set({
50+
alignY: "middle",
51+
});
52+
this._add(image, {
53+
row,
54+
column: 2,
55+
});
56+
}
57+
58+
row++;
59+
}
60+
},
61+
}
62+
});

0 commit comments

Comments
 (0)