Repository navigation
Copy all fields when creating an item from any existing item type #2195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -620,6 +620,16 @@ def search_items(): | |
| return jsonify({"status": "success", "items": list(cursor)}), 200 | ||
|
|
||
|
|
||
| COPYABLE_CONSTITUENT_FIELDS: tuple[str, ...] = ( | ||
| "synthesis_constituents", | ||
| "positive_electrode", | ||
| "negative_electrode", | ||
| "electrolyte", | ||
| ) | ||
| """Constituent list fields that are merged (rather than overwritten) when an item is | ||
| created as a copy of another item.""" | ||
|
|
||
|
|
||
| def _copy_sample_from_id(sample_dict: dict, copy_from_item_id: str) -> dict: | ||
| copied_doc = flask_mongo.db.items.find_one( | ||
| {"item_id": copy_from_item_id, **get_default_permissions(user_only=False)} | ||
|
|
@@ -647,47 +657,35 @@ def _copy_sample_from_id(sample_dict: dict, copy_from_item_id: str) -> dict: | |
| copied_doc.pop("blocks", None) | ||
| copied_doc.pop("file_ObjectIds", None) | ||
|
|
||
| # any provided constituents will be added to the synthesis information table in | ||
| # addition to the constituents copied from the copy_from_item_id, avoiding duplicates | ||
| if copied_doc["type"] == "samples": | ||
| requested_type = sample_dict.get("type") | ||
| if requested_type and requested_type != copied_doc["type"]: | ||
| raise BadRequest( | ||
| f"Request to copy item with id {copy_from_item_id} of type {copied_doc['type']!r} " | ||
| f"into a new item of different type {requested_type!r} is not supported." | ||
| ) | ||
|
|
||
| # any provided constituents will be added to the relevant constituent tables in | ||
| # addition to the constituents copied from the copy_from_item_id, avoiding duplicates. | ||
| # This is keyed on the fields present rather than the item type, so that custom item | ||
| # types inheriting these fields (e.g., `Sample` subclasses) are handled too. | ||
| for component in COPYABLE_CONSTITUENT_FIELDS: | ||
| if not isinstance(copied_doc.get(component), list): | ||
| continue | ||
| existing_consituent_ids = [ | ||
| constituent["item"].get("item_id", None) | ||
| for constituent in copied_doc["synthesis_constituents"] | ||
| constituent["item"].get("item_id", None) for constituent in copied_doc[component] | ||
| ] | ||
| copied_doc["synthesis_constituents"] += [ | ||
| copied_doc[component] += [ | ||
| constituent | ||
| for constituent in sample_dict.get("synthesis_constituents", []) | ||
| if constituent["item"].get("item_id") is None | ||
| for constituent in sample_dict.get(component, []) | ||
| if constituent["item"].get("item_id", None) is None | ||
| or constituent["item"].get("item_id") not in existing_consituent_ids | ||
|
Comment on lines
+677
to
681
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So here correct me if I understand it correctly, the new item will take precedence over the previous one right ? I.e. if we copy a Sample with e.g. a given quantity of H2SO4, if we say that we use another quantity of H2SO4 for the new sample, it will take the new quantity, not sum up the two ? (I think that's what I would expect, just to understand :)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really, as I understand, any constituent with a different item_id (or with no item_id, i.e. free-text) is appended. So the result is "source constituents + the extra ones picked", not a replacement. Also in the creation modal, you cannot choose the quantity, only the constituent. This PR is not changing the logic, just adding a loop over the constituent fields instead of being split by samples/cells. I agree that this might look a bit surprising in the UI. I'd say that if we want to make it replace, this should be discussed in another issue. |
||
| ] | ||
|
|
||
| original_collections = sample_dict.get("collections", []) | ||
| sample_dict = copied_doc | ||
|
|
||
| if original_collections: | ||
| sample_dict["collections"] = original_collections | ||
|
|
||
| elif copied_doc["type"] == "cells": | ||
| for component in ( | ||
| "positive_electrode", | ||
| "negative_electrode", | ||
| "electrolyte", | ||
| ): | ||
| existing_consituent_ids = [ | ||
| constituent["item"].get("item_id", None) for constituent in copied_doc[component] | ||
| ] | ||
| copied_doc[component] += [ | ||
| constituent | ||
| for constituent in sample_dict.get(component, []) | ||
| if constituent["item"].get("item_id", None) is None | ||
| or constituent["item"].get("item_id") not in existing_consituent_ids | ||
| ] | ||
|
|
||
| original_collections = sample_dict.get("collections", []) | ||
| sample_dict = copied_doc | ||
| original_collections = sample_dict.get("collections", []) | ||
| sample_dict = copied_doc | ||
|
|
||
| if original_collections: | ||
| sample_dict["collections"] = original_collections | ||
| if original_collections: | ||
| sample_dict["collections"] = original_collections | ||
|
Comment on lines
+687
to
+688
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not strictly a bug of this PR but it seems incorrect. Collections are fine (I think), but groups and creators aren't. If we do: @ml-evs Should we fix this in this PR ? I think it would be good. Actually this bug is in the samples but not in the starting materials (or equipment) on main, but the generalization here "extends" it to starting materials. One thing to note is: what should be the behavior ? I think one solution could be that if you select an item to be copied, the "(Optional) Share with groups:" (and the equivalent for creators) is automatically filled with the groups from the copied item, that you can then decide to remove, keep or extend. (something "similar" is done for the name, when you select the copied item, the name automatically changes to COPY OF , not strictly the same but related) To be noted also that this may change if/when we redesign access control (issue #2203 ) |
||
|
|
||
| return sample_dict | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.