Skip to content

Commit 0b2ea9f

Browse files
authored
✨ [Frontend] Search Files (#8520)
1 parent a7cae35 commit 0b2ea9f

File tree

24 files changed

+827
-93
lines changed

24 files changed

+827
-93
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ qx.Class.define("osparc.dashboard.CardContainer", {
2727
return (
2828
widget instanceof osparc.dashboard.CardBase ||
2929
widget instanceof osparc.dashboard.FolderButtonBase ||
30-
widget instanceof osparc.dashboard.WorkspaceButtonBase
30+
widget instanceof osparc.dashboard.WorkspaceButtonBase ||
31+
widget instanceof osparc.dashboard.FileButtonItem
3132
);
3233
},
3334
},
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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+
/**
19+
* Widget used for displaying a File in the Study Browser
20+
*
21+
*/
22+
23+
qx.Class.define("osparc.dashboard.FileButtonItem", {
24+
extend: osparc.dashboard.ListButtonBase,
25+
26+
/**
27+
* @param file {osparc.data.model.File} The file to display
28+
*/
29+
construct: function(file) {
30+
this.base(arguments);
31+
32+
this.set({
33+
cursor: "default",
34+
});
35+
36+
this.setPriority(osparc.dashboard.CardBase.CARD_PRIORITY.ITEM);
37+
38+
this.set({
39+
file: file
40+
});
41+
},
42+
43+
events: {
44+
"openLocation": "qx.event.type.Data",
45+
},
46+
47+
properties: {
48+
file: {
49+
check: "osparc.data.model.File",
50+
nullable: false,
51+
init: null,
52+
apply: "__applyFile",
53+
},
54+
},
55+
56+
members: {
57+
_createChildControlImpl: function(id) {
58+
let control;
59+
switch (id) {
60+
case "date-by":
61+
control = new osparc.ui.basic.DateAndBy();
62+
this._add(control, {
63+
row: 0,
64+
column: osparc.dashboard.ListButtonBase.POS.LAST_CHANGE
65+
});
66+
break;
67+
case "menu-button": {
68+
control = new qx.ui.form.MenuButton().set({
69+
appearance: "form-button-outlined",
70+
padding: [0, 8],
71+
maxWidth: osparc.dashboard.ListButtonItem.MENU_BTN_DIMENSIONS,
72+
maxHeight: osparc.dashboard.ListButtonItem.MENU_BTN_DIMENSIONS,
73+
alignX: "center",
74+
alignY: "middle",
75+
icon: "@FontAwesome5Solid/ellipsis-v/14",
76+
focusable: false
77+
});
78+
// make it circular
79+
control.getContentElement().setStyles({
80+
"border-radius": `${osparc.dashboard.ListButtonItem.MENU_BTN_DIMENSIONS / 2}px`
81+
});
82+
this._add(control, {
83+
row: 0,
84+
column: osparc.dashboard.ListButtonBase.POS.OPTIONS
85+
});
86+
break;
87+
}
88+
}
89+
return control || this.base(arguments, id);
90+
},
91+
92+
__applyFile: function(file) {
93+
const id = file.getPath();
94+
this.set({
95+
cardKey: "file-" + id,
96+
});
97+
osparc.utils.Utils.setIdToWidget(this, "fileItem_" + id);
98+
99+
this.setIcon(file.getIsDirectory() ? "@FontAwesome5Solid/folder/" : "@FontAwesome5Solid/file/");
100+
this.getChildControl("icon").getChildControl("image").set({
101+
paddingTop: 5,
102+
});
103+
104+
this.getChildControl("title").set({
105+
value: file.getName(),
106+
toolTipText: file.getName(),
107+
});
108+
109+
this.getChildControl("owner").set({
110+
value: "Project Id: " + osparc.utils.Utils.uuidToShort(file.getProjectId()),
111+
});
112+
113+
this.getChildControl("date-by").set({
114+
date: file.getModifiedAt(),
115+
toolTipText: this.tr("Last modified"),
116+
});
117+
118+
const menuButton = this.getChildControl("menu-button");
119+
menuButton.setVisibility("visible");
120+
121+
const menu = new qx.ui.menu.Menu().set({
122+
appearance: "menu-wider",
123+
position: "bottom-right",
124+
});
125+
126+
const openLocationButton = new qx.ui.menu.Button(this.tr("Open location"), "@FontAwesome5Solid/folder/12");
127+
openLocationButton.addListener("execute", () => this.fireDataEvent("openLocation", {
128+
projectId: file.getProjectId(),
129+
path: file.getPath()
130+
}), this);
131+
menu.add(openLocationButton);
132+
133+
menuButton.setMenu(menu);
134+
},
135+
}
136+
});

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ qx.Class.define("osparc.dashboard.ListButtonBase", {
4242
},
4343

4444
statics: {
45-
ITEM_HEIGHT: 35,
45+
ITEM_HEIGHT: 40,
4646
SPACING: 5,
4747
POS: {
4848
THUMBNAIL: 0,

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ qx.Class.define("osparc.dashboard.ListButtonLoadMore", {
3939
members: {
4040
_applyFetching: function(value) {
4141
this.setIcon(osparc.dashboard.CardBase.LOADING_ICON);
42+
const image = this.getChildControl("icon").getChildControl("image");
43+
image.setPadding(5); // add padding to make the rotation smoother
4244
if (value) {
43-
this.getChildControl("icon").getChildControl("image").getContentElement()
44-
.addClass("rotate");
45+
image.getContentElement().addClass("rotate");
4546
} else {
46-
this.getChildControl("icon").getChildControl("image").getContentElement()
47-
.removeClass("rotate");
47+
image.getContentElement().removeClass("rotate");
4848
}
4949
this.setEnabled(!value);
5050
},

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
357357
resourcesContainer.addListener("trashWorkspaceRequested", e => this._trashWorkspaceRequested(e.getData()));
358358
resourcesContainer.addListener("untrashWorkspaceRequested", e => this._untrashWorkspaceRequested(e.getData()));
359359
resourcesContainer.addListener("deleteWorkspaceRequested", e => this._deleteWorkspaceRequested(e.getData()));
360+
resourcesContainer.addListener("openLocation", e => this._openLocation(e.getData()));
360361

361362
this._addToLayout(resourcesContainer);
362363
},
@@ -928,7 +929,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
928929
throw new Error("Abstract method called!");
929930
},
930931

931-
_workspaceSelected: function(workspaceId) {
932+
_openLocation: function(data) {
932933
throw new Error("Abstract method called!");
933934
},
934935

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

Lines changed: 95 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
2929

3030
this.__workspacesList = [];
3131
this.__foldersList = [];
32+
this.__filesList = [];
3233
this.__resourcesList = [];
3334
this.__groupedContainersList = [];
3435
this.__resourceType = resourceType || "study";
@@ -41,14 +42,16 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
4142
const foldersContainer = this.__foldersContainer = new osparc.dashboard.CardContainer();
4243
this.__foldersContainer.exclude();
4344
this._add(foldersContainer);
45+
46+
const filesContainer = this.__filesContainer = new osparc.dashboard.CardContainer();
47+
filesContainer.getLayout().set({
48+
spacingY: osparc.dashboard.ListButtonBase.SPACING,
49+
});
50+
this.__filesContainer.exclude();
51+
this._add(filesContainer);
4452
}
4553

46-
const noResourcesFound = this.__noResourcesFound = new qx.ui.basic.Label("No resources found").set({
47-
visibility: "excluded",
48-
font: "text-14"
49-
});
50-
noResourcesFound.exclude();
51-
this._add(noResourcesFound);
54+
this.getChildControl("no-resources-found");
5255

5356
const nonGroupedContainer = this.__nonGroupedContainer = this.__createFlatList();
5457
this._add(nonGroupedContainer);
@@ -98,6 +101,7 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
98101
"changeContext": "qx.event.type.Data",
99102
"studyToFolderRequested": "qx.event.type.Data",
100103
"folderToFolderRequested": "qx.event.type.Data",
104+
"openLocation": "qx.event.type.Data",
101105
},
102106

103107
statics: {
@@ -128,22 +132,52 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
128132
spacingY: spacing
129133
});
130134
},
135+
136+
fitToContainer: function(card, container) {
137+
const __fitToContainer = () => {
138+
const bounds = container.getBounds() || container.getSizeHint();
139+
card.setWidth(bounds.width);
140+
};
141+
[
142+
"appear",
143+
"resize",
144+
].forEach(ev => {
145+
container.addListener(ev, () => __fitToContainer());
146+
});
147+
__fitToContainer();
148+
},
131149
},
132150

133151
members: {
134152
__foldersList: null,
135153
__workspacesList: null,
154+
__filesList: null,
136155
__resourcesList: null,
137156
__groupedContainersList: null,
138157
__foldersContainer: null,
139158
__workspacesContainer: null,
159+
__filesContainer: null,
140160
__nonGroupedContainer: null,
141161
__groupedContainers: null,
142162
__resourceType: null,
143-
__noResourcesFound: null,
144163
__noResourcesFoundTimer: null,
145164

146-
__evaluateNoResourcesFoundLabel: function() {
165+
_createChildControlImpl: function(id) {
166+
let control;
167+
switch (id) {
168+
case "no-resources-found":
169+
control = new qx.ui.basic.Label().set({
170+
value: this.tr("No Resources found"),
171+
visibility: "excluded",
172+
font: "text-14",
173+
});
174+
this._add(control);
175+
break;
176+
}
177+
return control || this.base(arguments, id);
178+
},
179+
180+
__getNotFoundText: function() {
147181
let text = null;
148182
switch (this.__resourceType) {
149183
case "study": {
@@ -175,26 +209,36 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
175209
case "service":
176210
text = this.tr("No Apps found");
177211
break;
178-
default:
179-
text = this.tr("No Resources found");
180-
break;
181212
}
213+
return text;
214+
},
182215

183-
this.__noResourcesFound.exclude();
216+
__evaluateNoResourcesFoundLabel: function() {
217+
const noResourcesFound = this.getChildControl("no-resources-found");
218+
noResourcesFound.exclude();
184219
if (this.__noResourcesFoundTimer) {
185220
clearTimeout(this.__noResourcesFoundTimer);
186221
}
187-
if (text && this.__resourcesList.length === 0) {
222+
223+
if (this.__resourcesList.length === 0) {
188224
// delay it a bit to avoid the initial flickering
189225
this.__noResourcesFoundTimer = setTimeout(() => {
190-
this.__noResourcesFound.set({
191-
value: text,
192-
visibility: "visible",
193-
});
226+
this.showNoResourcesFound();
194227
}, 2000);
195228
}
196229
},
197230

231+
showNoResourcesFound: function() {
232+
const text = this.__getNotFoundText();
233+
if (text) {
234+
const noResourcesFound = this.getChildControl("no-resources-found");
235+
noResourcesFound.set({
236+
value: text,
237+
});
238+
noResourcesFound.show();
239+
}
240+
},
241+
198242
addNonResourceCard: function(card) {
199243
if (osparc.dashboard.CardContainer.isValidCard(card)) {
200244
let groupContainer = null;
@@ -320,17 +364,7 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
320364
container.add(card);
321365

322366
if (this.getMode() === "list") {
323-
const fitToContainer = () => {
324-
const bounds = container.getBounds() || container.getSizeHint();
325-
card.setWidth(bounds.width);
326-
};
327-
[
328-
"appear",
329-
"resize",
330-
].forEach(ev => {
331-
container.addListener(ev, () => fitToContainer());
332-
});
333-
fitToContainer();
367+
this.self().fitToContainer(card, container);
334368
}
335369
},
336370

@@ -526,6 +560,39 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
526560
},
527561
// /FOLDERS
528562

563+
// FILES
564+
setFilesToList: function(filesList) {
565+
this.__filesList = filesList;
566+
},
567+
568+
reloadFiles: function() {
569+
if (this.__filesContainer) {
570+
this.__filesContainer.removeAll();
571+
this.__filesContainer.exclude();
572+
}
573+
let fileCards = [];
574+
this.__filesList.forEach(fileData => fileCards.push(this.__fileToCard(fileData)));
575+
return fileCards;
576+
},
577+
578+
__fileToCard: function(fileData) {
579+
const card = this.__createFileCard(fileData);
580+
this.__filesContainer.add(card);
581+
this.__filesContainer.show();
582+
this.self().fitToContainer(card, this.__filesContainer);
583+
return card;
584+
},
585+
586+
__createFileCard: function(fileData) {
587+
const file = new osparc.data.model.File(fileData);
588+
const card = new osparc.dashboard.FileButtonItem(file);
589+
[
590+
"openLocation",
591+
].forEach(eName => card.addListener(eName, e => this.fireDataEvent(eName, e.getData())));
592+
return card;
593+
},
594+
// /FILES
595+
529596
__moveNoGroupToLast: function() {
530597
const idx = this.__groupedContainers.getChildren().findIndex(grpContainer => grpContainer === this.__getGroupContainer("no-group"));
531598
if (idx > -1) {

0 commit comments

Comments
 (0)