diff --git a/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py b/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py index 9bbb92f447c..2ecf809870a 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py @@ -40,8 +40,8 @@ class SlideshowUI(TypedDict): class AnnotationUI(BaseModel): - type: Literal["note", "rect", "text"] - color: Annotated[Color, PlainSerializer(Color.as_hex)] + type: Literal["note", "rect", "text", "conversation"] + color: Annotated[Color | None, PlainSerializer(Color.as_hex)] = None attributes: Annotated[dict, Field(description="svg attributes")] @staticmethod @@ -71,6 +71,15 @@ def _update_json_schema_extra(schema: JsonDict) -> None: "color": "#0000FF", "attributes": {"x": 415, "y": 100, "text": "Hey!"}, }, + { + "type": "conversation", + "attributes": { + "conversationId": 2, + "x": 415, + "y": 100, + "title": "My chat", + }, + }, ] }, ) @@ -169,6 +178,15 @@ def _update_json_schema_extra(schema: JsonDict) -> None: "fontSize": 12, }, }, + "cf94f068-259c-4192-89f9-b2a56d51249d": { + "type": "conversation", + "attributes": { + "conversationId": 2, + "x": 119, + "y": 223, + "title": "My chat", + }, + }, }, "current_node_id": "4b3345e5-861f-47b0-8b52-a4508449be79", "template_type": "hypertool", diff --git a/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml b/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml index 23dbe53f649..dec98e42082 100644 --- a/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml +++ b/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml @@ -8458,7 +8458,7 @@ components: - stats - limits title: Activity - AnnotationUI: + AnnotationUI-Input: properties: type: type: string @@ -8466,10 +8466,36 @@ components: - note - rect - text + - conversation + title: Type + color: + anyOf: + - type: string + format: color + - type: 'null' + title: Color + attributes: + type: object + title: Attributes + description: svg attributes + additionalProperties: false + type: object + required: + - type + - attributes + title: AnnotationUI + AnnotationUI-Output: + properties: + type: + type: string + enum: + - note + - rect + - text + - conversation title: Type color: type: string - format: color title: Color attributes: type: object @@ -8479,7 +8505,6 @@ components: type: object required: - type - - color - attributes title: AnnotationUI Announcement: diff --git a/services/web/server/src/simcore_service_webserver/projects/utils.py b/services/web/server/src/simcore_service_webserver/projects/utils.py index 93c19a823a4..70a0047c042 100644 --- a/services/web/server/src/simcore_service_webserver/projects/utils.py +++ b/services/web/server/src/simcore_service_webserver/projects/utils.py @@ -93,6 +93,12 @@ def _replace_uuids(node: str | list | dict) -> str | list | dict: project_copy["ui"].get("slideshow", {}) ) + # exclude annotations UI info for conversations done in the source project + annotations = project_copy.get("ui", {}).get("annotations", {}).copy() + for ann_id, ann in annotations.items(): + if ann["type"] == "conversation": + project_copy["ui"]["annotations"].pop(ann_id) + if clean_output_data: for node_data in project_copy.get("workbench", {}).values(): for field in _FIELDS_TO_DELETE: diff --git a/services/web/server/tests/data/fake-project-with-conversation.json b/services/web/server/tests/data/fake-project-with-conversation.json new file mode 100644 index 00000000000..5c8ddfa9e35 --- /dev/null +++ b/services/web/server/tests/data/fake-project-with-conversation.json @@ -0,0 +1,89 @@ +{ + "accessRights": {}, + "uuid": "de2578c5-431e-6257-a462-d7bf73b76c0c", + "name": "fake-project-name", + "description": "anim sint pariatur do dolore", + "prjOwner": "foo@foo.com", + "creationDate": "1865-11-30T04:00:14.000Z", + "lastChangeDate": "7364-11-30T10:04:52.000Z", + "thumbnail": "https://some_fake_project_thumbnail.com/fake", + "tags": [], + "classifiers": [], + "workbench": { + "b4b20476-e7c0-47c2-8cc4-f66ac21a13bf": { + "key": "simcore/services/frontend/file-picker", + "version": "1.0.0", + "label": "File Picker 0D", + "inputs": {}, + "inputNodes": [], + "outputs": {}, + "position": { + "x": 50, + "y": 150 + } + }, + "5739e377-17f7-4f09-a6ad-62659fb7fdec": { + "key": "simcore/services/comp/ucdavis-singlecell-cardiac-model", + "version": "1.0.0", + "label": "DBP-Clancy-Rabbit-Single-Cell solver", + "inputAccess": { + "Na": "ReadAndWrite", + "Kr": "ReadOnly", + "BCL": "ReadAndWrite", + "NBeats": "ReadOnly", + "Ligand": "Invisible", + "cAMKII": "Invisible" + }, + "inputs": { + "Na": 0, + "Kr": 0, + "BCL": 200, + "NBeats": 5, + "Ligand": 0, + "cAMKII": "WT", + "initfile": { + "nodeUuid": "b4b20476-e7c0-47c2-8cc4-f66ac21a13bf", + "output": "outFile" + } + }, + "inputNodes": [ + "b4b20476-e7c0-47c2-8cc4-f66ac21a13bf" + ], + "outputs": {}, + "position": { + "x": 300, + "y": 150 + } + }, + "351fd505-1ee3-466d-ad6c-ea2915ffd364": { + "key": "simcore/services/dynamic/raw-graphs", + "version": "2.10.4", + "label": "2D plot", + "inputs": {}, + "outputs": {}, + "position": { + "x": 1073, + "y": 307 + }, + "progress": 100 + } + }, + "ui": { + "annotations": { + "b8a7e8e2-1c2d-4f3a-9c5e-123456789abc": { + "type": "conversation", + "attributes": { + "conversationId": 2, + "x": 415, + "y": 100, + "title": "My chat" + } + } + } + }, + "quality": {}, + "dev": {}, + "workspaceId": null, + "type": "STANDARD", + "templateType": null +} diff --git a/services/web/server/tests/unit/isolated/test_projects_utils.py b/services/web/server/tests/unit/isolated/test_projects_utils.py index 0178882d760..1dffd70ad63 100644 --- a/services/web/server/tests/unit/isolated/test_projects_utils.py +++ b/services/web/server/tests/unit/isolated/test_projects_utils.py @@ -22,6 +22,7 @@ "test_data_file_name", [ "fake-project.json", + "fake-project-with-conversation.json", "fake-template-projects.hack08.notebooks.json", "fake-template-projects.isan.2dplot.json", "fake-template-projects.isan.matward.json", @@ -51,6 +52,13 @@ def test_clone_project_document( for clone_node_id in clone["workbench"]: assert clone_node_id not in node_ids + # checks no conversation have been copied + if "ui" in clone and "annotations" in clone["ui"]: + assert not any( + annotation["type"] == "conversation" + for annotation in clone["ui"]["annotations"].values() + ) + # Here we do not use anymore jsonschema.validator since ... # # "OpenAPI 3.0 does not have an explicit null type as in JSON Schema, but you can use nullable: