Skip to content
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
948de8b
CollaboratorsFunction
odeimaiz Aug 22, 2025
f04483f
Merge branch 'master' into feature/share-functions
odeimaiz Aug 22, 2025
ef25275
Merge branch 'feature/share-functions' of github.com:odeimaiz/osparc-…
odeimaiz Aug 22, 2025
41feca4
right icon
odeimaiz Aug 22, 2025
3aa1370
minor
odeimaiz Aug 22, 2025
6acf8f2
_applyOwner
odeimaiz Aug 22, 2025
cdc1e53
__addPermissionsPage
odeimaiz Aug 22, 2025
99a9195
refactor
odeimaiz Aug 22, 2025
a6f19b5
more progress
odeimaiz Aug 22, 2025
7049063
call accessRights endpoints
odeimaiz Aug 25, 2025
d12b498
function role
odeimaiz Aug 25, 2025
b7b0eaf
minor fix
odeimaiz Aug 25, 2025
8a5eee5
createRolesFunctionInfo
odeimaiz Aug 25, 2025
8cf2081
refactor
odeimaiz Aug 25, 2025
e525d1a
default access rights
odeimaiz Aug 25, 2025
6291071
Can use it
odeimaiz Aug 25, 2025
8975e25
not used
odeimaiz Aug 25, 2025
2a46e98
minor
odeimaiz Aug 25, 2025
f0f78bc
curateOrderBy
odeimaiz Aug 25, 2025
2db9de3
comment
odeimaiz Aug 25, 2025
1243603
searchFunctionsPaginated
odeimaiz Aug 25, 2025
3604467
osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS
odeimaiz Aug 25, 2025
21d57f3
minor
odeimaiz Aug 25, 2025
8b5a967
SearchBarFilterExtended
odeimaiz Aug 25, 2025
27aa4b1
Study Browser
odeimaiz Aug 25, 2025
9c5ccf8
refactor
odeimaiz Aug 25, 2025
8eab3f0
refactor
odeimaiz Aug 25, 2025
a54e281
working
odeimaiz Aug 25, 2025
583f20f
Reduce number of buttons: Context in Drop Down
odeimaiz Aug 25, 2025
db222b7
minor
odeimaiz Aug 25, 2025
5b37fff
aesthetics
odeimaiz Aug 25, 2025
023e8b0
minWidth
odeimaiz Aug 25, 2025
96ed563
ARROOOOOOOOOOOOOOW
odeimaiz Aug 25, 2025
504dbba
minor
odeimaiz Aug 25, 2025
06dedaf
attachHideHandlers
odeimaiz Aug 25, 2025
21d97a8
not needed
odeimaiz Aug 25, 2025
3ddbf0a
comment
odeimaiz Aug 25, 2025
c712a14
Merge branch 'master' into feature/share-functions
odeimaiz Aug 25, 2025
2ed4975
getAllMyGroupIds
odeimaiz Aug 25, 2025
eaee376
Merge branch 'feature/share-functions' of github.com:odeimaiz/osparc-…
odeimaiz Aug 25, 2025
58ff54f
minor check
odeimaiz Aug 25, 2025
96e627f
one more check
odeimaiz Aug 25, 2025
fe75253
better fix
odeimaiz Aug 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ qx.Class.define("osparc.dashboard.GridButtonItem", {
_applyOwner: function(value, old) {
const label = this.getChildControl("subtitle-text");
if (osparc.utils.Resources.isFunction(this.getResourceData())) {
const canIWrite = Boolean(this.getResourceData()["accessRights"]["write"]);
// Functions don't have 'owner'
const canIWrite = osparc.data.model.Function.canIWrite(this.getResourceData()["accessRights"]);
label.setValue(canIWrite ? "My Function" : "Read Only");
} else {
const user = this.__createOwner(value);
Expand All @@ -262,20 +263,15 @@ qx.Class.define("osparc.dashboard.GridButtonItem", {
_applyAccessRights: function(value) {
if (value && Object.keys(value).length) {
const shareIcon = this.getChildControl("subtitle-icon");
if (this.isResourceType("function")) {
// in case of functions, the access rights are actually myAccessRights
osparc.dashboard.CardBase.populateMyAccessRightsIcon(shareIcon, value);
} else {
shareIcon.addListener("tap", e => {
e.stopPropagation();
this.openAccessRights();
}, this);
shareIcon.addListener("pointerdown", e => e.stopPropagation());
osparc.dashboard.CardBase.populateShareIcon(shareIcon, value);
shareIcon.addListener("tap", e => {
e.stopPropagation();
this.openAccessRights();
}, this);
shareIcon.addListener("pointerdown", e => e.stopPropagation());
osparc.dashboard.CardBase.populateShareIcon(shareIcon, value);

if (this.isResourceType("study")) {
this._setStudyPermissions(value);
}
if (this.isResourceType("study")) {
this._setStudyPermissions(value);
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ qx.Class.define("osparc.dashboard.ListButtonItem", {
_applyOwner: function(value, old) {
const label = this.getChildControl("owner");
if (osparc.utils.Resources.isFunction(this.getResourceData())) {
const canIWrite = Boolean(this.getResourceData()["accessRights"]["write"]);
// Functions don't have 'owner'
const canIWrite = osparc.data.model.Function.canIWrite(this.getResourceData()["accessRights"]);
label.setValue(canIWrite ? "My Function" : "Read Only");
} else {
const user = this.__createOwner(value);
Expand All @@ -257,20 +258,15 @@ qx.Class.define("osparc.dashboard.ListButtonItem", {
_applyAccessRights: function(value) {
if (value && Object.keys(value).length) {
const shareIcon = this.getChildControl("shared-icon");
if (this.isResourceType("function")) {
// in case of functions, the access rights are actually myAccessRights
osparc.dashboard.CardBase.populateMyAccessRightsIcon(shareIcon, value);
} else {
shareIcon.addListener("tap", e => {
e.stopPropagation();
this.openAccessRights();
}, this);
shareIcon.addListener("pointerdown", e => e.stopPropagation());
osparc.dashboard.CardBase.populateShareIcon(shareIcon, value);
shareIcon.addListener("tap", e => {
e.stopPropagation();
this.openAccessRights();
}, this);
shareIcon.addListener("pointerdown", e => e.stopPropagation());
osparc.dashboard.CardBase.populateShareIcon(shareIcon, value);

if (this.isResourceType("study")) {
this._setStudyPermissions(value);
}
if (this.isResourceType("study")) {
this._setStudyPermissions(value);
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
text = this.tr("No Public Projects found");
break;
case osparc.dashboard.StudyBrowser.CONTEXT.FUNCTIONS:
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS:
text = this.tr("No Functions found");
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
return;
} else if (osparc.utils.Resources.isFunction(this.__resourceData)) {
this.__addInfoPage();
this.__addPermissionsPage();
if (this.__resourceModel.getFunctionClass() === osparc.data.model.Function.FUNCTION_CLASS.PROJECT) {
this.__addPreviewPage();
}
Expand Down Expand Up @@ -641,6 +642,12 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
const updatedData = e.getData();
this.__fireUpdateEvent(resourceData, updatedData);
}, this);
} else if (osparc.utils.Resources.isFunction(resourceData)) {
collaboratorsView = new osparc.share.CollaboratorsFunction(resourceData);
collaboratorsView.addListener("updateAccessRights", e => {
const updatedData = e.getData();
this.__fireUpdateEvent(resourceData, updatedData);
}, this);
} else {
collaboratorsView = new osparc.share.CollaboratorsStudy(resourceData);
if (osparc.utils.Resources.isStudy(resourceData)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
"searchProjects", // osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PROJECTS,
"searchTemplates", // osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_TEMPLATES,
"searchPublicTemplates", // osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PUBLIC_TEMPLATES,
"searchFunctions" // osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS
],
init: null,
nullable: false,
Expand All @@ -62,24 +63,17 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
},

statics: {
createToolbarRadioButton: function(label, icon, toolTipText = null, pos = null) {
const rButton = new qx.ui.toolbar.RadioButton().set({
label,
icon,
toolTipText,
padding: 8,
decorateListItem: function(listItem) {
listItem.set({
gap: 8,
margin: 0,
backgroundColor: osparc.dashboard.SearchBarFilter.BG_COLOR,
});
rButton.getContentElement().setStyles({
"border-radius": "0px"
});
if (pos === "left") {
osparc.utils.Utils.addBorderLeftRadius(rButton);
} else if (pos === "right") {
osparc.utils.Utils.addBorderRightRadius(rButton);
}
return rButton;
},

createListItem: function(label, icon, model) {
const listItem = new qx.ui.form.ListItem(label, icon, model);
this.self().decorateListItem(listItem);
return listItem;
},
},

Expand All @@ -90,48 +84,74 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
let control;
switch (id) {
case "search-bar-filter": {
control = new osparc.dashboard.SearchBarFilter(this.__resourceType);
control = new osparc.dashboard.SearchBarFilter(this.__resourceType).set({
showFilterMenu: false,
});
const textField = control.getChildControl("text-field");
textField.addListener("appear", () => {
textField.focus();
textField.activate();
});
const resetButton = control.getChildControl("reset-button");
resetButton.set({
paddingRight: 2, // 10-8
opacity: 0.7,
backgroundColor: "transparent",
});
osparc.utils.Utils.hideBorder(resetButton);
this._add(control);
break;
}
case "context-buttons":
control = new qx.ui.toolbar.ToolBar().set({
spacing: 0,
padding: 0,
backgroundColor: osparc.dashboard.SearchBarFilter.BG_COLOR,
case "context-drop-down": {
control = new qx.ui.form.SelectBox().set({
minWidth: 150,
});
this._add(control);
control.getChildControl("arrow").syncAppearance(); // force sync to show the arrow
this.self().decorateListItem(control.getChildControl("atom"));
const searchBarFilter = this.getChildControl("search-bar-filter");
searchBarFilter._addAt(control, 3); //"search-icon", "active-filters", "text-field", "reset-button"
break;
case "my-projects-button":
control = this.self().createToolbarRadioButton(
}
case "my-projects-button": {
control = this.self().createListItem(
this.tr("My Projects"),
"@FontAwesome5Solid/file/14",
null,
"left",
"myProjects"
);
this.getChildControl("context-buttons").add(control);
const contextDropDown = this.getChildControl("context-drop-down");
contextDropDown.add(control);
break;
case "templates-button":
control = this.self().createToolbarRadioButton(
}
case "templates-button": {
control = this.self().createListItem(
this.tr("Templates"),
"@FontAwesome5Solid/copy/14",
"templates"
);
this.getChildControl("context-buttons").add(control);
const contextDropDown = this.getChildControl("context-drop-down");
contextDropDown.add(control);
break;
case "public-projects-button":
control = this.self().createToolbarRadioButton(
}
case "public-projects-button": {
control = this.self().createListItem(
this.tr("Public Projects"),
"@FontAwesome5Solid/globe/14",
null,
"right",
"publicProjects"
);
this.getChildControl("context-buttons").add(control);
const contextDropDown = this.getChildControl("context-drop-down");
contextDropDown.add(control);
break;
}
case "functions-button": {
control = this.self().createListItem(
this.tr("Functions"),
"@MaterialIcons/functions/18",
"functions"
);
const contextDropDown = this.getChildControl("context-drop-down");
contextDropDown.add(control);
break;
}
case "filter-buttons":
control = new qx.ui.toolbar.ToolBar().set({
backgroundColor: osparc.dashboard.SearchBarFilter.BG_COLOR,
Expand All @@ -153,30 +173,37 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
},

__buildLayout: function() {
this.getChildControl("search-bar-filter").set({
showFilterMenu: false,
});

const resetButton = this.getChildControl("search-bar-filter").getChildControl("reset-button");
resetButton.set({
paddingRight: 2, // 10-8
opacity: 0.7,
backgroundColor: "transparent",
const searchBarFilter = this.getChildControl("search-bar-filter");

const contextDropDown = this.getChildControl("context-drop-down");
this.getChildControl("my-projects-button");
this.getChildControl("templates-button");
this.getChildControl("public-projects-button");
this.getChildControl("functions-button");
contextDropDown.addListener("changeSelection", e => {
const selection = e.getData();
if (selection.length) {
const selectedContext = selection[0].getModel();
switch (selectedContext) {
case "myProjects":
this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PROJECTS);
break;
case "templates":
this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_TEMPLATES);
break;
case "publicProjects":
this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PUBLIC_TEMPLATES);
break;
case "functions":
this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS);
break;
}
}
});
osparc.utils.Utils.hideBorder(resetButton);

const radioGroup = new qx.ui.form.RadioGroup();
const myProjectsButton = this.getChildControl("my-projects-button");
const templatesButton = this.getChildControl("templates-button");
const publicProjectsButton = this.getChildControl("public-projects-button");
radioGroup.add(myProjectsButton, templatesButton, publicProjectsButton);
myProjectsButton.addListener("changeValue", e => e.getData() ? this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PROJECTS) : null, this);
templatesButton.addListener("changeValue", e => e.getData() ? this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_TEMPLATES) : null, this);
publicProjectsButton.addListener("changeValue", e => e.getData() ? this.setCurrentContext(osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PUBLIC_TEMPLATES) : null, this);

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

const resetButton = searchBarFilter.getChildControl("reset-button");
resetButton.addListener("tap", () => {
this.fireEvent("resetButtonPressed");
this.exclude();
Expand All @@ -219,24 +247,34 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
if (value === old) {
return;
}
const contextDropDown = this.getChildControl("context-drop-down");
const searchBarFilter = this.getChildControl("search-bar-filter");
const sharedWithButton = this.getChildControl("shared-with-button");
const tagsButton = this.getChildControl("tags-button");
switch (value) {
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PROJECTS:
this.getChildControl("my-projects-button").setValue(true);
this.getChildControl("search-bar-filter").getChildControl("text-field").setPlaceholder(this.tr("Search in My projects"));
this.getChildControl("shared-with-button").setVisibility("visible");
this.getChildControl("tags-button").setVisibility("visible");
contextDropDown.setSelection([this.getChildControl("my-projects-button")]);
searchBarFilter.getChildControl("text-field").setPlaceholder(this.tr("Search in My projects"));
sharedWithButton.setVisibility("visible");
tagsButton.setVisibility("visible");
break;
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_TEMPLATES:
this.getChildControl("templates-button").setValue(true);
this.getChildControl("search-bar-filter").getChildControl("text-field").setPlaceholder(this.tr("Search in Templates"));
this.getChildControl("shared-with-button").setVisibility("excluded");
this.getChildControl("tags-button").setVisibility("visible");
contextDropDown.setSelection([this.getChildControl("templates-button")]);
searchBarFilter.getChildControl("text-field").setPlaceholder(this.tr("Search in Templates"));
sharedWithButton.setVisibility("excluded");
tagsButton.setVisibility("visible");
break;
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_PUBLIC_TEMPLATES:
this.getChildControl("public-projects-button").setValue(true);
this.getChildControl("search-bar-filter").getChildControl("text-field").setPlaceholder(this.tr("Search in Public projects"));
this.getChildControl("shared-with-button").setVisibility("excluded");
this.getChildControl("tags-button").setVisibility("visible");
contextDropDown.setSelection([this.getChildControl("public-projects-button")]);
searchBarFilter.getChildControl("text-field").setPlaceholder(this.tr("Search in Public Projects"));
sharedWithButton.setVisibility("excluded");
tagsButton.setVisibility("visible");
break;
case osparc.dashboard.StudyBrowser.CONTEXT.SEARCH_FUNCTIONS:
contextDropDown.setSelection([this.getChildControl("functions-button")]);
searchBarFilter.getChildControl("text-field").setPlaceholder(this.tr("Search in Functions"));
sharedWithButton.setVisibility("excluded");
tagsButton.setVisibility("excluded");
break;
}
},
Expand Down Expand Up @@ -291,6 +329,12 @@ qx.Class.define("osparc.dashboard.SearchBarFilterExtended", {
this.__sharedWithMenu,
this.__tagsMenu,
];
// handle clicks on the drop down menu that might go out of bounds
const contextDropDown = this.getChildControl("context-drop-down");
const popup = contextDropDown.getChildControl("popup");
if (popup.isVisible()) {
excludeElements.push(popup);
}
for (let i = 0; i < excludeElements.length; i++) {
if (excludeElements[i] && osparc.utils.Utils.isMouseOnElement(excludeElements[i], e)) {
return;
Expand Down
Loading
Loading