Skip to content

Commit a2d7efa

Browse files
authored
Merge branch 'master' into fix/orphan-study
2 parents e2370a6 + ddbf7ee commit a2d7efa

File tree

50 files changed

+1240
-541
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1240
-541
lines changed

api/specs/web-server/_storage.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
StorageAsyncJobResult,
2727
StorageAsyncJobStatus,
2828
StorageLocationPathParams,
29+
StoragePathComputeSizeParams,
2930
)
3031
from models_library.generics import Envelope
3132
from models_library.projects_nodes_io import LocationID
@@ -68,6 +69,15 @@ async def list_storage_paths(
6869
"""Lists the files/directories in WorkingDirectory"""
6970

7071

72+
@router.post(
73+
"/storage/locations/{location_id}/paths/{path}:size",
74+
response_model=Envelope[StorageAsyncJobGet],
75+
status_code=status.HTTP_202_ACCEPTED,
76+
)
77+
async def compute_path_size(_path: Annotated[StoragePathComputeSizeParams, Depends()]):
78+
"""Compute the size of a path"""
79+
80+
7181
@router.get(
7282
"/storage/locations/{location_id}/datasets",
7383
response_model=Envelope[list[DatasetMetaData]],

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
from pathlib import Path
22
from typing import Annotated, Any
33

4-
from models_library.api_schemas_storage.storage_schemas import (
5-
DEFAULT_NUMBER_OF_PATHS_PER_PAGE,
6-
MAX_NUMBER_OF_PATHS_PER_PAGE,
7-
)
84
from pydantic import BaseModel, Field
95

106
from ..api_schemas_rpc_async_jobs.async_jobs import (
@@ -14,6 +10,10 @@
1410
AsyncJobStatus,
1511
)
1612
from ..api_schemas_storage.data_export_async_jobs import DataExportTaskStartInput
13+
from ..api_schemas_storage.storage_schemas import (
14+
DEFAULT_NUMBER_OF_PATHS_PER_PAGE,
15+
MAX_NUMBER_OF_PATHS_PER_PAGE,
16+
)
1717
from ..progress_bar import ProgressReport
1818
from ..projects_nodes_io import LocationID, StorageFileID
1919
from ..rest_pagination import (
@@ -26,6 +26,10 @@ class StorageLocationPathParams(BaseModel):
2626
location_id: LocationID
2727

2828

29+
class StoragePathComputeSizeParams(StorageLocationPathParams):
30+
path: Path
31+
32+
2933
class ListPathsQueryParams(InputSchema, CursorQueryParameters):
3034
file_filter: Path | None = None
3135

packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/async_jobs/async_jobs.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ async def abort(
2323
*,
2424
rpc_namespace: RPCNamespace,
2525
job_id: AsyncJobId,
26-
job_id_data: AsyncJobNameData
26+
job_id_data: AsyncJobNameData,
2727
) -> AsyncJobAbort:
2828
result = await rabbitmq_rpc_client.request(
2929
rpc_namespace,
@@ -41,7 +41,7 @@ async def get_status(
4141
*,
4242
rpc_namespace: RPCNamespace,
4343
job_id: AsyncJobId,
44-
job_id_data: AsyncJobNameData
44+
job_id_data: AsyncJobNameData,
4545
) -> AsyncJobStatus:
4646
result = await rabbitmq_rpc_client.request(
4747
rpc_namespace,
@@ -59,7 +59,7 @@ async def get_result(
5959
*,
6060
rpc_namespace: RPCNamespace,
6161
job_id: AsyncJobId,
62-
job_id_data: AsyncJobNameData
62+
job_id_data: AsyncJobNameData,
6363
) -> AsyncJobResult:
6464
result = await rabbitmq_rpc_client.request(
6565
rpc_namespace,
@@ -77,7 +77,7 @@ async def list_jobs(
7777
*,
7878
rpc_namespace: RPCNamespace,
7979
filter_: str,
80-
job_id_data: AsyncJobNameData
80+
job_id_data: AsyncJobNameData,
8181
) -> list[AsyncJobGet]:
8282
result: list[AsyncJobGet] = await rabbitmq_rpc_client.request(
8383
rpc_namespace,
@@ -95,7 +95,7 @@ async def submit_job(
9595
rpc_namespace: RPCNamespace,
9696
method_name: str,
9797
job_id_data: AsyncJobNameData,
98-
**kwargs
98+
**kwargs,
9999
) -> AsyncJobGet:
100100
result = await rabbitmq_rpc_client.request(
101101
rpc_namespace,
@@ -104,5 +104,5 @@ async def submit_job(
104104
**kwargs,
105105
timeout_s=_DEFAULT_TIMEOUT_S,
106106
)
107-
assert isinstance(result, AsyncJobGet)
107+
assert isinstance(result, AsyncJobGet) # nosec
108108
return result

packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/storage/__init__.py

Whitespace-only changes.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from pathlib import Path
2+
3+
from models_library.api_schemas_rpc_async_jobs.async_jobs import (
4+
AsyncJobNameData,
5+
)
6+
from models_library.api_schemas_storage import STORAGE_RPC_NAMESPACE
7+
from models_library.api_schemas_webserver.storage import StorageAsyncJobGet
8+
from models_library.projects_nodes_io import LocationID
9+
from models_library.rabbitmq_basic_types import RPCMethodName
10+
from models_library.users import UserID
11+
12+
from ..._client_rpc import RabbitMQRPCClient
13+
from ..async_jobs.async_jobs import submit_job
14+
15+
16+
async def compute_path_size(
17+
client: RabbitMQRPCClient,
18+
*,
19+
user_id: UserID,
20+
product_name: str,
21+
location_id: LocationID,
22+
path: Path,
23+
) -> tuple[StorageAsyncJobGet, AsyncJobNameData]:
24+
job_id_data = AsyncJobNameData(user_id=user_id, product_name=product_name)
25+
async_job_rpc_get = await submit_job(
26+
rabbitmq_rpc_client=client,
27+
rpc_namespace=STORAGE_RPC_NAMESPACE,
28+
method_name=RPCMethodName("compute_path_size"),
29+
job_id_data=job_id_data,
30+
location_id=location_id,
31+
path=path,
32+
)
33+
return StorageAsyncJobGet.from_rpc_schema(async_job_rpc_get), job_id_data

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

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
140140
const hGrid = new qx.ui.layout.Grid().set({
141141
spacing: 6,
142142
});
143+
hGrid.setRowFlex(0, 1);
143144
hGrid.setColumnFlex(1, 1);
144145
hGrid.setColumnAlign(0, "right", "middle");
145146
hGrid.setColumnAlign(1, "left", "middle");
@@ -149,6 +150,7 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
149150
paddingBottom: 6,
150151
paddingRight: 4,
151152
maxWidth: this.self().ITEM_WIDTH,
153+
minHeight: 32 + 6,
152154
maxHeight: this.self().ITEM_HEIGHT
153155
});
154156
control.setLayout(hGrid);
@@ -283,18 +285,11 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
283285

284286
// overridden
285287
_applyThumbnail: function(value, old) {
286-
if (value.includes("@FontAwesome5Solid/")) {
288+
if (qx.util.ResourceManager.getInstance().isFontUri(value)) {
287289
value += this.self().THUMBNAIL_SIZE;
288-
const image = this.getChildControl("thumbnail").set({
290+
this.getChildControl("thumbnail").set({
289291
source: value,
290292
});
291-
292-
[
293-
"appear",
294-
"loaded"
295-
].forEach(eventName => {
296-
image.addListener(eventName, () => this.__fitThumbnailHeight(), this);
297-
});
298293
} else {
299294
let source = osparc.product.Utils.getThumbnailUrl();
300295
osparc.utils.Utils.checkImageExists(value)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ qx.Class.define("osparc.dashboard.ServiceBrowser", {
4848
// overridden
4949
initResources: function() {
5050
this._resourcesList = [];
51-
osparc.store.Services.getServicesLatest(false)
51+
osparc.store.Services.getServicesLatest()
5252
.then(services => {
5353
// Show "Contact Us" message if services.length === 0
5454
// Most probably is a product-stranger user (it can also be that the catalog is down)

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

Lines changed: 76 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -169,80 +169,83 @@ qx.Class.define("osparc.study.Utils", {
169169

170170
createStudyFromTemplate: function(templateData, loadingPage, contextProps = {}) {
171171
return new Promise((resolve, reject) => {
172-
const inaccessibleServices = osparc.store.Services.getInaccessibleServices(templateData["workbench"]);
173-
if (inaccessibleServices.length) {
174-
const msg = osparc.store.Services.getInaccessibleServicesMsg(inaccessibleServices, templateData["workbench"]);
175-
reject({
176-
message: msg
172+
osparc.store.Services.getStudyServicesMetadata(templateData)
173+
.finally(() => {
174+
const inaccessibleServices = osparc.store.Services.getInaccessibleServices(templateData["workbench"]);
175+
if (inaccessibleServices.length) {
176+
const msg = osparc.store.Services.getInaccessibleServicesMsg(inaccessibleServices, templateData["workbench"]);
177+
reject({
178+
message: msg
179+
});
180+
return;
181+
}
182+
// context props, otherwise Study will be created in the root folder of my personal workspace
183+
const minStudyData = Object.assign(osparc.data.model.Study.createMinStudyObject(), contextProps);
184+
minStudyData["name"] = templateData["name"];
185+
minStudyData["description"] = templateData["description"];
186+
minStudyData["thumbnail"] = templateData["thumbnail"];
187+
const params = {
188+
url: {
189+
templateId: templateData["uuid"]
190+
},
191+
data: minStudyData
192+
};
193+
const options = {
194+
pollTask: true
195+
};
196+
const fetchPromise = osparc.data.Resources.fetch("studies", "postNewStudyFromTemplate", params, options);
197+
const pollTasks = osparc.data.PollTasks.getInstance();
198+
const interval = 1000;
199+
pollTasks.createPollingTask(fetchPromise, interval)
200+
.then(task => {
201+
const title = qx.locale.Manager.tr("CREATING ") + osparc.product.Utils.getStudyAlias({allUpperCase: true}) + " ...";
202+
const progressSequence = new osparc.widget.ProgressSequence(title).set({
203+
minHeight: 180 // four tasks
204+
});
205+
progressSequence.addOverallProgressBar();
206+
loadingPage.clearMessages();
207+
loadingPage.addWidgetToMessages(progressSequence);
208+
task.addListener("updateReceived", e => {
209+
const updateData = e.getData();
210+
if ("task_progress" in updateData && loadingPage) {
211+
const progress = updateData["task_progress"];
212+
const message = progress["message"];
213+
const percent = progress["percent"] ? parseFloat(progress["percent"].toFixed(3)) : progress["percent"];
214+
progressSequence.setOverallProgress(percent);
215+
const existingTask = progressSequence.getTask(message);
216+
if (existingTask) {
217+
// update task
218+
osparc.widget.ProgressSequence.updateTaskProgress(existingTask, {
219+
value: percent,
220+
progressLabel: parseFloat((percent*100).toFixed(2)) + "%"
221+
});
222+
} else {
223+
// new task
224+
// all the previous steps to 100%
225+
progressSequence.getTasks().forEach(tsk => osparc.widget.ProgressSequence.updateTaskProgress(tsk, {
226+
value: 1,
227+
progressLabel: "100%"
228+
}));
229+
// and move to the next new task
230+
const subTask = progressSequence.addNewTask(message);
231+
osparc.widget.ProgressSequence.updateTaskProgress(subTask, {
232+
value: percent,
233+
progressLabel: "0%"
234+
});
235+
}
236+
}
237+
}, this);
238+
task.addListener("resultReceived", e => {
239+
const studyData = e.getData();
240+
resolve(studyData);
241+
}, this);
242+
task.addListener("pollingError", e => {
243+
const err = e.getData();
244+
reject(err);
245+
}, this);
246+
})
247+
.catch(err => reject(err));
177248
});
178-
return;
179-
}
180-
// context props, otherwise Study will be created in the root folder of my personal workspace
181-
const minStudyData = Object.assign(osparc.data.model.Study.createMinStudyObject(), contextProps);
182-
minStudyData["name"] = templateData["name"];
183-
minStudyData["description"] = templateData["description"];
184-
minStudyData["thumbnail"] = templateData["thumbnail"];
185-
const params = {
186-
url: {
187-
templateId: templateData["uuid"]
188-
},
189-
data: minStudyData
190-
};
191-
const options = {
192-
pollTask: true
193-
};
194-
const fetchPromise = osparc.data.Resources.fetch("studies", "postNewStudyFromTemplate", params, options);
195-
const pollTasks = osparc.data.PollTasks.getInstance();
196-
const interval = 1000;
197-
pollTasks.createPollingTask(fetchPromise, interval)
198-
.then(task => {
199-
const title = qx.locale.Manager.tr("CREATING ") + osparc.product.Utils.getStudyAlias({allUpperCase: true}) + " ...";
200-
const progressSequence = new osparc.widget.ProgressSequence(title).set({
201-
minHeight: 180 // four tasks
202-
});
203-
progressSequence.addOverallProgressBar();
204-
loadingPage.clearMessages();
205-
loadingPage.addWidgetToMessages(progressSequence);
206-
task.addListener("updateReceived", e => {
207-
const updateData = e.getData();
208-
if ("task_progress" in updateData && loadingPage) {
209-
const progress = updateData["task_progress"];
210-
const message = progress["message"];
211-
const percent = progress["percent"] ? parseFloat(progress["percent"].toFixed(3)) : progress["percent"];
212-
progressSequence.setOverallProgress(percent);
213-
const existingTask = progressSequence.getTask(message);
214-
if (existingTask) {
215-
// update task
216-
osparc.widget.ProgressSequence.updateTaskProgress(existingTask, {
217-
value: percent,
218-
progressLabel: parseFloat((percent*100).toFixed(2)) + "%"
219-
});
220-
} else {
221-
// new task
222-
// all the previous steps to 100%
223-
progressSequence.getTasks().forEach(tsk => osparc.widget.ProgressSequence.updateTaskProgress(tsk, {
224-
value: 1,
225-
progressLabel: "100%"
226-
}));
227-
// and move to the next new task
228-
const subTask = progressSequence.addNewTask(message);
229-
osparc.widget.ProgressSequence.updateTaskProgress(subTask, {
230-
value: percent,
231-
progressLabel: "0%"
232-
});
233-
}
234-
}
235-
}, this);
236-
task.addListener("resultReceived", e => {
237-
const studyData = e.getData();
238-
resolve(studyData);
239-
}, this);
240-
task.addListener("pollingError", e => {
241-
const err = e.getData();
242-
reject(err);
243-
}, this);
244-
})
245-
.catch(err => reject(err));
246249
});
247250
},
248251

services/static-webserver/client/source/class/osparc/workbench/ServiceCatalog.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,10 @@ qx.Class.define("osparc.workbench.ServiceCatalog", {
247247
osparc.store.Services.populateVersionsSelectBox(key, selectBox)
248248
.then(() => {
249249
osparc.utils.Utils.growSelectBox(selectBox, 200);
250-
selectBox.setSelection([latest]);
250+
const idx = selectBox.getSelectables().indexOf(latest);
251+
if (idx > -1) {
252+
selectBox.setSelection([latest]);
253+
}
251254
});
252255
}
253256
}

0 commit comments

Comments
 (0)