Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [Frontend] Feature: Share Tags #6899

Merged
merged 39 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1222d6d
refactor
odeimaiz Dec 3, 2024
74c1fd8
multiselect propoerty
odeimaiz Dec 3, 2024
67ed884
refactor
odeimaiz Dec 3, 2024
7cc1727
more compact icon
odeimaiz Dec 3, 2024
b5988fd
aesthetics
odeimaiz Dec 3, 2024
d129744
[skip ci] allowMultiselection
odeimaiz Dec 3, 2024
57448e3
Merge branch 'master' into enh/multiselect-data
odeimaiz Dec 4, 2024
3e1870d
Merge branch 'master' into enh/multiselect-data
odeimaiz Dec 4, 2024
a95fc6e
minor
odeimaiz Dec 4, 2024
82c013d
multiSelectionChanged
odeimaiz Dec 4, 2024
8e28e68
minor
odeimaiz Dec 4, 2024
7104733
tag accessRights
odeimaiz Dec 4, 2024
d86c061
fetchAccessRights
odeimaiz Dec 4, 2024
f71e3ca
Merge branch 'master' into feature/share-tags
odeimaiz Jan 6, 2025
01eabbe
better practises
odeimaiz Jan 6, 2025
82855c0
[skip ci] share-icon
odeimaiz Jan 6, 2025
7b21119
Merge branch 'master' into feature/share-tags
odeimaiz Jan 7, 2025
fbe8e31
CollaboratorsTag
odeimaiz Jan 7, 2025
fd25441
Merge branch 'master' into feature/share-tags
odeimaiz Jan 7, 2025
9677df1
text
odeimaiz Jan 7, 2025
33adc76
minor fix
odeimaiz Jan 7, 2025
766ee8f
canI write/delete
odeimaiz Jan 7, 2025
a215c9d
myAccessRights
odeimaiz Jan 7, 2025
a6d75ed
[skip ci] refactoring
odeimaiz Jan 7, 2025
8c1d22f
minors
odeimaiz Jan 7, 2025
684e2ee
minor
odeimaiz Jan 7, 2025
815bd4c
Merge branch 'master' into feature/share-tags
odeimaiz Jan 7, 2025
cc826bb
Merge branch 'feature/share-tags' of github.com:odeimaiz/osparc-simco…
odeimaiz Jan 7, 2025
ae45706
myAccessRights
odeimaiz Jan 7, 2025
4f3102b
populate share icon
odeimaiz Jan 7, 2025
1844cbe
list collaborators
odeimaiz Jan 7, 2025
0f1ba36
fix postTag
odeimaiz Jan 7, 2025
0c8e8e2
CRUD accessRights
odeimaiz Jan 7, 2025
73bcf94
viewer per default
odeimaiz Jan 7, 2025
df4ca4c
update shared icon
odeimaiz Jan 7, 2025
081de8d
Merge branch 'master' into feature/share-tags
odeimaiz Jan 7, 2025
5a53f1a
Merge branch 'master' into feature/share-tags
odeimaiz Jan 7, 2025
68f482d
Merge branch 'master' into feature/share-tags
odeimaiz Jan 7, 2025
d6f8ff8
Merge branch 'master' into feature/share-tags
odeimaiz Jan 8, 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 @@ -1266,7 +1266,23 @@ qx.Class.define("osparc.data.Resources", {
delete: {
method: "DELETE",
url: statics.API + "/tags/{tagId}"
}
},
getAccessRights: {
method: "GET",
url: statics.API + "/tags/{tagId}/groups"
},
putAccessRights: {
method: "PUT",
url: statics.API + "/tags/{tagId}/groups/{groupId}"
},
postAccessRights: {
method: "POST",
url: statics.API + "/tags/{tagId}/groups/{groupId}"
},
deleteAccessRights: {
method: "DELETE",
url: statics.API + "/tags/{tagId}/groups/{groupId}"
},
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ qx.Class.define("osparc.data.model.Tag", {
name: tagData.name,
description: tagData.description,
color: tagData.color,
accessRights: tagData.accessRights,
myAccessRights: tagData.accessRights,
});
},

Expand Down Expand Up @@ -65,6 +65,13 @@ qx.Class.define("osparc.data.model.Tag", {
init: "#303030"
},

myAccessRights: {
check: "Object",
nullable: false,
init: null,
event: "changeMyAccessRights"
},

accessRights: {
check: "Object",
nullable: false,
Expand All @@ -73,6 +80,12 @@ qx.Class.define("osparc.data.model.Tag", {
},
},

statics: {
getProperties: function() {
return Object.keys(qx.util.PropertyUtil.getProperties(osparc.data.model.Tag));
}
},

members: {
serialize: function() {
const jsonObject = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,9 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
converter: val => val ? "tab-button-selected" : "tab-button"
});
if (widget) {
tabPage.add(widget, {
const scrollView = new qx.ui.container.Scroll();
scrollView.add(widget);
tabPage.add(scrollView, {
flex: 1
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ qx.Class.define("osparc.desktop.preferences.pages.TagsPage", {
const studiesLabel = osparc.product.Utils.getStudyAlias({plural: true});
const studyLabel = osparc.product.Utils.getStudyAlias();
const msg = this.tr("\
Tags are annotations to help users with grouping ") + studiesLabel + this.tr(" in the Dashboard. \
Tags help you organize the ") + studiesLabel + this.tr(" in the Dashboard by categorizing topics, making it easier to search and filter. \
Once the tags are created, they can be assigned to the ") + studyLabel + this.tr(" via 'More options...' on the ") + studyLabel + this.tr(" cards.");
const intro = osparc.ui.window.TabbedView.createHelpLabel(msg);
this._add(intro);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ qx.Class.define("osparc.form.tag.TagItem", {
this.base(arguments);
this._setLayout(new qx.ui.layout.HBox(5));
this.__validationManager = new qx.ui.form.validation.Manager();
this.__renderLayout();
},

statics: {
Expand Down Expand Up @@ -57,18 +56,23 @@ qx.Class.define("osparc.form.tag.TagItem", {
init: "#303030"
},

myAccessRights: {
check: "Object",
nullable: false,
event: "changeMyAccessRights",
},

accessRights: {
check: "Object",
nullable: false,
event: "changeAccessRights",
apply: "__renderLayout",
},

mode: {
check: "String",
init: "display",
nullable: false,
apply: "_applyMode"
apply: "__applyMode"
},

appearance: {
Expand All @@ -84,83 +88,62 @@ qx.Class.define("osparc.form.tag.TagItem", {
},

members: {
__tag: null,
__description: null,
__nameInput: null,
__descriptionInput: null,
__colorInput: null,
__colorButton: null,
__loadingIcon: null,
__validationManager: null,

_createChildControlImpl: function(id) {
let control;
switch (id) {
case "tag":
// Tag sample on display mode
if (this.__tag === null) {
this.__tag = new osparc.ui.basic.Tag();
this.bind("name", this.__tag, "value");
this.bind("color", this.__tag, "color");
}
control = this.__tag;
control = new osparc.ui.basic.Tag();
this.bind("name", control, "value");
this.bind("color", control, "color");
break;
case "description":
// Description label on display mode
if (this.__description === null) {
this.__description = new qx.ui.basic.Label().set({
rich: true
});
this.bind("description", this.__description, "value");
}
control = this.__description;
control = new qx.ui.basic.Label().set({
rich: true,
allowGrowX: true,
});
this.bind("description", control, "value");
break;
case "shared-icon":
control = new qx.ui.basic.Image().set({
minWidth: 30,
alignY: "middle",
cursor: "pointer",
});
osparc.dashboard.CardBase.populateShareIcon(control, this.getAccessRights())
control.addListener("tap", () => this.__openAccessRights(), this);
break;
case "name-input":
// Tag name input in edit mode
if (this.__nameInput === null) {
this.__nameInput = new qx.ui.form.TextField().set({
required: true
});
this.__validationManager.add(this.__nameInput);
this.__nameInput.getContentElement().setAttribute("autocomplete", "off");
}
control = this.__nameInput;
control = new qx.ui.form.TextField().set({
required: true
});
this.__validationManager.add(control);
control.getContentElement().setAttribute("autocomplete", "off");
break;
case "description-input":
// Tag description input in edit mode
if (this.__descriptionInput === null) {
this.__descriptionInput = new qx.ui.form.TextArea().set({
autoSize: true,
minimalLineHeight: 1
});
}
control = this.__descriptionInput;
control = new qx.ui.form.TextArea().set({
autoSize: true,
minimalLineHeight: 1
});
break;
case "color-input":
// Color input in edit mode
if (this.__colorInput === null) {
this.__colorInput = new qx.ui.form.TextField().set({
value: this.getColor(),
width: 60,
required: true
});
this.__colorInput.bind("value", this.getChildControl("color-button"), "backgroundColor");
this.__colorInput.bind("value", this.getChildControl("color-button"), "textColor", {
converter: value => osparc.utils.Utils.getContrastedBinaryColor(value)
});
this.__validationManager.add(this.__colorInput, osparc.utils.Validators.hexColor);
}
control = this.__colorInput;
control = new qx.ui.form.TextField().set({
value: this.getColor(),
width: 60,
required: true
});
control.bind("value", this.getChildControl("color-button"), "backgroundColor");
control.bind("value", this.getChildControl("color-button"), "textColor", {
converter: value => osparc.utils.Utils.getContrastedBinaryColor(value)
});
this.__validationManager.add(control, osparc.utils.Validators.hexColor);
break;
case "color-button":
// Random color generator button in edit mode
if (this.__colorButton === null) {
this.__colorButton = new qx.ui.form.Button(null, "@FontAwesome5Solid/sync-alt/12");
this.__colorButton.addListener("execute", () => {
this.getChildControl("color-input").setValue(osparc.utils.Utils.getRandomColor());
}, this);
}
control = this.__colorButton;
control = new qx.ui.form.Button(null, "@FontAwesome5Solid/sync-alt/12");
control.addListener("execute", () => {
this.getChildControl("color-input").setValue(osparc.utils.Utils.getRandomColor());
}, this);
break;
}
return control || this.base(arguments, id);
Expand All @@ -171,7 +154,10 @@ qx.Class.define("osparc.form.tag.TagItem", {
tag.bind("name", this, "name");
tag.bind("description", this, "description");
tag.bind("color", this, "color");
tag.bind("myAccessRights", this, "myAccessRights");
tag.bind("accessRights", this, "accessRights");

this.__renderLayout();
},

/**
Expand Down Expand Up @@ -212,40 +198,48 @@ qx.Class.define("osparc.form.tag.TagItem", {
},

__renderDisplayMode: function() {
const tagContainer = new qx.ui.container.Composite(new qx.ui.layout.HBox()).set({
width: 100
});
tagContainer.add(this.getChildControl("tag"));
this._add(tagContainer);
const descriptionContainer = new qx.ui.container.Composite(new qx.ui.layout.HBox());
descriptionContainer.add(this.getChildControl("description"), {
width: "100%"
});
this._add(descriptionContainer, {
this._add(this.getChildControl("tag"));
this._add(this.getChildControl("description"), {
flex: 1
});
this._add(this.getChildControl("shared-icon"));
this._add(this.__tagItemButtons());
this.resetBackgroundColor();
},

__openAccessRights: function() {
const permissionsView = new osparc.share.CollaboratorsTag(this.getTag());
const title = this.tr("Share Tag");
osparc.ui.window.Window.popUpInWindow(permissionsView, title, 600, 600);

permissionsView.addListener("updateAccessRights", () => {
const accessRights = this.getTag().getAccessRights();
if (accessRights) {
const sharedIcon = this.getChildControl("shared-icon");
osparc.dashboard.CardBase.populateShareIcon(sharedIcon, accessRights);
}
}, this);
},

/**
* Generates and returns the buttons for deleting and editing an existing label (display mode)
*/
__tagItemButtons: function() {
const canIWrite = osparc.share.CollaboratorsTag.canIWrite(this.getMyAccessRights());
const canIDelete = osparc.share.CollaboratorsTag.canIDelete(this.getMyAccessRights());

const buttonContainer = new qx.ui.container.Composite(new qx.ui.layout.HBox());
const editButton = new qx.ui.form.Button().set({
icon: "@FontAwesome5Solid/pencil-alt/12",
toolTipText: this.tr("Edit")
toolTipText: this.tr("Edit"),
enabled: canIWrite,
});
const deleteButton = new osparc.ui.form.FetchButton().set({
appearance: "danger-button",
icon: "@FontAwesome5Solid/trash/12",
toolTipText: this.tr("Delete")
toolTipText: this.tr("Delete"),
enabled: canIDelete,
});
if (this.isPropertyInitialized("accessRights")) {
editButton.setEnabled(this.getAccessRights()["write"]);
deleteButton.setEnabled(this.getAccessRights()["delete"]);
}
buttonContainer.add(editButton);
buttonContainer.add(deleteButton);
editButton.addListener("execute", () => this.setMode(this.self().modes.EDIT), this);
Expand Down Expand Up @@ -279,20 +273,31 @@ qx.Class.define("osparc.form.tag.TagItem", {
if (this.__validationManager.validate()) {
const data = this.__serializeData();
saveButton.setFetching(true);
let fetch;
const tagsStore = osparc.store.Tags.getInstance();
if (this.isPropertyInitialized("id")) {
fetch = osparc.store.Tags.getInstance().putTag(this.getId(), data);
tagsStore.putTag(this.getId(), data)
.then(tag => this.setTag(tag))
.catch(console.error)
.finally(() => {
this.fireEvent("tagSaved");
this.setMode(this.self().modes.DISPLAY);
saveButton.setFetching(false);
});
} else {
fetch = osparc.store.Tags.getInstance().postTag(data);
let newTag = null;
tagsStore.postTag(data)
.then(tag => {
newTag = tag;
return tagsStore.fetchAccessRights(tag);
})
.then(() => this.setTag(newTag))
.catch(console.error)
.finally(() => {
this.fireEvent("tagSaved");
this.setMode(this.self().modes.DISPLAY);
saveButton.setFetching(false);
});
}
fetch
.then(tag => this.setTag(tag))
.catch(console.error)
.finally(() => {
this.fireEvent("tagSaved");
this.setMode(this.self().modes.DISPLAY);
saveButton.setFetching(false);
});
}
}, this);
cancelButton.addListener("execute", () => {
Expand Down Expand Up @@ -334,7 +339,7 @@ qx.Class.define("osparc.form.tag.TagItem", {
color: color
};
},
_applyMode: function() {
__applyMode: function() {
this.__renderLayout();
}
}
Expand Down
Loading
Loading