Skip to content

(fix) O3-4320: Remove Irrelevant Properties When Changing Question Type #391

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

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

Bharath-K-Shetty
Copy link
Contributor

@Bharath-K-Shetty Bharath-K-Shetty commented Feb 10, 2025

Requirements

  • This PR has a title that briefly describes the work done including the ticket number. If there is a ticket, make sure your PR title includes a conventional commit label. See existing PR titles for inspiration.
  • My work conforms to the OpenMRS 3.0 Styleguide and design documentation.
  • My work includes tests or is validated by existing tests.

Summary

This PR implements functionality to clean up form field data when a user changes a question's type in the form builder. A mapping of allowed properties for each question type is defined, and a helper function (cleanFormFieldForType) ensures that only the properties relevant to the newly selected question type are retained. The solution also cleans the nested questionOptions object based on a separate mapping, ensuring required keys like "rendering" remain intact.

Screenshots

Screen.Recording.2025-02-10.183846.mp4

Related Issue

https://openmrs.atlassian.net/browse/O3-4320

Other

@Bharath-K-Shetty
Copy link
Contributor Author

@NethmiRodrigo review required..!

@NethmiRodrigo NethmiRodrigo self-requested a review February 11, 2025 11:57
Copy link
Collaborator

@NethmiRodrigo NethmiRodrigo left a comment

Choose a reason for hiding this comment

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

Thanks @Bharath-K-Shetty! A couple of suggestions:

@Bharath-K-Shetty
Copy link
Contributor Author

@NethmiRodrigo updated the pr..!

Copy link
Collaborator

@NethmiRodrigo NethmiRodrigo left a comment

Choose a reason for hiding this comment

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

@Bharath-K-Shetty left a few comments. Please add unit tests to cover this scenario

Copy link
Collaborator

@NethmiRodrigo NethmiRodrigo left a comment

Choose a reason for hiding this comment

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

@Bharath-K-Shetty looks like this isn't as simple as what I had initially thought. While this is halfway there, we have to consider the propeties specific for renderingTypes as well (as per https://openmrs.atlassian.net/wiki/spaces/docs/pages/68681754/Field+Types+Reference), which means there needs to be a bit more rework that needs to be done on this PR. You can do it and I can guide you through it, but if its a hassle, I can do it. What do you prefer?

@Bharath-K-Shetty
Copy link
Contributor Author

Bharath-K-Shetty commented Mar 11, 2025

Hey @NethmiRodrigo i think for cleanup of rendering Type there is a separate ticket focusing on that can you please clarify once.Ticket:https://openmrs.atlassian.net/browse/O3-4319

@NethmiRodrigo
Copy link
Collaborator

Hey @NethmiRodrigo i think for cleanup of rendering Type there is a separate ticket focusing on that can you please clarify once.Ticket:https://openmrs.atlassian.net/browse/O3-4319

Yeah, I thought we could handle it separately, but now seeing it in action, I don't think we can do them seperately

Copy link
Collaborator

@NethmiRodrigo NethmiRodrigo left a comment

Choose a reason for hiding this comment

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

@Bharath-K-Shetty you'd have to reconsider the properties you added for questionType since some of them are for renderingType

