Skip to content
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

Add "default" initialize property to QCBX #6037

Draft
wants to merge 9 commits into
base: production
Choose a base branch
from
Draft

Conversation

alesan99
Copy link
Contributor

@alesan99 alesan99 commented Jan 3, 2025

Fixes #3994

Adds ability for a QCBX to have a user-defined default selected record.

The following property on a QCBX can be set to a specify api uri:
initialize='default=/api/specify/agent/1/'
It can also be set to
CURRENT_AGENT
CURRENT_USER
BLANK (Can be used to override hardcoded defaults, like with cataloger)

Notes:

  • I chose to use resource URIs rather than record IDs to avoid confusion about ids and to simplify the code. At a glance I think its more clear, but it is a bit unnecessarily detailed. I don't anticipate this functionality being used often, so I think its okay to prioritize clarity over ease of typing. I can switch back to record IDs if those seem better though.
  • The Query Builder currently uses a similar keyword "currentSpecifyUserName" under the hood, but I chose to go with the sp6 convention of all caps.

Checklist

  • Self-review the PR after opening it to make sure the changes look good and
    self-explanatory (or properly documented)
  • Add automated tests
  • Add relevant issue to release milestone

Testing instructions

  • Edit any form definition that currently contains a QCBX.
  • Add default=/api/specify/TABLE/ID/ to the QCBX 'initialize' property. (Replace TABLE and ID)
  • Load the form or view it in the visual form editor
  • If you set it to a URI, make sure it resolves to the record with the ID you entered
  • If you set it to CURRENT_AGENT, make sure it resolves to the agent belonging to the current logged-in user.
  • If you set it to CURRENT_USER, make sure it resolves to the current logged-in user.
  • Edit the cataloger QCBX in the CollectionObject form.
  • Make sure it fills in automatically like normal before you make any changes
  • If you set it to BLANK, make sure it no longer fills in the current agent.

@alesan99 alesan99 marked this pull request as ready for review January 6, 2025 18:58
@melton-jason melton-jason self-requested a review January 6, 2025 20:03
Copy link
Contributor

@melton-jason melton-jason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! 🥳

My comments are primarily about code style, improving the code that was already there, and ways you could maybe make this even better for both dev and user if you wanted to.
Nothing strikes me as too pressing, and certainly not required (though still worth consideration hopefully).

Are you planning on adding automated tests to this PR, or will that be later? 👀

I'm a fan of the defaults, and I love the potential of the feature.

I find it a little unfortunate that we have to expose the concept of IDs to the user here: that will certainly require some documentation on the feature and won't be initially intuitive. Hopefully this is a feature that'll save users lots of time and configured infrequently!

@specify/ux-testing
Does this solve the most commonly reported use case for #3994?
Do most users have just a single record they want to set as default for a field?

@@ -61,6 +61,7 @@ export type FieldTypes = {
readonly hasViewButton: boolean;
readonly typeSearch: string | undefined;
readonly searchView: string | undefined;
readonly defaultRecordId: string | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(optional)

If it's possible, can you include the respected default values (CURRENT_USER, CURRENT_AGENT, and BLANK) into this type?

That way, the default values will be present when using Intellisense with this property.
And arguably even more helpful, if the feature needs to be expanded/worked-on in the future, including the defaults in the type definition provides another clear pathway to investigate the feature, an alternative to searching the Code/GitHub/Speciforum for the property name alone.

@@ -246,6 +247,7 @@ const processFieldType: {
: getProperty('viewBtn')?.toLowerCase() === 'true',
typeSearch: getProperty('name'),
searchView: getProperty('searchView'),
defaultRecordId: getProperty('defaultRecordId'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(just a note)

If desired, you can do whatever additional parsing here that you need!

For example, you can check if the value here is one of the defaults and if not, then try and parse it as an integer and otherwise return undefined.

That way, when working with defaultRecordId later down the line, you already know if it's supposed to be converted to a resource_uri, is one of the defaults, etc.

If you do change how the defaultRecordId is parsed, don't forget to modify the type definition accordingly and other places it's used (like the syncer).

@@ -862,6 +862,7 @@ const queryComboBoxSpec = (
syncers.maybe(syncers.toBoolean),
syncers.default<boolean>(true)
),
defaultRecordId: syncers.xmlAttribute('initialize defaultRecordId', 'skip'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(also a note, building on the above comment)

Whatever parsing behavior you implement in the form parsing code should also be reflected here in the Syncer as well (the Syncer is in charge of converting xml to json and vice-versa; for ease of use for visual editor).

One benefit of working with the Syncer is that it's also in charge of emitting errors to the user while they are using the CodeMirror text editor.

For example the following error when trying to render a to-many relationship with a QueryComboBox:

Screen.Recording.2025-01-07.at.3.20.14.AM.mov

Is caused because of the following console.error statement on the QueryComboBox syncer!:

field: pipe(
rawFieldSpec(table).field,
syncer(
({ parsed, ...rest }) => {
if (
parsed?.some(
(field) => field.isRelationship && relationshipIsToMany(field)
)
)
console.error(
'Unable to render a to-many relationship as a querycbx. Use a Subview instead'
);
return { parsed, ...rest };
},
(value) => value
)
),

Maybe you want to check the value: is one of the defaults, the default is being used correctly1, a valid number and a record exists with the ID, etc.

Footnotes

  1. We know CURRENT_AGENT and CURRENT_USER should only be used for relationships to Agent and Specifyuser (respectively): currently a user can technically use the defaults in any QueryComboBox

@alesan99
Copy link
Contributor Author

alesan99 commented Jan 7, 2025

Thanks for the in-depth review Jason!
I know you approved it but I do want to get to everything you mentioned first so I can get a hang of the code style.

Are you planning on adding automated tests to this PR, or will that be later? 👀

I definitely want to give that a shot when I am back in the office.
I see I can add on to one of the existing tests for parsing QCBX properties, but I want to see if its possible for me to test the functionality in some way as well.

I find it a little unfortunate that we have to expose the concept of IDs to the user here: that will certainly require some documentation on the feature and won't be initially intuitive. Hopefully this is a feature that'll save users lots of time and configured infrequently!

Another idea @maxpatiiuk had in #3994 (comment) was to possibly use the record API url directly, and that would draw focus away from the ID itself.
I would like that solution for the sake of clarity. But I would like more thoughts if there is something better.

@alesan99 alesan99 marked this pull request as draft January 7, 2025 14:43
@alesan99 alesan99 changed the title Add default Record ID property to QCBX Add "default" initialize property to QCBX Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 📋Back Log
Development

Successfully merging this pull request may close these issues.

Add ability to set any agent query combo box to the current user's agent
2 participants