Skip to content

Commit 3b37e29

Browse files
authored
Merge branch 'master' into feature/more-plus-button
2 parents 947b02e + eeb6a1c commit 3b37e29

File tree

20 files changed

+609
-27
lines changed

20 files changed

+609
-27
lines changed

packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Models Front-end UI
2+
Models Front-end UI
33
"""
44

55
from typing import Annotated, Literal, NotRequired
@@ -20,6 +20,7 @@
2020

2121
from ..projects_nodes_io import NodeID, NodeIDStr
2222
from ..utils.common_validators import empty_str_to_none_pre_validator
23+
from ._base import OutputSchema
2324
from .projects_nodes_ui import MarkerUI, PositionUI
2425

2526

@@ -79,14 +80,15 @@ def _update_json_schema_extra(schema: JsonDict) -> None:
7980
)
8081

8182

82-
class StudyUI(BaseModel):
83+
class StudyUI(OutputSchema):
8384
# Model fully controlled by the UI and stored under `projects.ui`
8485
icon: HttpUrl | None = None
8586

8687
workbench: dict[NodeIDStr, WorkbenchUI] | None = None
8788
slideshow: dict[NodeIDStr, SlideshowUI] | None = None
88-
current_node_id: Annotated[NodeID | None, Field(alias="currentNodeId")] = None
89+
current_node_id: NodeID | None = None
8990
annotations: dict[NodeIDStr, AnnotationUI] | None = None
91+
template_type: Literal["hypertool"] | None = None
9092

9193
_empty_is_none = field_validator("*", mode="before")(
9294
empty_str_to_none_pre_validator
@@ -169,6 +171,7 @@ def _update_json_schema_extra(schema: JsonDict) -> None:
169171
},
170172
},
171173
"current_node_id": "4b3345e5-861f-47b0-8b52-a4508449be79",
174+
"template_type": "hypertool",
172175
},
173176
]
174177
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from datetime import datetime
2+
from typing import Annotated, TypeAlias
3+
4+
from models_library.projects import ProjectID
5+
from models_library.rpc_pagination import PageRpc
6+
from pydantic import BaseModel, ConfigDict, Field
7+
8+
9+
class ProjectRpcGet(BaseModel):
10+
"""
11+
Minimal information about a project that (for now) will fullfill
12+
the needs of the api-server. Specifically, the fields needed in
13+
project to call create_job_from_project
14+
"""
15+
16+
uuid: Annotated[
17+
ProjectID,
18+
Field(description="project unique identifier"),
19+
]
20+
name: Annotated[
21+
str,
22+
Field(description="project display name"),
23+
]
24+
description: str
25+
26+
# timestamps
27+
creation_date: datetime
28+
last_change_date: datetime
29+
30+
model_config = ConfigDict(
31+
extra="forbid",
32+
populate_by_name=True,
33+
)
34+
35+
36+
PageRpcProjectRpcGet: TypeAlias = PageRpc[
37+
# WARNING: keep this definition in models_library and not in the RPC interface
38+
# otherwise the metaclass PageRpc[*] will create *different* classes in server/client side
39+
# and will fail to serialize/deserialize these parameters when transmitted/received
40+
ProjectRpcGet
41+
]

packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/webserver/projects.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import logging
2+
from typing import cast
23

34
from models_library.api_schemas_webserver import WEBSERVER_RPC_NAMESPACE
45
from models_library.products import ProductName
56
from models_library.projects import ProjectID
67
from models_library.rabbitmq_basic_types import RPCMethodName
8+
from models_library.rest_pagination import PageOffsetInt
9+
from models_library.rpc.webserver.projects import PageRpcProjectRpcGet
10+
from models_library.rpc_pagination import (
11+
DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
12+
PageLimitInt,
13+
)
714
from models_library.users import UserID
815
from pydantic import TypeAdapter, validate_call
916
from servicelib.logging_utils import log_decorator
@@ -32,3 +39,29 @@ async def mark_project_as_job(
3239
job_parent_resource_name=job_parent_resource_name,
3340
)
3441
assert result is None
42+
43+
44+
@log_decorator(_logger, level=logging.DEBUG)
45+
@validate_call(config={"arbitrary_types_allowed": True})
46+
async def list_projects_marked_as_jobs(
47+
rpc_client: RabbitMQRPCClient,
48+
*,
49+
product_name: ProductName,
50+
user_id: UserID,
51+
# pagination
52+
offset: PageOffsetInt = 0,
53+
limit: PageLimitInt = DEFAULT_NUMBER_OF_ITEMS_PER_PAGE,
54+
# filters
55+
job_parent_resource_name_filter: str | None = None,
56+
) -> PageRpcProjectRpcGet:
57+
result = await rpc_client.request(
58+
WEBSERVER_RPC_NAMESPACE,
59+
TypeAdapter(RPCMethodName).validate_python("list_projects_marked_as_jobs"),
60+
product_name=product_name,
61+
user_id=user_id,
62+
offset=offset,
63+
limit=limit,
64+
job_parent_resource_name_filter=job_parent_resource_name_filter,
65+
)
66+
assert TypeAdapter(PageRpcProjectRpcGet).validate_python(result) # nosec
67+
return cast(PageRpcProjectRpcGet, result)

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

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ qx.Class.define("osparc.dashboard.Dashboard", {
7979
members: {
8080
__studyBrowser: null,
8181
__templateBrowser: null,
82+
__hypertoolBrowser: null,
8283
__serviceBrowser: null,
8384
__dataBrowser: null,
8485

@@ -90,6 +91,10 @@ qx.Class.define("osparc.dashboard.Dashboard", {
9091
return this.__templateBrowser;
9192
},
9293

94+
getHypertoolBrowser: function() {
95+
return this.__hypertoolBrowser;
96+
},
97+
9398
getServiceBrowser: function() {
9499
return this.__serviceBrowser;
95100
},
@@ -118,6 +123,14 @@ qx.Class.define("osparc.dashboard.Dashboard", {
118123
icon: "@FontAwesome5Solid/copy/"+tabIconSize,
119124
buildLayout: this.__createTemplateBrowser
120125
});
126+
tabs.push({
127+
id: "hypertoolsTab",
128+
buttonId: "hypertoolsTabBtn",
129+
label: this.tr("HYPERTOOLS"),
130+
icon: "@FontAwesome5Solid/copy/"+tabIconSize,
131+
initVisibility: "excluded",
132+
buildLayout: this.__createHypertoolsBrowser
133+
});
121134
}
122135
if (permissions.canDo("dashboard.services.read")) {
123136
tabs.push({
@@ -128,16 +141,17 @@ qx.Class.define("osparc.dashboard.Dashboard", {
128141
buildLayout: this.__createServiceBrowser
129142
});
130143
}
131-
if (permissions.canDo("dashboard.data.read") && osparc.product.Utils.isProduct("osparc")) {
144+
if (permissions.canDo("dashboard.data.read")) {
132145
tabs.push({
133146
id: "dataTab",
134147
buttonId: "dataTabBtn",
135148
label: this.tr("DATA"),
136149
icon: "@FontAwesome5Solid/folder/"+tabIconSize,
150+
initVisibility: osparc.product.Utils.isProduct("osparc") ? "visible" : "excluded",
137151
buildLayout: this.__createDataBrowser
138152
});
139153
}
140-
tabs.forEach(({id, buttonId, label, icon, buildLayout}) => {
154+
tabs.forEach(({id, buttonId, label, icon, initVisibility, buildLayout}) => {
141155
const tabPage = new qx.ui.tabview.Page(label, icon).set({
142156
appearance: "dashboard-page"
143157
});
@@ -146,6 +160,7 @@ qx.Class.define("osparc.dashboard.Dashboard", {
146160
tabButton.set({
147161
minWidth: 50,
148162
maxHeight: 36,
163+
visibility: initVisibility ? initVisibility : "visible",
149164
});
150165
tabButton.ttt = label;
151166
tabButton.getChildControl("label").set({
@@ -171,6 +186,10 @@ qx.Class.define("osparc.dashboard.Dashboard", {
171186
this.setSelection([tabFound]);
172187
}
173188
}, this);
189+
viewLayout.addListener("showTab", e => {
190+
const showTab = e.getData();
191+
tabButton.setVisibility(showTab ? "visible" : "excluded");
192+
})
174193
const scrollerMainView = new qx.ui.container.Scroll();
175194
scrollerMainView.add(viewLayout);
176195
tabPage.add(scrollerMainView);
@@ -188,6 +207,7 @@ qx.Class.define("osparc.dashboard.Dashboard", {
188207
[
189208
this.__studyBrowser,
190209
this.__templateBrowser,
210+
this.__hypertoolBrowser,
191211
this.__serviceBrowser,
192212
this.__dataBrowser
193213
].forEach(resourceBrowser => {
@@ -209,6 +229,12 @@ qx.Class.define("osparc.dashboard.Dashboard", {
209229
return templatesView;
210230
},
211231

232+
__createHypertoolsBrowser: function() {
233+
const templateType = osparc.data.model.StudyUI.HYPERTOOL_TYPE;
234+
const hypertoolsView = this.__hypertoolBrowser = new osparc.dashboard.TemplateBrowser(templateType);
235+
return hypertoolsView;
236+
},
237+
212238
__createServiceBrowser: function() {
213239
const servicesView = this.__serviceBrowser = new osparc.dashboard.ServiceBrowser();
214240
return servicesView;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
8888

8989
events: {
9090
"changeTab": "qx.event.type.Data",
91-
"publishTemplate": "qx.event.type.Data"
91+
"showTab": "qx.event.type.Data",
92+
"publishTemplate": "qx.event.type.Data",
9293
},
9394

9495
statics: {

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,16 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
315315
__rebuildLayout: function(resourceType) {
316316
this.__cleanAll();
317317
if (this.getGroupBy()) {
318-
const noGroupContainer = this.__createGroupContainer("no-group", "No Group", "transparent");
318+
let groupTitle = "No Group";
319+
switch (this.getGroupBy()) {
320+
case "tags":
321+
groupTitle = "Not Tagged";
322+
break;
323+
case "shared":
324+
groupTitle = "Not Shared";
325+
break;
326+
}
327+
const noGroupContainer = this.__createGroupContainer("no-group", groupTitle, "transparent");
319328
this.__groupedContainers.add(noGroupContainer);
320329
this._add(this.__groupedContainers);
321330
} else {

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
qx.Class.define("osparc.dashboard.TemplateBrowser", {
1919
extend: osparc.dashboard.ResourceBrowserBase,
2020

21-
construct: function() {
21+
construct: function(templateType = null) {
2222
this._resourceType = "template";
23+
this.__templateType = templateType;
24+
2325
this.base(arguments);
2426
},
2527

2628
members: {
29+
__templateType: null,
2730
__updateAllButton: null,
2831

2932
// overridden
@@ -99,7 +102,8 @@ qx.Class.define("osparc.dashboard.TemplateBrowser", {
99102

100103
__setResourcesToList: function(templatesList) {
101104
templatesList.forEach(template => template["resourceType"] = "template");
102-
this._resourcesList = templatesList;
105+
this._resourcesList = templatesList.filter(template => osparc.study.Utils.extractTemplateType(template) === this.__templateType);
106+
this.fireDataEvent("showTab", Boolean(this._resourcesList.length));
103107
this._reloadCards();
104108
},
105109

services/static-webserver/client/source/class/osparc/data/model/StudyUI.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ qx.Class.define("osparc.data.model.StudyUI", {
3333
slideshow: new osparc.data.model.Slideshow(studyDataUI && studyDataUI.slideshow ? studyDataUI.slideshow : this.getSlideshow()),
3434
currentNodeId: studyDataUI && studyDataUI.currentNodeId ? studyDataUI.currentNodeId : this.initCurrentNodeId(),
3535
mode: studyDataUI && studyDataUI.mode ? studyDataUI.mode : this.initMode(),
36-
annotations: {}
36+
annotations: {},
37+
templateType: studyDataUI && studyDataUI.templateType ? studyDataUI.templateType : null,
3738
});
3839

3940
if ("annotations" in studyDataUI) {
@@ -79,7 +80,18 @@ qx.Class.define("osparc.data.model.StudyUI", {
7980
check: "Object",
8081
init: {},
8182
nullable: true
82-
}
83+
},
84+
85+
templateType: {
86+
check: [null, "hypertool"],
87+
init: null,
88+
nullable: true,
89+
event: "changeTemplateType",
90+
},
91+
},
92+
93+
statics: {
94+
HYPERTOOL_TYPE: "hypertool",
8395
},
8496

8597
members: {

services/static-webserver/client/source/class/osparc/desktop/MainPage.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,17 @@ qx.Class.define("osparc.desktop.MainPage", {
227227
const text = this.tr("Started template creation and added to the background tasks");
228228
osparc.FlashMessenger.logAs(text, "INFO");
229229

230+
const studyId = data["studyData"].uuid;
231+
const studyName = data["studyData"].name;
232+
const copyData = data["copyData"];
233+
const templateAccessRights = data["accessRights"];
234+
const templateType = data["templateType"];
235+
230236
const params = {
231237
url: {
232-
"study_id": data["studyData"].uuid,
233-
"copy_data": data["copyData"]
238+
"study_id": studyId,
239+
"copy_data": copyData
234240
},
235-
data: data["studyData"]
236241
};
237242
const options = {
238243
pollTask: true
@@ -242,12 +247,27 @@ qx.Class.define("osparc.desktop.MainPage", {
242247
pollTasks.createPollingTask(fetchPromise)
243248
.then(task => {
244249
const templateBrowser = this.__dashboard.getTemplateBrowser();
250+
const hypertoolBrowser = this.__dashboard.getHypertoolBrowser();
245251
if (templateBrowser) {
246-
templateBrowser.taskToTemplateReceived(task, data["studyData"].name);
252+
templateBrowser.taskToTemplateReceived(task, studyName);
247253
}
248254
task.addListener("resultReceived", e => {
249255
const templateData = e.getData();
250-
osparc.store.Study.addCollaborators(templateData, data["accessRights"]);
256+
// these operations need to be done after template creation
257+
osparc.store.Study.addCollaborators(templateData, templateAccessRights);
258+
if (templateType) {
259+
const studyUI = osparc.utils.Utils.deepCloneObject(templateData["ui"]);
260+
studyUI["templateType"] = templateType;
261+
osparc.store.Study.patchStudyData(templateData, "ui", studyUI)
262+
.then(() => {
263+
if (templateBrowser) {
264+
templateBrowser.reloadResources();
265+
}
266+
if (hypertoolBrowser) {
267+
hypertoolBrowser.reloadResources();
268+
}
269+
});
270+
}
251271
});
252272
})
253273
.catch(errMsg => {

services/static-webserver/client/source/class/osparc/share/PublishTemplate.js renamed to services/static-webserver/client/source/class/osparc/share/ShareTemplateWith.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* - Product everyone
2323
*/
2424

25-
qx.Class.define("osparc.share.PublishTemplate", {
25+
qx.Class.define("osparc.share.ShareTemplateWith", {
2626
extend: qx.ui.core.Widget,
2727

2828
/**

0 commit comments

Comments
 (0)