Skip to content

Commit d6b61cd

Browse files
Merge branch 'is8159/fix-redis-client-lifecycle' of github.com:giancarloromeo/osparc-simcore into is8159/fix-redis-client-lifecycle
2 parents 18978e0 + 0160e0c commit d6b61cd

File tree

46 files changed

+911
-264
lines changed

Some content is hidden

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

46 files changed

+911
-264
lines changed
Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
from types import UnionType
2-
from typing import Any, Literal, get_args, get_origin
2+
from typing import Annotated, Any, Literal, Union, get_args, get_origin
33

44
from pydantic.fields import FieldInfo
55

6+
NoneType: type = type(None)
7+
68

79
def get_type(info: FieldInfo) -> Any:
810
field_type = info.annotation
911
if args := get_args(info.annotation):
10-
field_type = next(a for a in args if a is not type(None))
12+
field_type = next(a for a in args if a is not NoneType)
1113
return field_type
1214

1315

16+
def _unwrap_annotation(ann):
17+
"""Peel off Annotated wrappers until reaching the core type."""
18+
while get_origin(ann) is Annotated:
19+
ann = get_args(ann)[0]
20+
return ann
21+
22+
1423
def is_literal(info: FieldInfo) -> bool:
15-
return get_origin(info.annotation) is Literal
24+
ann = _unwrap_annotation(info.annotation)
25+
return get_origin(ann) is Literal
1626

1727

1828
def is_nullable(info: FieldInfo) -> bool:
19-
origin = get_origin(info.annotation) # X | None or Optional[X] will return Union
20-
if origin is UnionType:
21-
return any(x in get_args(info.annotation) for x in (type(None), Any))
22-
return False
29+
"""Checks whether a field allows None as a value."""
30+
ann = _unwrap_annotation(info.annotation)
31+
origin = get_origin(ann) # X | None or Optional[X] will return Union
32+
33+
if origin in (Union, UnionType):
34+
return any(arg is NoneType or arg is Any for arg in get_args(ann))
35+
36+
return ann is NoneType or ann is Any

packages/common-library/tests/test_pydantic_fields_extension.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from collections.abc import Callable
2-
from typing import Any, Literal
2+
from typing import Annotated, Any, Literal
33

44
import pytest
55
from common_library.pydantic_fields_extension import get_type, is_literal, is_nullable
6-
from pydantic import BaseModel
6+
from pydantic import BaseModel, PositiveInt
77

88

99
class MyModel(BaseModel):
@@ -12,6 +12,11 @@ class MyModel(BaseModel):
1212
c: str = "bla"
1313
d: bool | None = None
1414
e: Literal["bla"]
15+
f: Annotated[
16+
PositiveInt | None,
17+
"nullable inside Annotated (PositiveInt = Annotated[int, ...])",
18+
]
19+
g: Annotated[Literal["foo", "bar"], "literal inside Annotated"]
1520

1621

