-
Notifications
You must be signed in to change notification settings - Fork 36
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
Allow Independent Subviews via API #5253
base: production
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing instructions
When testing Independent -to-many relationships, please test Accession -> collectionObjects
and RepositoryAgreement -> accessions
. These are pretty popular!
Unless otherwise stated in the testing instruction, a specific step (or chain of steps) should be able to be performed on any Independent Subview (-to-one, -to-many, as button, etc.)
Querying related records
- Using the QueryBuilder interface, make sure you can only select a single record when adding to a -to-one independent relationship (save the "base" record after adding the record)
- Using the QueryBuilder interface, make sure you can select multiple records when adding to a -to-many independent relationship(save the "base" record after adding the records)
Creating new related records
- For an independent subview which uses the default DataEntry view for the table (usually just the name of the table. If
viewname
is omitted in the subview cell, this view is used by default), ensure that no dialog is used when creating a new associated related record using the independent subview. - For an independent subview which uses a different view from the default DataEntry view for the table, ensure that a dialog is displayed and resource creation occurs within that dialog (once the resource is saved, it should be automatically added to the independent subview)
- For more information and examples, see the
Adding new records to an Independent Subview
section earlier in this PR
Permissions
- Ensure the buttons for Viewing, Searching/Querying, Creating, and Removing are only present if the logged in user has the correct permissions (All operations should require read permissions, and Query/Create/Remove should require update permissions on the related record table)
Version control
-
- Record the
version
and/ortimestampModified
of one or more related records before adding/editing them via an independent subview
- Record the
-
- Add the related record to an independent subview (or edit/remove the related record if already present in the independent subview) and save the "base" record
-
Ensure that the version has increased by one and that the timestampModified has been updated since the recorded value for each related record
-
- Add one or more related records to an independent subview
- Do not yet save the "base" record!
-
- In a separate tab, edit one or more of the related records and save them
-
Ensure the "base" record can still be saved
-
- Find an independent subview with one or more related records (add them if needed. "base" record saving is optional at this point)
-
- In a separate tab, edit one or more of the related records and save them
-
- Explicitly modify one or more of the related records which you saved in step 2 in the independent subview
-
Ensure an 'out-of-date' error is raised when the "base" record is saved.
Misc.
- When working with an independent -to-one relationship (such as CollectionObject -> cataloger), make sure that the 🔍 and ➕ icons are disabled for the Subviewwhen there is one related record
- When you have one or more related records blocking the deletion of a "base" record, ensure that you can remove the association(s) from the "base" record, save the "base" record, and then delete the "base" record.
- Find or create a record on the
one
side of aone-to-many
record (i.e., Accession with collectionObjects) with a lot (probably 80+) of related records and make sure a loading indicator is displayed while the Subview is loading.
All my previous issues seems to be fixed, and the testing checklist looks good for the most part 👍
When testing on kufish_5_16_24
, I ran into multiple OperationalErrors for missing table columns, but it looks like it's either an issue with migrations/db or a separate issue from this PR.
Screen.Recording.2024-10-09.at.4.35.37.PM.mov
Specify 7 Crash Report - 2024-10-09T21_35_51.458Z.txt
Also, when adding or deleting fields in related records, other fields must be updated first for the changes to be saved correctly. If no other field is updated before saving, the changes will not take effect.
Screen.Recording.2024-10-09.at.4.26.26.PM.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing instructions
When testing Independent -to-many relationships, please test Accession -> collectionObjects
and RepositoryAgreement -> accessions
. These are pretty popular!
Unless otherwise stated in the testing instruction, a specific step (or chain of steps) should be able to be performed on any Independent Subview (-to-one, -to-many, as button, etc.)
Querying related records
- Using the QueryBuilder interface, make sure you can only select a single record when adding to a -to-one independent relationship (save the "base" record after adding the record)
- Using the QueryBuilder interface, make sure you can select multiple records when adding to a -to-many independent relationship(save the "base" record after adding the records)
Creating new related records
- For an independent subview which uses the default DataEntry view for the table (usually just the name of the table. If
viewname
is omitted in the subview cell, this view is used by default), ensure that no dialog is used when creating a new associated related record using the independent subview. - For an independent subview which uses a different view from the default DataEntry view for the table, ensure that a dialog is displayed and resource creation occurs within that dialog (once the resource is saved, it should be automatically added to the independent subview)
- For more information and examples, see the
Adding new records to an Independent Subview
section earlier in this PR
Permissions
- Ensure the buttons for Viewing, Searching/Querying, Creating, and Removing are only present if the logged in user has the correct permissions (All operations should require read permissions, and Query/Create/Remove should require update permissions on the related record table)
Version control
-
- Record the
version
and/ortimestampModified
of one or more related records before adding/editing them via an independent subview
- Record the
-
- Add the related record to an independent subview (or edit/remove the related record if already present in the independent subview) and save the "base" record
- Ensure that the version has increased by one and that the timestampModified has been updated since the recorded value for each related record
-
- Add one or more related records to an independent subview
- Do not yet save the "base" record!
-
- In a separate tab, edit one or more of the related records and save them
- Ensure the "base" record can still be saved
-
- Find an independent subview with one or more related records (add them if needed. "base" record saving is optional at this point)
-
- In a separate tab, edit one or more of the related records and save them
-
- Explicitly modify one or more of the related records which you saved in step 2 in the independent subview
- Ensure an 'out-of-date' error is raised when the "base" record is saved.
Misc.
- When working with an independent -to-one relationship (such as CollectionObject -> cataloger), make sure that the 🔍 and ➕ icons are disabled for the Subviewwhen there is one related record
- When you have one or more related records blocking the deletion of a "base" record, ensure that you can remove the association(s) from the "base" record, save the "base" record, and then delete the "base" record.
- Find or create a record on the
one
side of aone-to-many
record (i.e., Accession with collectionObjects) with a lot (probably 80+) of related records and make sure a loading indicator is displayed while the Subview is loading.
Other bugs that were previously appearing that I checked were fixed (not all of them):
- QueryCBX bug from Elizabeth's first review here.
- Forms that refer to each other do not loop infinitely (same as above).
- No longer triggers 'out of date' error when saving a referred object from base object multiple times.
- Grid view loading issues fixed from my original review.
Responding to Pashia's comment: my thought is that there should be an out of date error if possible. The current behavior does have it so that the collection object's changelog does record it which is good. Either way, should be discussed before full approval. 👍
Very nice work Jason!
Triggered by fb3dc17 on branch refs/heads/issue-114-backend
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing instructions
When testing Independent -to-many relationships, please test Accession -> collectionObjects
and RepositoryAgreement -> accessions
. These are pretty popular!
Unless otherwise stated in the testing instruction, a specific step (or chain of steps) should be able to be performed on any Independent Subview (-to-one, -to-many, as button, etc.)
Querying related records
- Using the QueryBuilder interface, make sure you can only select a single record when adding to a -to-one independent relationship (save the "base" record after adding the record)
- Using the QueryBuilder interface, make sure you can select multiple records when adding to a -to-many independent relationship(save the "base" record after adding the records)
Creating new related records
- For an independent subview which uses the default DataEntry view for the table (usually just the name of the table. If
viewname
is omitted in the subview cell, this view is used by default), ensure that no dialog is used when creating a new associated related record using the independent subview. - For an independent subview which uses a different view from the default DataEntry view for the table, ensure that a dialog is displayed and resource creation occurs within that dialog (once the resource is saved, it should be automatically added to the independent subview)
- For more information and examples, see the
Adding new records to an Independent Subview
section earlier in this PR
Permissions
- Ensure the buttons for Viewing, Searching/Querying, Creating, and Removing are only present if the logged in user has the correct permissions (All operations should require read permissions, and Query/Create/Remove should require update permissions on the related record table)
Version control
-
- Record the
version
and/ortimestampModified
of one or more related records before adding/editing them via an independent subview
- Record the
-
- Add the related record to an independent subview (or edit/remove the related record if already present in the independent subview) and save the "base" record
- Ensure that the version has increased by one and that the timestampModified has been updated since the recorded value for each related record
-
- Add one or more related records to an independent subview
- Do not yet save the "base" record!
-
- In a separate tab, edit one or more of the related records and save them
- Ensure the "base" record can still be saved
-
- Find an independent subview with one or more related records (add them if needed. "base" record saving is optional at this point)
-
- In a separate tab, edit one or more of the related records and save them
-
- Explicitly modify one or more of the related records which you saved in step 2 in the independent subview
- Ensure an 'out-of-date' error is raised when the "base" record is saved.
Misc.
- When working with an independent -to-one relationship (such as CollectionObject -> cataloger), make sure that the 🔍 and ➕ icons are disabled for the Subviewwhen there is one related record
- When you have one or more related records blocking the deletion of a "base" record, ensure that you can remove the association(s) from the "base" record, save the "base" record, and then delete the "base" record.
- Find or create a record on the
one
side of aone-to-many
record (i.e., Accession with collectionObjects) with a lot (probably 80+) of related records and make sure a loading indicator is displayed while the Subview is loading.
Everything looks good except I did notice an issue similar to what Andrew brought up in his last review. This behavior is a bit hard to explain but I will do my best, also I'm sure this happens in other places but I tried it with accession agents. If you have an existing accession agent and you try to delete it the save button doesn't trigger but if you refresh and try again it does and then if you save and try to add another agent the save button doesn't trigger again.
chrome_Y8sOTTqT17.mp4
With the issue Pashia and Anya mentioned, I think the current behavior makes the most sense, I also don't think it is something users would try so I don't think it would be worth it to change. In my opinion it's the same as the second version check where you saved the related record independently and then you go back and save the base record.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great job on all those tests
and good job on changes to collection api
specifyweb/frontend/js_src/lib/components/DataModel/collectionApi.ts
Outdated
Show resolved
Hide resolved
specifyweb/frontend/js_src/lib/components/FormCells/FormTableCollection.tsx
Outdated
Show resolved
Hide resolved
Triggered by 7c45847 on branch refs/heads/issue-114-backend
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When testing Independent -to-many relationships, please test Accession -> collectionObjects
and RepositoryAgreement -> accessions
. These are pretty popular!
Unless otherwise stated in the testing instruction, a specific step (or chain of steps) should be able to be performed on any Independent Subview (-to-one, -to-many, as button, etc.)
Querying related records
- Using the QueryBuilder interface, make sure you can only select a single record when adding to a -to-one independent relationship (save the "base" record after adding the record)
- Using the QueryBuilder interface, make sure you can select multiple records when adding to a -to-many independent relationship(save the "base" record after adding the records)
Creating new related records
- For an independent subview which uses the default DataEntry view for the table (usually just the name of the table. If
viewname
is omitted in the subview cell, this view is used by default), ensure that no dialog is used when creating a new associated related record using the independent subview. - For an independent subview which uses a different view from the default DataEntry view for the table, ensure that a dialog is displayed and resource creation occurs within that dialog (once the resource is saved, it should be automatically added to the independent subview)
- For more information and examples, see the
Adding new records to an Independent Subview
section earlier in this PR
Permissions
- Ensure the buttons for Viewing, Searching/Querying, Creating, and Removing are only present if the logged in user has the correct permissions (All operations should require read permissions, and Query/Create/Remove should require update permissions on the related record table)
Version control
-
- Record the
version
and/ortimestampModified
of one or more related records before adding/editing them via an independent subview
- Record the
-
- Add the related record to an independent subview (or edit/remove the related record if already present in the independent subview) and save the "base" record
- Ensure that the version has increased by one and that the timestampModified has been updated since the recorded value for each related record
-
- Add one or more related records to an independent subview
- Do not yet save the "base" record!
-
- In a separate tab, edit one or more of the related records and save them
- Ensure the "base" record can still be saved
-
- Find an independent subview with one or more related records (add them if needed. "base" record saving is optional at this point)
-
- In a separate tab, edit one or more of the related records and save them
-
- Explicitly modify one or more of the related records which you saved in step 2 in the independent subview
- Ensure an 'out-of-date' error is raised when the "base" record is saved.
Misc.
- When working with an independent -to-one relationship (such as CollectionObject -> cataloger), make sure that the 🔍 and ➕ icons are disabled for the Subviewwhen there is one related record
- When you have one or more related records blocking the deletion of a "base" record, ensure that you can remove the association(s) from the "base" record, save the "base" record, and then delete the "base" record.
- Find or create a record on the
one
side of aone-to-many
record (i.e., Accession with collectionObjects) with a lot (probably 80+) of related records and make sure a loading indicator is displayed while the Subview is loading.
(I added 110 at once and they loading immediately)
@melton-jason excellent instructions and implementation! Lots of hard work here.
For the issue mentioned in previous reviews, I was able to recreate this for deleting Loan Agent from a saved Loan and taxon citations on a saved Taxon but found it was inconsistent and would sometimes give me the expected behavior of triggering save.
Screen.Recording.2024-10-22.at.10.15.44.AM.mov
Screen.Recording.2024-10-22.at.10.17.55.AM.mov
Triggered by c6c9d8c on branch refs/heads/issue-114-backend
Thanks for the reviews everyone!
This Issue you all have been running into should be fixed! Very briefly: when the base record is saved, it replaces the records associated with a relationship with what is now in the database. The problem was that the SubView was not being updated as well: so for dependent relationships the records you see after you save are the previous un-replaced records (and no longer 'connected' to the base record in the way it expects). So to consistently reproduce the Issue, you had to have had an existing Dependent Collection, save the base record, and then any modifications to any Dependent Collections would not trigger the save button or propagate save blockers. issue_before_fix.movThe behavior with the fix (should be same behavior in issue_after_fix.mov |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing instructions
When testing Independent -to-many relationships, please test Accession -> collectionObjects
and RepositoryAgreement -> accessions
. These are pretty popular!
Unless otherwise stated in the testing instruction, a specific step (or chain of steps) should be able to be performed on any Independent Subview (-to-one, -to-many, as button, etc.)
Querying related records
- Using the QueryBuilder interface, make sure you can only select a single record when adding to a -to-one independent relationship (save the "base" record after adding the record)
- Using the QueryBuilder interface, make sure you can select multiple records when adding to a -to-many independent relationship(save the "base" record after adding the records)
Creating new related records
- For an independent subview which uses the default DataEntry view for the table (usually just the name of the table. If
viewname
is omitted in the subview cell, this view is used by default), ensure that no dialog is used when creating a new associated related record using the independent subview. - For an independent subview which uses a different view from the default DataEntry view for the table, ensure that a dialog is displayed and resource creation occurs within that dialog (once the resource is saved, it should be automatically added to the independent subview)
- For more information and examples, see the
Adding new records to an Independent Subview
section earlier in this PR
Permissions
- Ensure the buttons for Viewing, Searching/Querying, Creating, and Removing are only present if the logged in user has the correct permissions (All operations should require read permissions, and Query/Create/Remove should require update permissions on the related record table)
Version control
-
- Record the
version
and/ortimestampModified
of one or more related records before adding/editing them via an independent subview
- Record the
-
- Add the related record to an independent subview (or edit/remove the related record if already present in the independent subview) and save the "base" record
- Ensure that the version has increased by one and that the timestampModified has been updated since the recorded value for each related record
-
- Add one or more related records to an independent subview
- Do not yet save the "base" record!
-
- In a separate tab, edit one or more of the related records and save them
- Ensure the "base" record can still be saved
-
- Find an independent subview with one or more related records (add them if needed. "base" record saving is optional at this point)
-
- In a separate tab, edit one or more of the related records and save them
-
- Explicitly modify one or more of the related records which you saved in step 2 in the independent subview
- Ensure an 'out-of-date' error is raised when the "base" record is saved.
Misc.
- When working with an independent -to-one relationship (such as CollectionObject -> cataloger), make sure that the 🔍 and ➕ icons are disabled for the Subviewwhen there is one related record
- When you have one or more related records blocking the deletion of a "base" record, ensure that you can remove the association(s) from the "base" record, save the "base" record, and then delete the "base" record.
- Find or create a record on the
one
side of aone-to-many
record (i.e., Accession with collectionObjects) with a lot (probably 80+) of related records and make sure a loading indicator is displayed while the Subview is loading.
Great job so far, Jason!!
Issues below can only be recreated with:
- an independent subview that displays another dialog when creating a record
- OR adding a record through QueryBuilder.
Creating a record through independent subviews that use the default DataEntry view do not have these issues.
Infinite loading:
- Go to an existing Accession with no relating records
- Add a collection object (through query builder OR creating a new one)
- Delete that collection object
- Infinitely loads
Screen.Recording.2024-10-23.at.2.28.10.PM.mov
AssertionError:
- Create a new Accession OR go to an existing Accession that has 1 or more relating records
- Add a collection object (through query builder OR creating a new one)
- Delete that collection object
- Save
- See error
Screen.Recording.2024-10-23.at.3.04.13.PM.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing instructions
When testing Independent -to-many relationships, please test Accession -> collectionObjects
and RepositoryAgreement -> accessions
. These are pretty popular!
Unless otherwise stated in the testing instruction, a specific step (or chain of steps) should be able to be performed on any Independent Subview (-to-one, -to-many, as button, etc.)
Querying related records
- Using the QueryBuilder interface, make sure you can only select a single record when adding to a -to-one independent relationship (save the "base" record after adding the record)
- Using the QueryBuilder interface, make sure you can select multiple records when adding to a -to-many independent relationship(save the "base" record after adding the records)
Creating new related records
- For an independent subview which uses the default DataEntry view for the table (usually just the name of the table. If
viewname
is omitted in the subview cell, this view is used by default), ensure that no dialog is used when creating a new associated related record using the independent subview. - For an independent subview which uses a different view from the default DataEntry view for the table, ensure that a dialog is displayed and resource creation occurs within that dialog (once the resource is saved, it should be automatically added to the independent subview)
- For more information and examples, see the
Adding new records to an Independent Subview
section earlier in this PR
Permissions
- Ensure the buttons for Viewing, Searching/Querying, Creating, and Removing are only present if the logged in user has the correct permissions (All operations should require read permissions, and Query/Create/Remove should require update permissions on the related record table)
Version control
-
- Record the
version
and/ortimestampModified
of one or more related records before adding/editing them via an independent subview
- Record the
-
- Add the related record to an independent subview (or edit/remove the related record if already present in the independent subview) and save the "base" record
- Ensure that the version has increased by one and that the timestampModified has been updated since the recorded value for each related record
-
- Add one or more related records to an independent subview
- Do not yet save the "base" record!
-
- In a separate tab, edit one or more of the related records and save them
- Ensure the "base" record can still be saved
-
- Find an independent subview with one or more related records (add them if needed. "base" record saving is optional at this point)
-
- In a separate tab, edit one or more of the related records and save them
-
- Explicitly modify one or more of the related records which you saved in step 2 in the independent subview
- Ensure an 'out-of-date' error is raised when the "base" record is saved.
Misc.
- When working with an independent -to-one relationship (such as CollectionObject -> cataloger), make sure that the 🔍 and ➕ icons are disabled for the Subviewwhen there is one related record
- When you have one or more related records blocking the deletion of a "base" record, ensure that you can remove the association(s) from the "base" record, save the "base" record, and then delete the "base" record.
- Find or create a record on the
one
side of aone-to-many
record (i.e., Accession with collectionObjects) with a lot (probably 80+) of related records and make sure a loading indicator is displayed while the Subview is loading.
Aside from the issues Pashia mentioned I only found one other issue. I think I reported this or something similar in an earlier review but when you add a RA to an accession, save, and then remove the RA agent and save you get an error.
Fixes #114
Alternative implementation of #3125
New Functionality
Independent Subviews
An Independent Subview can be distinguished from its dependent counterpart (for both button/non-button subviews) by a magnifying glass which is used to search existing related records, or a link icon
An independent subview in subform mode with no related records
An independent subview in subform mode with no related records
Querying to add to a -to-many independent subview
subview_to_many_add_via_query.mov
Querying to add to a -to-one independent subview
subview_to_one_add_via_query.mov
Unlike dependent records, because the records can exist without each other (hence independent), removing a related record from an independent collection only removes it from the associated relationship and does not delete the record.
💡 Unless a resource is explicitly saved/deleted in a dialog (in which case only that specific resource is modified), no changes are made to any of the related records until the "base" record is saved
Saveblockers propagate to the "base" resource
When the subview is not being rendered as a button, if there are any Saveblockers they will be propagated to the "base" record.
subview_save_blocker.mov
Adding new records to an Independent Subview
Because a
viewname
can be specified on the Form Definition, there is some special logic used when creating new related records to add to the collection.When the
viewname
of the Subview is the same view as the default DataEntry form for the table, then the new resource is directly added to the Collection.subview_base_form_add.mov
Otherwise, if the
viewname
for the independent subview is not the default DataEntry view, then a separate dialog will be used to create the new resourcesubview_different_form_add.mov
(In the above example, a CollectionObject view called
AccessionItems
is used)Version Control
To handle version control and ensure that the related records do not get out of date, in the background Specify will only care about the values of the related objects (CollectionObjects related to an Accession for example) when they are explicitly changed.
In other words, you should only experience an out-of-date error on the "base" record if you attempt to save the "base" record when a change to a related record was already made (i.e., the version has been incremented) and you have made changes to the related record from the "base" record.
In other words, the following is okay (as well as adding related records and then modifying them not in the Independent Subview and then saving the "base" record):
subview_independent_version_ctrl.mov
But the below workflow will result in an error:
subview_version_ctl_error.mov
Loading Indicator while fetching collections
subview_loading.mov
Form Editing Improvements
Previously, when trying to render a -to-many relationship as a Query Combo Box, three unintuitive errors were thrown (see #5253 (review)).
Now, a helpful error is displayed to the user:
Screen.Recording.2024-08-31.at.5.35.11.PM.1.mov
When trying to render a relationship which has no reverse as a Subview, an error is now displayed explaining the situation
Screen.Recording.2024-09-03.at.1.56.38.PM.mov
Previously, if there was a cyclical referencing of Views (e.g., both sides of the relationship are rendered CollectionObject -> accession, Accession -> collectionObjects), then this would cause an infinite loop of rendering loops (See #5253 (review)).
Now behind-the-scenes subviews keep track of which relationships have already been rendered in a specific SubView hierarchy. If a relationship (like RepositoryAgreement -> accessions) would be rendered as a SubView but it already is being rendered, then Specify will not render that relationship.
Here is an example with simplified RepositoryAgreement and Accession forms demonstrating the change:
Screen.Recording.2024-09-03.at.1.47.02.PM.mov
Finding Independent Relationships
You can use the Database Schema viewer in UserTools to find independent relationships on specific tables:
finding_independence.mov
For convenience, i've also compiled a list of every independent relationship in Specify organized by table in a json format: independent_master_list.json
You can open the file in any text editor.
(note that PaleoContext and CollectingEvent may be dependent/independent depending on the
Discipline -> IsPaleoContextEmbedded
andCollection -> IsEmbeddedCollectingEvent
respectively)Checklist
and self-explanatory (or properly documented)
Testing instructions
When testing Independent -to-many relationships, please test
Accession -> collectionObjects
andRepositoryAgreement -> accessions
. These are pretty popular!Unless otherwise stated in the testing instruction, a specific step (or chain of steps) should be able to be performed on any Independent Subview (-to-one, -to-many, as button, etc.)
Querying related records
Creating new related records
viewname
is omitted in the subview cell, this view is used by default), ensure that no dialog is used when creating a new associated related record using the independent subview.Adding new records to an Independent Subview
section earlier in this PRPermissions
Version control
version
and/ortimestampModified
of one or more related records before adding/editing them via an independent subviewMisc.
one
side of aone-to-many
record (i.e., Accession with collectionObjects) with a lot (probably 80+) of related records and make sure a loading indicator is displayed while the Subview is loading.