encounterLocation: [],
encounterProvider: [],
encounterRole: [],
obs: ['required'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

'required` is a common property

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please see this comment again

src/constants.ts Outdated
Mapping of allowed keys for the nested questionOptions object per question type.
*/
export const allowedQuestionOptionsMapping: Record<string, string[]> = {
control: ['rendering', 'minLength', 'maxLength'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

'minLength', 'maxLength' are properties relevant to text rendering type and not specific to the control question type

src/constants.ts Outdated
encounterDatetime: ['rendering'],
encounterLocation: ['rendering'],
encounterProvider: ['rendering'],
encounterRole: ['rendering', 'isSearchable'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Similarly, isSearchable is for ui-select-extended rendering type

@NethmiRodrigo
Copy link
Collaborator

@Bharath-K-Shetty So what I do to find the correct properties is, I go through the FormField type definition - https://github.com/openmrs/openmrs-esm-form-engine-lib/blob/d28f37f92cff6c6e97b3339113d921e880400855/src/types/schema.ts#L60 because most often than not they are pretty self explanatory. Similarly, - https://openmrs.atlassian.net/wiki/spaces/docs/pages/68681754/Field+Types+Reference for renderingType. Most of what you have put for questionType you'd see is actually what should be under renderingType

Copy link
Collaborator

@NethmiRodrigo NethmiRodrigo left a comment

Choose a reason for hiding this comment

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

@Bharath-K-Shetty I've left a few comments, but the more I think about this, the more this approach seems to be unscalable, especially because I was thinking of all the possible combinations of questionType to renderingType we'd have to consider. Seems like the best way forward is to rework this to:

  1. When changing the question type or rendering type, we just remove all the properties except id, label and required
  2. Show a info tooltip next to the question type and rendering type that on hover would show a warning that changing the type would remove properties.
    Over time, we'll probably evolve this into a better solution, but I think this proposed approach would be a much better and less complex task (and easier to test).
    Sorry about the iterative changes, this is a ticket that I hadn't thought about in such depth until now

Copy link
Collaborator

Choose a reason for hiding this comment

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

Since these test cases are explicitly for testing the functions within the question-utils file and doesn't test anything within the question.component itself, it would be better to add these to a question-utils.test file. A test case that you could write for the question.component would be something like loading a formField like:

const formField: FormField = {
      id: 'testQuestion',
      label: 'Test Question',
      type: 'obs',
      questionOptions: {
        rendering: 'radio',
        concept: '12345',
        answers: [
          { concept: '111', label: 'Yes' },
          { concept: '222', label: 'No' },
        ],
      },
      required: true,
    };

and then rendering the question component, and then clicking on the Select Type and changing the type and then checking if setFormField gets called with the unnecessary properties removed

// Assert that id remains.
expect(cleaned.id).toBe('testQuestion');

// In our design, label is required for all question types, so it should remain.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually, the label property is not required for questions that have the renderingType markdown

Suggested change
// In our design, label is required for all question types, so it should remain.

Comment on lines +35 to +40
expect(cleaned.label).toBe('Test Question');

// Irrelevant nested properties should be removed.
expect(cleaned.questionOptions).toHaveProperty('rendering', 'markdown');
expect(cleaned.questionOptions).not.toHaveProperty('concept');
expect(cleaned.questionOptions).not.toHaveProperty('answers');
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of asserting property by property, can't we have a result object and assert that the cleaned object is equal to that, i.e:

const expectedObjectAfterClean = {
      id: 'testQuestion',
      type: 'control',
      questionOptions: {
        rendering: 'markdown',
        concept: '12345',
      },
      required: true,
}
expect(cleaned).toEqual(expectedObjectAfterClean);

encounterLocation: [],
encounterProvider: [],
encounterRole: [],
obs: ['required'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please see this comment again

toggle: ['rendering', 'concept', 'toggleOptions'],
'ui-select-extended': ['rendering', 'concept', 'isSearchable'],
'workspace-launcher': ['rendering', 'concept'],
markdown: ['rendering', 'concept'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
markdown: ['rendering', 'concept'],
markdown: ['rendering'],

'ui-select-extended': ['rendering', 'concept', 'isSearchable'],
'workspace-launcher': ['rendering', 'concept'],
markdown: ['rendering', 'concept'],
'extension-widget': ['rendering', 'concept'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

The following are types relevant to this:

 extensionId?: string;
 extensionSlotName?: string;

'fixed-value': ['rendering', 'concept'],
file: ['rendering', 'concept'],
group: ['rendering', 'concept'],
number: ['rendering', 'concept', 'min', 'max'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also relevant type: step?: number;

number: ['rendering', 'concept', 'min', 'max'],
problem: ['rendering', 'concept'],
radio: ['rendering', 'concept', 'answers'],
repeating: ['rendering', 'concept'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Relevant to this: repeatOptions?: RepeatOptions;

'encounter-provider': ['rendering', 'concept'],
'encounter-role': ['rendering', 'concept', 'isSearchable'],
'fixed-value': ['rendering', 'concept'],
file: ['rendering', 'concept'],
Copy link
Collaborator

Choose a reason for hiding this comment

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

allowedFileTypes?: Array<string>;

obsGroup: ['questions'],
patientIdentifier: [],
testOrder: [],
programState: [],
Copy link
Collaborator

Choose a reason for hiding this comment

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

 programUuid?: string;
 workflowUuid?: string;

@NethmiRodrigo NethmiRodrigo changed the title (fix)O3-4320: Remove Irrelevant Properties When Changing Question Type (fix) O3-4320: Remove Irrelevant Properties When Changing Question Type Mar 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants