Skip to content

Commit 9de4d19

Browse files
🎨 [Frontend] Workspaces & Folders: Show them as a tree (#6343)
Co-authored-by: matusdrobuliak66 <[email protected]>
1 parent 0722af4 commit 9de4d19

File tree

6 files changed

+218
-26
lines changed

6 files changed

+218
-26
lines changed

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
8383
statics: {
8484
PAGINATED_STUDIES: 10,
8585
MIN_GRID_CARDS_PER_ROW: 3,
86-
SIDE_SPACER_WIDTH: 180,
86+
SIDE_SPACER_WIDTH: 200,
8787

8888
checkLoggedIn: function() {
8989
const isLogged = osparc.auth.Manager.getInstance().isLoggedIn();
@@ -359,7 +359,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
359359

360360
_addResourceFilter: function() {
361361
const resourceFilter = this._resourceFilter = new osparc.dashboard.ResourceFilter(this._resourceType).set({
362-
marginTop: osparc.dashboard.SearchBarFilter.HEIGHT + 10, // aligned with toolbar buttons: search bar + spacing
362+
marginTop: osparc.dashboard.SearchBarFilter.HEIGHT,
363363
maxWidth: this.self().SIDE_SPACER_WIDTH,
364364
width: this.self().SIDE_SPACER_WIDTH
365365
});
@@ -372,6 +372,14 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
372372
this._searchBarFilter.setSharedWithActiveFilter(sharedWith.id, sharedWith.label);
373373
}, this);
374374

375+
if (this._resourceType === "study") {
376+
const workspacesAndFoldersTree = resourceFilter.getWorkspacesAndFoldersTree();
377+
workspacesAndFoldersTree.bind("currentWorkspaceId", this, "currentWorkspaceId");
378+
workspacesAndFoldersTree.bind("currentFolderId", this, "currentFolderId");
379+
this.bind("currentWorkspaceId", workspacesAndFoldersTree, "currentWorkspaceId");
380+
this.bind("currentFolderId", workspacesAndFoldersTree, "currentFolderId");
381+
}
382+
375383
resourceFilter.addListener("changeWorkspace", e => {
376384
const workspaceId = e.getData();
377385
this.setCurrentWorkspaceId(workspaceId);
@@ -395,7 +403,9 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
395403
resourceFilter.filterChanged(filterData);
396404
});
397405

398-
this.__leftFilters.add(resourceFilter);
406+
this.__leftFilters.add(resourceFilter, {
407+
flex: 1
408+
});
399409
},
400410

401411
/**

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,12 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
3030
this.__tagButtons = [];
3131
this.__serviceTypeButtons = [];
3232

33-
this._setLayout(new qx.ui.layout.VBox());
33+
this._setLayout(new qx.ui.layout.VBox(30));
3434
this.__buildLayout();
3535
},
3636

3737
events: {
3838
"changeSharedWith": "qx.event.type.Data",
39-
"changeWorkspace": "qx.event.type.Data",
4039
"changeSelectedTags": "qx.event.type.Data",
4140
"changeServiceType": "qx.event.type.Data"
4241
},
@@ -45,29 +44,39 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
4544
__resourceType: null,
4645
__contextLayout: null,
4746
__contextRadioGroup: null,
47+
__workspacesAndFoldersTree: null,
4848
__sharedWithButtons: null,
4949
__workspaceButtons: null,
5050
__tagButtons: null,
5151
__serviceTypeButtons: null,
5252

5353
__buildLayout: function() {
54-
const layout = new qx.ui.container.Composite(new qx.ui.layout.VBox(40));
55-
56-
layout.add(this.__createSharedWithFilterLayout());
54+
if (this.__resourceType === "study") {
55+
this._add(this.__createWorkspacesAndFoldersTree());
56+
} else {
57+
this._add(this.__createSharedWithFilterLayout());
58+
}
5759

5860
if (this.__resourceType !== "service") {
59-
layout.add(this.__createTagsFilterLayout());
61+
this._add(this.__createTagsFilterLayout());
6062
}
6163

6264
if (this.__resourceType === "service") {
63-
layout.add(this.__createServiceTypeFilterLayout());
65+
this._add(this.__createServiceTypeFilterLayout());
6466
}
67+
},
6568

66-
const scrollContainer = new qx.ui.container.Scroll();
67-
scrollContainer.add(layout);
68-
this._add(scrollContainer, {
69-
flex: 1
70-
});
69+
__createWorkspacesAndFoldersTree: function() {
70+
const workspacesAndFoldersTree = this.__workspacesAndFoldersTree = new osparc.dashboard.WorkspacesAndFoldersTree();
71+
// play with the height of:
72+
// osparc.dashboard.WorkspacesAndFoldersTree
73+
// Pane
74+
// 1st child
75+
return workspacesAndFoldersTree;
76+
},
77+
78+
getWorkspacesAndFoldersTree: function() {
79+
return this.__workspacesAndFoldersTree;
7180
},
7281

7382
/* SHARED WITH */
@@ -121,10 +130,6 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
121130
this.__sharedWithButtons.push(button);
122131
});
123132

124-
if (this.__resourceType === "study") {
125-
this.__addWorkspaceButtons();
126-
}
127-
128133
return layout;
129134
},
130135
/* /SHARED WITH */

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
105105
__currentRequest: null,
106106
__workspacesList: null,
107107
__foldersList: null,
108+
__reloadFoldersAndStudiesTimeout: null,
108109

109110
// overridden
110111
initResources: function() {
@@ -401,11 +402,7 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
401402
if (workspaceId === -1) {
402403
this._resourcesContainer.setResourcesToList([]);
403404
this._resourcesList = [];
404-
405405
this.__reloadWorkspaces();
406-
} else if (this.getCurrentFolderId()) {
407-
// this will also trigger the __resetAndReloadAll
408-
this.setCurrentFolderId(null);
409406
} else {
410407
this.__resetAndReloadAll();
411408
}
@@ -461,7 +458,15 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
461458
this._resourcesList = [];
462459
this.invalidateStudies();
463460

464-
this.__reloadFoldersAndStudies();
461+
// It can be triggered by a change of context: workspace and folder,
462+
// delay it to make just one call
463+
if (this.__reloadFoldersAndStudiesTimeout) {
464+
clearTimeout(this.__reloadFoldersAndStudiesTimeout);
465+
}
466+
this.__reloadFoldersAndStudiesTimeout = setTimeout(() => {
467+
this.__reloadFoldersAndStudiesTimeout = null;
468+
this.__reloadFoldersAndStudies();
469+
}, 50);
465470
}
466471
},
467472

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
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+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
qx.Class.define("osparc.dashboard.WorkspacesAndFoldersTree", {
19+
extend: qx.ui.tree.VirtualTree,
20+
21+
construct: function() {
22+
const treeName = "WorkspacesAndFoldersTree";
23+
const rootData = {
24+
label: treeName,
25+
children: [],
26+
loaded: true,
27+
};
28+
const rootModel = qx.data.marshal.Json.createModel(rootData, true);
29+
30+
this.base(arguments, rootModel, "label", "children");
31+
32+
this.set({
33+
openMode: "dbltap",
34+
decorator: "no-border",
35+
font: "text-14",
36+
hideRoot: true,
37+
paddingLeft: -10,
38+
});
39+
40+
this.__addMyWorkspace(rootModel);
41+
this.__addSharedWorkspaces(rootModel);
42+
43+
this.__initTree();
44+
},
45+
46+
properties: {
47+
currentWorkspaceId: {
48+
check: "Number",
49+
nullable: true,
50+
init: null,
51+
event: "changeCurrentWorkspaceId",
52+
// apply: "__applyCurrentWorkspaceId"
53+
},
54+
55+
currentFolderId: {
56+
check: "Number",
57+
nullable: true,
58+
init: null,
59+
event: "changeCurrentFolderId",
60+
// apply: "__resetAndReloadAll"
61+
},
62+
},
63+
64+
members: {
65+
__initTree: function() {
66+
const that = this;
67+
this.setDelegate({
68+
bindItem: (c, item, id) => {
69+
c.bindDefaultProperties(item, id);
70+
c.bindProperty("", "open", {
71+
converter(value, model, source, target) {
72+
const isOpen = target.isOpen();
73+
if (isOpen && !value.getLoaded()) {
74+
// eslint-disable-next-line no-underscore-dangle
75+
that.__populateFolder(value, value.getWorkspaceId(), value.getFolderId());
76+
}
77+
return isOpen;
78+
},
79+
}, item, id);
80+
},
81+
configureItem: item => {
82+
item.addListener("tap", () => {
83+
this.set({
84+
currentWorkspaceId: item.getModel().getWorkspaceId(),
85+
currentFolderId: item.getModel().getFolderId(),
86+
})
87+
}, this);
88+
},
89+
});
90+
91+
this.setIconPath("icon");
92+
this.setIconOptions({
93+
converter(value) {
94+
if (value === "shared") {
95+
return osparc.store.Workspaces.iconPath(18);
96+
} else if (value === "home") {
97+
return "@FontAwesome5Solid/home/16";
98+
}
99+
return "@FontAwesome5Solid/folder/16";
100+
},
101+
});
102+
},
103+
104+
__addMyWorkspace: function(rootModel) {
105+
const myWorkspaceData = {
106+
label: "My Workspace",
107+
icon: "home",
108+
workspaceId: null,
109+
folderId: null,
110+
loaded: false,
111+
children: [{
112+
label: "Loading...",
113+
}],
114+
}
115+
const myWorkspaceModel = qx.data.marshal.Json.createModel(myWorkspaceData, true);
116+
rootModel.getChildren().append(myWorkspaceModel);
117+
},
118+
119+
__addSharedWorkspaces: function(rootModel) {
120+
const sharedWorkspaceData = {
121+
label: "Shared Workspace",
122+
icon: "shared",
123+
workspaceId: -1,
124+
folderId: null,
125+
loaded: true,
126+
children: [],
127+
}
128+
const sharedWorkspaceModel = qx.data.marshal.Json.createModel(sharedWorkspaceData, true);
129+
rootModel.getChildren().append(sharedWorkspaceModel);
130+
131+
osparc.store.Workspaces.fetchWorkspaces()
132+
.then(workspaces => {
133+
workspaces.forEach(workspace => {
134+
const workspaceData = {
135+
label: workspace.getName(),
136+
icon: "shared",
137+
workspaceId: workspace.getWorkspaceId(),
138+
folderId: null,
139+
loaded: false,
140+
children: [{
141+
label: "Loading...",
142+
}],
143+
};
144+
const workspaceModel = qx.data.marshal.Json.createModel(workspaceData, true);
145+
sharedWorkspaceModel.getChildren().append(workspaceModel);
146+
});
147+
})
148+
.catch(console.error);
149+
},
150+
151+
__populateFolder: function(model, workspaceId, folderId) {
152+
osparc.store.Folders.getInstance().fetchFolders(folderId, workspaceId)
153+
.then(folders => {
154+
model.setLoaded(true);
155+
model.getChildren().removeAll();
156+
folders.forEach(folder => {
157+
const folderData = {
158+
label: folder.getName(),
159+
icon: workspaceId ? "shared" : "folder",
160+
workspaceId,
161+
folderId: folder.getFolderId(),
162+
loaded: false,
163+
children: [{
164+
label: "Loading...",
165+
}]
166+
};
167+
model.getChildren().push(qx.data.marshal.Json.createModel(folderData, true));
168+
});
169+
});
170+
}
171+
}
172+
});

services/static-webserver/client/source/class/osparc/file/FilesTree.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ qx.Class.define("osparc.file.FilesTree", {
4545
this.set({
4646
openMode: "none",
4747
decorator: "no-border",
48-
font: "text-14"
48+
font: "text-14",
4949
});
5050

5151
this.resetChecks();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ qx.Class.define("osparc.study.Utils", {
220220
if ("task_progress" in updateData && loadingPage) {
221221
const progress = updateData["task_progress"];
222222
const message = progress["message"];
223-
const percent = progress["percent"] ? progress["percent"].toFixed(3) : progress["percent"];
223+
const percent = progress["percent"] ? parseFloat(progress["percent"].toFixed(3)) : progress["percent"];
224224
progressSequence.setOverallProgress(percent);
225225
const existingTask = progressSequence.getTask(message);
226226
if (existingTask) {

0 commit comments

Comments
 (0)