1722
@pytest.mark.parametrize(
@@ -50,6 +55,8 @@ class MyModel(BaseModel):
5055
),
5156
(is_literal, False, "d"),
5257
(is_literal, True, "e"),
58+
(is_literal, False, "f"),
59+
(is_literal, True, "g"),
5360
(
5461
is_nullable,
5562
False,
@@ -67,6 +74,11 @@ class MyModel(BaseModel):
6774
),
6875
(is_nullable, True, "d"),
6976
(is_nullable, False, "e"),
77+
(
78+
is_nullable,
79+
True,
80+
"f",
81+
),
7082
],
7183
)
7284
def test_field_fn(fn: Callable[[Any], Any], expected: Any, name: str):

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from ..basic_types import IDStr
2626
from ..emails import LowerCaseEmailStr
27-
from ..groups import AccessRightsDict, Group, GroupID, GroupsByTypeTuple
27+
from ..groups import AccessRightsDict, Group, GroupID, GroupsByTypeTuple, PrimaryGroupID
2828
from ..products import ProductName
2929
from ..rest_base import RequestParameters
3030
from ..users import (
@@ -381,14 +381,32 @@ class UserAccountGet(OutputSchema):
381381

382382
# user status
383383
registered: bool
384-
status: UserStatus | None
384+
status: UserStatus | None = None
385385
products: Annotated[
386386
list[ProductName] | None,
387387
Field(
388388
description="List of products this users is included or None if fields is unset",
389389
),
390390
] = None
391391

392+
# user (if an account was created)
393+
user_id: Annotated[
394+
UserID | None,
395+
Field(description="Unique identifier of the user if an account was created"),
396+
] = None
397+
user_name: Annotated[
398+
UserNameID | None,
399+
Field(description="Username of the user if an account was created"),
400+
] = None
401+
user_primary_group_id: Annotated[
402+
PrimaryGroupID | None,
403+
Field(
404+
description="Primary group ID of the user if an account was created",
405+
alias="groupId",
406+
# SEE https://github.com/ITISFoundation/osparc-simcore/pull/8358#issuecomment-3279491740
407+
),
408+
] = None
409+
392410
@field_validator("status")
393411
@classmethod
394412
def _consistency_check(cls, v, info: ValidationInfo):

packages/models-library/src/models_library/groups.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
EVERYONE_GROUP_ID: Final[int] = 1
1616

1717
GroupID: TypeAlias = PositiveInt
18+
PrimaryGroupID: TypeAlias = Annotated[GroupID, Field(gt=EVERYONE_GROUP_ID)]
19+
StandardGroupID: TypeAlias = Annotated[GroupID, Field(gt=EVERYONE_GROUP_ID)]
1820

1921
__all__: tuple[str, ...] = ("GroupType",)
2022

2123

2224
class Group(BaseModel):
23-
gid: PositiveInt
25+
gid: GroupID
2426
name: str
2527
description: str
2628
group_type: Annotated[GroupType, Field(alias="type")]

services/static-webserver/client/source/class/osparc/NewRelease.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ qx.Class.define("osparc.NewRelease", {
7373
const releaseTag = osparc.utils.Utils.getReleaseTag();
7474
const releaseLink = osparc.utils.Utils.getReleaseLink();
7575
const linkLabel = new osparc.ui.basic.LinkLabel().set({
76-
value: this.tr("What's new in ") + releaseTag,
76+
value: this.tr("What's New in ") + releaseTag,
7777
url: releaseLink,
7878
font: "link-label-14"
7979
});

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,12 @@ qx.Class.define("osparc.dashboard.Dashboard", {
5454
osparc.wrapper.JsonTreeViewer.getInstance().init();
5555
osparc.wrapper.JsonFormatter.getInstance().init();
5656
osparc.wrapper.DOMPurify.getInstance().init();
57-
osparc.wrapper.RadialMenu.getInstance().init()
58-
.then(loaded => {
59-
if (loaded) {
60-
// hack to trigger fonts loading
61-
const menu = osparc.wrapper.RadialMenu.getInstance().createMenu();
62-
menu.show();
63-
menu.hide();
64-
}
65-
});
57+
osparc.wrapper.RadialMenu.getInstance().init();
58+
6659
this.__createMainViewLayout();
60+
61+
62+
qx.event.message.Bus.getInstance().subscribe("showTab", msg => this.showTab(msg.getData()), this);
6763
},
6864

6965
properties: {
@@ -99,6 +95,13 @@ qx.Class.define("osparc.dashboard.Dashboard", {
9995
return this.__appBrowser;
10096
},
10197

98+
showTab: function(tabId) {
99+
const tabFound = this.getSelectables().find(s => s.id === tabId);
100+
if (tabFound) {
101+
this.setSelection([tabFound]);
102+
}
103+
},
104+
102105
__createMainViewLayout: function() {
103106
const permissions = osparc.data.Permissions.getInstance();
104107
const tabIconSize = 20;

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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -356,20 +356,24 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
356356
}
357357
}
358358

359-
// Show Quick Start if there are no studies in the root folder of the personal workspace
360-
const quickStartInfo = osparc.product.quickStart.Utils.getQuickStart();
361-
if (quickStartInfo) {
362-
const dontShowQuickStart = osparc.utils.Utils.localCache.getLocalStorageItem(quickStartInfo.localStorageStr);
363-
if (dontShowQuickStart === "true" || this.__dontQuickStart) {
364-
return;
365-
}
366-
const nStudies = "_meta" in resp ? resp["_meta"]["total"] : 0;
367-
if (
368-
nStudies === 0 &&
369-
this.getCurrentContext() === osparc.dashboard.StudyBrowser.CONTEXT.PROJECTS &&
370-
this.getCurrentWorkspaceId() === null &&
371-
this.getCurrentFolderId() === null
372-
) {
359+
// Check if this is the first time the user logged in
360+
const nStudies = "_meta" in resp ? resp["_meta"]["total"] : 0;
361+
if (
362+
nStudies === 0 &&
363+
this.getCurrentContext() === osparc.dashboard.StudyBrowser.CONTEXT.PROJECTS &&
364+
this.getCurrentWorkspaceId() === null &&
365+
this.getCurrentFolderId() === null
366+
) {
367+
// It is!
368+
// Open Support Center
369+
osparc.support.SupportCenter.openWindow();
370+
// and open the Introductory Quick Start if any
371+
const quickStartInfo = osparc.product.quickStart.Utils.getQuickStart();
372+
if (quickStartInfo) {
373+
const dontShowQuickStart = osparc.utils.Utils.localCache.getLocalStorageItem(quickStartInfo.localStorageStr);
374+
if (dontShowQuickStart === "true" || this.__dontQuickStart) {
375+
return;
376+
}
373377
const quickStartWindow = quickStartInfo.tutorial();
374378
quickStartWindow.center();
375379
quickStartWindow.open();

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ qx.Class.define("osparc.data.model.IframeHandler", {
116116

117117
__initIFrame: function() {
118118
const iframe = new osparc.widget.PersistentIframe();
119+
if (this.getNode().getKey().includes("s4l-ui")) {
120+
iframe.getIframe().setAppearance("iframe-no-border");
121+
}
119122
osparc.utils.Utils.setIdToWidget(iframe.getIframe(), "iframe_"+this.getNode().getNodeId());
120123
this.self().evalShowToolbar(iframe, this.getStudy());
121124
iframe.addListener("restart", () => this.restartIFrame(), this);

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

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
5858
},
5959

6060
createSectionBox: function(title) {
61-
const box = osparc.ui.window.TabbedView.createSectionBox(title).set({
61+
const box = new osparc.widget.SectionBox(title).set({
6262
alignX: "left",
6363
maxWidth: 500
6464
});
@@ -337,9 +337,7 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
337337
const privacyModel = this.__userPrivacyModel = qx.data.marshal.Json.createModel(defaultModel, true);
338338

339339
const box = this.self().createSectionBox(this.tr("Privacy"));
340-
341-
const label = osparc.ui.window.TabbedView.createHelpLabel(this.tr("Choose what others see."));
342-
box.add(label);
340+
box.addHelper(this.tr("Choose what others see."));
343341

344342
const hideUserName = new qx.ui.form.CheckBox().set({
345343
value: defaultModel.hideUserName
@@ -453,9 +451,7 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
453451

454452
__create2FASection: function() {
455453
const box = this.self().createSectionBox(this.tr("Two-Factor Authentication"));
456-
457-
const label = osparc.ui.window.TabbedView.createHelpLabel(this.tr("Set your preferred method to use for two-factor authentication when signing in:"));
458-
box.add(label);
454+
box.addHelper(this.tr("Set your preferred method to use for two-factor authentication when signing in:"));
459455

460456
const form = new qx.ui.form.Form();
461457

@@ -659,9 +655,7 @@ qx.Class.define("osparc.desktop.account.ProfilePage", {
659655
__createDeleteAccount: function() {
660656
// layout
661657
const box = this.self().createSectionBox(this.tr("Delete Account"));
662-
663-
const label = osparc.ui.window.TabbedView.createHelpLabel(this.tr("Request the deletion of your account."));
664-
box.add(label);
658+
box.addHelper(this.tr("Request the deletion of your account."));
665659

666660
const deleteBtn = new qx.ui.form.Button(this.tr("Delete Account")).set({
667661
appearance: "danger-button",

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ qx.Class.define("osparc.desktop.credits.BuyCreditsStepper", {
6868
const { paymentId, paymentFormUrl } = data;
6969
this.setPaymentId(paymentId)
7070
this.__iframe = new qx.ui.embed.Iframe(paymentFormUrl).set({
71-
decorator: "no-border-2"
71+
decorator: "no-border-0"
7272
});
7373
this.add(this.__iframe);
7474
this.setSelection([this.__iframe])

0 commit comments

Comments
 (0)