Skip to content

Commit 2755211

Browse files
authored
✨ [Frontend] Functions Browser: Permissions and Search (#8252)
1 parent 13b6062 commit 2755211

24 files changed

+578
-153
lines changed

services/static-webserver/client/source/class/osparc/dashboard/GridButtonItem.js

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,8 @@ qx.Class.define("osparc.dashboard.GridButtonItem", {
250250
_applyOwner: function(value, old) {
251251
const label = this.getChildControl("subtitle-text");
252252
if (osparc.utils.Resources.isFunction(this.getResourceData())) {
253-
const canIWrite = Boolean(this.getResourceData()["accessRights"]["write"]);
253+
// Functions don't have 'owner'
254+
const canIWrite = osparc.data.model.Function.canIWrite(this.getResourceData()["accessRights"]);
254255
label.setValue(canIWrite ? "My Function" : "Read Only");
255256
} else {
256257
const user = this.__createOwner(value);
@@ -262,20 +263,15 @@ qx.Class.define("osparc.dashboard.GridButtonItem", {
262263
_applyAccessRights: function(value) {
263264
if (value && Object.keys(value).length) {
264265
const shareIcon = this.getChildControl("subtitle-icon");
265-
if (this.isResourceType("function")) {
266-
// in case of functions, the access rights are actually myAccessRights
267-
osparc.dashboard.CardBase.populateMyAccessRightsIcon(shareIcon, value);
268-
} else {
269-
shareIcon.addListener("tap", e => {
270-
e.stopPropagation();
271-
this.openAccessRights();
272-
}, this);
273-
shareIcon.addListener("pointerdown", e => e.stopPropagation());
274-
osparc.dashboard.CardBase.populateShareIcon(shareIcon, value);
266+
shareIcon.addListener("tap", e => {
267+
e.stopPropagation();
268+
this.openAccessRights();
269+
}, this);
270+
shareIcon.addListener("pointerdown", e => e.stopPropagation());
271+
osparc.dashboard.CardBase.populateShareIcon(shareIcon, value);
275272

276-
if (this.isResourceType("study")) {
277-
this._setStudyPermissions(value);
278-
}
273+
if (this.isResourceType("study")) {
274+
this._setStudyPermissions(value);
279275
}
280276
}
281277
},

services/static-webserver/client/source/class/osparc/dashboard/ListButtonItem.js

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ qx.Class.define("osparc.dashboard.ListButtonItem", {
244244
_applyOwner: function(value, old) {
245245
const label = this.getChildControl("owner");
246246
if (osparc.utils.Resources.isFunction(this.getResourceData())) {
247-
const canIWrite = Boolean(this.getResourceData()["accessRights"]["write"]);
247+
// Functions don't have 'owner'
248+
const canIWrite = osparc.data.model.Function.canIWrite(this.getResourceData()["accessRights"]);
248249
label.setValue(canIWrite ? "My Function" : "Read Only");
249250
} else {
250251
const user = this.__createOwner(value);
@@ -257,20 +258,15 @@ qx.Class.define("osparc.dashboard.ListButtonItem", {
257258
_applyAccessRights: function(value) {
258259
if (value && Object.keys(value).length) {
259260
const shareIcon = this.getChildControl("shared-icon");
260-
if (this.isResourceType("function")) {
261-
// in case of functions, the access rights are actually myAccessRights
262-
osparc.dashboard.CardBase.populateMyAccessRightsIcon(shareIcon, value);
263-
} else {
264-
shareIcon.addListener("tap", e => {
265-
e.stopPropagation();
266-
this.openAccessRights();
267-
}, this);
268-
shareIcon.addListener("pointerdown", e => e.stopPropagation());
269-
osparc.dashboard.CardBase.populateShareIcon(shareIcon, value);
261+
shareIcon.addListener("tap", e => {
262+
e.stopPropagation();
263+
this.openAccessRights();
264+
}, this);
265+
shareIcon.addListener("pointerdown", e => e.stopPropagation());
266+
osparc.dashboard.CardBase.populateShareIcon(shareIcon, value);
270267

271-
if (this.isResourceType("study")) {
272-
this._setStudyPermissions(value);
273-
}
268+
if (this.isResourceType("study")) {
269+
this._setStudyPermissions(value);
274270
}
275271
}
276272
},

services/static-webserver/client/source/class/osparc/dashboard/ResourceContainerManager.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
163163
text = this.tr("No Public Projects found");
164164
break;
165165
case osparc.dashboard.StudyBrowser.CONTEXT.FUNCTIONS:
166+
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS:
166167
text = this.tr("No Functions found");
167168
break;
168169
}

services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
409409
return;
410410
} else if (osparc.utils.Resources.isFunction(this.__resourceData)) {
411411
this.__addInfoPage();
412+
this.__addPermissionsPage();
412413
if (this.__resourceModel.getFunctionClass() === osparc.data.model.Function.FUNCTION_CLASS.PROJECT) {
413414
this.__addPreviewPage();
414415
}
@@ -641,6 +642,12 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
641642
const updatedData = e.getData();
642643
this.__fireUpdateEvent(resourceData, updatedData);
643644
}, this);
645+
} else if (osparc.utils.Resources.isFunction(resourceData)) {
646+
collaboratorsView = new osparc.share.CollaboratorsFunction(resourceData);
647+
collaboratorsView.addListener("updateAccessRights", e => {
648+
const updatedData = e.getData();
649+
this.__fireUpdateEvent(resourceData, updatedData);
650+
}, this);
644651
} else {
645652
collaboratorsView = new osparc.share.CollaboratorsStudy(resourceData);
646653
if (osparc.utils.Resources.isStudy(resourceData)) {

services/static-webserver/client/source/class/osparc/dashboard/SearchBarFilterExtended.js

Lines changed: 113 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
5353
"searchProjects", // osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PROJECTS,
5454
"searchTemplates", // osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_TEMPLATES,
5555
"searchPublicTemplates", // osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PUBLIC_TEMPLATES,
56+
"searchFunctions" // osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS
5657
],
5758
init: null,
5859
nullable: false,
@@ -62,24 +63,17 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
6263
},
6364

6465
statics: {
65-
createToolbarRadioButton: function(label, icon, toolTipText = null, pos = null) {
66-
const rButton = new qx.ui.toolbar.RadioButton().set({
67-
label,
68-
icon,
69-
toolTipText,
70-
padding: 8,
66+
decorateListItem: function(listItem) {
67+
listItem.set({
7168
gap: 8,
72-
margin: 0,
69+
backgroundColor: osparc.dashboard.SearchBarFilter.BG_COLOR,
7370
});
74-
rButton.getContentElement().setStyles({
75-
"border-radius": "0px"
76-
});
77-
if (pos === "left") {
78-
osparc.utils.Utils.addBorderLeftRadius(rButton);
79-
} else if (pos === "right") {
80-
osparc.utils.Utils.addBorderRightRadius(rButton);
81-
}
82-
return rButton;
71+
},
72+
73+
createListItem: function(label, icon, model) {
74+
const listItem = new qx.ui.form.ListItem(label, icon, model);
75+
this.self().decorateListItem(listItem);
76+
return listItem;
8377
},
8478
},
8579

@@ -90,48 +84,74 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
9084
let control;
9185
switch (id) {
9286
case "search-bar-filter": {
93-
control = new osparc.dashboard.SearchBarFilter(this.__resourceType);
87+
control = new osparc.dashboard.SearchBarFilter(this.__resourceType).set({
88+
showFilterMenu: false,
89+
});
9490
const textField = control.getChildControl("text-field");
9591
textField.addListener("appear", () => {
9692
textField.focus();
9793
textField.activate();
9894
});
95+
const resetButton = control.getChildControl("reset-button");
96+
resetButton.set({
97+
paddingRight: 2, // 10-8
98+
opacity: 0.7,
99+
backgroundColor: "transparent",
100+
});
101+
osparc.utils.Utils.hideBorder(resetButton);
99102
this._add(control);
100103
break;
101104
}
102-
case "context-buttons":
103-
control = new qx.ui.toolbar.ToolBar().set({
104-
spacing: 0,
105-
padding: 0,
106-
backgroundColor: osparc.dashboard.SearchBarFilter.BG_COLOR,
105+
case "context-drop-down": {
106+
control = new qx.ui.form.SelectBox().set({
107+
minWidth: 150,
107108
});
108-
this._add(control);
109+
control.getChildControl("arrow").syncAppearance(); // force sync to show the arrow
110+
this.self().decorateListItem(control.getChildControl("atom"));
111+
const searchBarFilter = this.getChildControl("search-bar-filter");
112+
searchBarFilter._addAt(control, 3); //"search-icon", "active-filters", "text-field", "reset-button"
109113
break;
110-
case "my-projects-button":
111-
control = this.self().createToolbarRadioButton(
114+
}
115+
case "my-projects-button": {
116+
control = this.self().createListItem(
112117
this.tr("My Projects"),
113118
"@FontAwesome5Solid/file/14",
114-
null,
115-
"left",
119+
"myProjects"
116120
);
117-
this.getChildControl("context-buttons").add(control);
121+
const contextDropDown = this.getChildControl("context-drop-down");
122+
contextDropDown.add(control);
118123
break;
119-
case "templates-button":
120-
control = this.self().createToolbarRadioButton(
124+
}
125+
case "templates-button": {
126+
control = this.self().createListItem(
121127
this.tr("Templates"),
122128
"@FontAwesome5Solid/copy/14",
129+
"templates"
123130
);
124-
this.getChildControl("context-buttons").add(control);
131+
const contextDropDown = this.getChildControl("context-drop-down");
132+
contextDropDown.add(control);
125133
break;
126-
case "public-projects-button":
127-
control = this.self().createToolbarRadioButton(
134+
}
135+
case "public-projects-button": {
136+
control = this.self().createListItem(
128137
this.tr("Public Projects"),
129138
"@FontAwesome5Solid/globe/14",
130-
null,
131-
"right",
139+
"publicProjects"
132140
);
133-
this.getChildControl("context-buttons").add(control);
141+
const contextDropDown = this.getChildControl("context-drop-down");
142+
contextDropDown.add(control);
134143
break;
144+
}
145+
case "functions-button": {
146+
control = this.self().createListItem(
147+
this.tr("Functions"),
148+
"@MaterialIcons/functions/18",
149+
"functions"
150+
);
151+
const contextDropDown = this.getChildControl("context-drop-down");
152+
contextDropDown.add(control);
153+
break;
154+
}
135155
case "filter-buttons":
136156
control = new qx.ui.toolbar.ToolBar().set({
137157
backgroundColor: osparc.dashboard.SearchBarFilter.BG_COLOR,
@@ -153,30 +173,37 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
153173
},
154174

155175
__buildLayout: function() {
156-
this.getChildControl("search-bar-filter").set({
157-
showFilterMenu: false,
158-
});
159-
160-
const resetButton = this.getChildControl("search-bar-filter").getChildControl("reset-button");
161-
resetButton.set({
162-
paddingRight: 2, // 10-8
163-
opacity: 0.7,
164-
backgroundColor: "transparent",
176+
const searchBarFilter = this.getChildControl("search-bar-filter");
177+
178+
const contextDropDown = this.getChildControl("context-drop-down");
179+
this.getChildControl("my-projects-button");
180+
this.getChildControl("templates-button");
181+
this.getChildControl("public-projects-button");
182+
this.getChildControl("functions-button");
183+
contextDropDown.addListener("changeSelection", e => {
184+
const selection = e.getData();
185+
if (selection.length) {
186+
const selectedContext = selection[0].getModel();
187+
switch (selectedContext) {
188+
case "myProjects":
189+
this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PROJECTS);
190+
break;
191+
case "templates":
192+
this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_TEMPLATES);
193+
break;
194+
case "publicProjects":
195+
this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PUBLIC_TEMPLATES);
196+
break;
197+
case "functions":
198+
this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS);
199+
break;
200+
}
201+
}
165202
});
166-
osparc.utils.Utils.hideBorder(resetButton);
167-
168-
const radioGroup = new qx.ui.form.RadioGroup();
169-
const myProjectsButton = this.getChildControl("my-projects-button");
170-
const templatesButton = this.getChildControl("templates-button");
171-
const publicProjectsButton = this.getChildControl("public-projects-button");
172-
radioGroup.add(myProjectsButton, templatesButton, publicProjectsButton);
173-
myProjectsButton.addListener("changeValue", e => e.getData() ? this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PROJECTS) : null, this);
174-
templatesButton.addListener("changeValue", e => e.getData() ? this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_TEMPLATES) : null, this);
175-
publicProjectsButton.addListener("changeValue", e => e.getData() ? this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PUBLIC_TEMPLATES) : null, this);
176203

177204
// Set initial state based on the provided initFilterData
178-
const activeFilters = this.getChildControl("search-bar-filter").getChildControl("active-filters");
179-
const textField = this.getChildControl("search-bar-filter").getChildControl("text-field");
205+
const activeFilters = searchBarFilter.getChildControl("active-filters");
206+
const textField = searchBarFilter.getChildControl("text-field");
180207
if ("sharedWith" in this.__initFilterData && this.__initFilterData["sharedWith"]) {
181208
const sharedWithOptions = osparc.dashboard.SearchBarFilter.getSharedWithOptions(this.__resourceType);
182209
const optionsFound = sharedWithOptions.find(option => option.id === this.__initFilterData["sharedWith"]);
@@ -209,6 +236,7 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
209236
this.__filter("text", textField.getValue());
210237
}, this);
211238

239+
const resetButton = searchBarFilter.getChildControl("reset-button");
212240
resetButton.addListener("tap", () => {
213241
this.fireEvent("resetButtonPressed");
214242
this.exclude();
@@ -219,24 +247,34 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
219247
if (value === old) {
220248
return;
221249
}
250+
const contextDropDown = this.getChildControl("context-drop-down");
251+
const searchBarFilter = this.getChildControl("search-bar-filter");
252+
const sharedWithButton = this.getChildControl("shared-with-button");
253+
const tagsButton = this.getChildControl("tags-button");
222254
switch (value) {
223255
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PROJECTS:
224-
this.getChildControl("my-projects-button").setValue(true);
225-
this.getChildControl("search-bar-filter").getChildControl("text-field").setPlaceholder(this.tr("Search in My projects"));
226-
this.getChildControl("shared-with-button").setVisibility("visible");
227-
this.getChildControl("tags-button").setVisibility("visible");
256+
contextDropDown.setSelection([this.getChildControl("my-projects-button")]);
257+
searchBarFilter.getChildControl("text-field").setPlaceholder(this.tr("Search in My projects"));
258+
sharedWithButton.setVisibility("visible");
259+
tagsButton.setVisibility("visible");
228260
break;
229261
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_TEMPLATES:
230-
this.getChildControl("templates-button").setValue(true);
231-
this.getChildControl("search-bar-filter").getChildControl("text-field").setPlaceholder(this.tr("Search in Templates"));
232-
this.getChildControl("shared-with-button").setVisibility("excluded");
233-
this.getChildControl("tags-button").setVisibility("visible");
262+
contextDropDown.setSelection([this.getChildControl("templates-button")]);
263+
searchBarFilter.getChildControl("text-field").setPlaceholder(this.tr("Search in Templates"));
264+
sharedWithButton.setVisibility("excluded");
265+
tagsButton.setVisibility("visible");
234266
break;
235267
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PUBLIC_TEMPLATES:
236-
this.getChildControl("public-projects-button").setValue(true);
237-
this.getChildControl("search-bar-filter").getChildControl("text-field").setPlaceholder(this.tr("Search in Public projects"));
238-
this.getChildControl("shared-with-button").setVisibility("excluded");
239-
this.getChildControl("tags-button").setVisibility("visible");
268+
contextDropDown.setSelection([this.getChildControl("public-projects-button")]);
269+
searchBarFilter.getChildControl("text-field").setPlaceholder(this.tr("Search in Public Projects"));
270+
sharedWithButton.setVisibility("excluded");
271+
tagsButton.setVisibility("visible");
272+
break;
273+
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS:
274+
contextDropDown.setSelection([this.getChildControl("functions-button")]);
275+
searchBarFilter.getChildControl("text-field").setPlaceholder(this.tr("Search in Functions"));
276+
sharedWithButton.setVisibility("excluded");
277+
tagsButton.setVisibility("excluded");
240278
break;
241279
}
242280
},
@@ -291,6 +329,12 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
291329
this.__sharedWithMenu,
292330
this.__tagsMenu,
293331
];
332+
// handle clicks on the drop down menu that might go out of bounds
333+
const contextDropDown = this.getChildControl("context-drop-down");
334+
const popup = contextDropDown.getChildControl("popup");
335+
if (popup.isVisible()) {
336+
excludeElements.push(popup);
337+
}
294338
for (let i = 0; i < excludeElements.length; i++) {
295339
if (excludeElements[i] && osparc.utils.Utils.isMouseOnElement(excludeElements[i], e)) {
296340
return;

0 commit comments

Comments
 (0)