Skip to content

OLMIS-8177: Show required tooltip on invalid table inputs - #84

Merged
denys1204 merged 5 commits into
masterfrom
OLMIS-8177
Aug 26, 2026
Merged

denys1204 merged 5 commits into
masterfrom
OLMIS-8177

Conversation

@michaldev0

@michaldev0 michaldev0 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

React table input cells show a required-field tooltip when invalid, instead of a red mark with no tooltip.

The text comes from the shared form message, the same key and wording the AngularJS forms use for an empty required input, so it gets translated instead of sitting in the component as an English literal.

It also marks the packs/doses quantity inputs when their cell is invalid. The component keeps its inputs two levels below the cell, out of reach of the rule that marks a single input control, so an invalid quantity showed the cell icon but never outlined the input the way every other invalid table input does. That also makes the packs unit, which renders two inputs and so loses the single-control class, look like the doses unit.

Checked against the rebuilt stylesheet and then in the running app: invalid quantity controls in both units are outlined in the danger colour and valid cells are untouched. Unit suite 920 of 920 green.

@sonarqubecloud

Copy link
Copy Markdown

The tooltip carried an English literal, so it stayed English in every
locale. Read the shared form message instead, which is the same key and
the same wording the AngularJS forms use for an empty required input.
The component keeps its inputs two levels below the cell, out of reach of
the rule that marks a single input control, so an invalid quantity showed
the cell icon but never outlined the input the way every other invalid
table input does. Marking them here also makes the packs unit, which
renders two inputs and therefore loses the single-control class, look
like the doses unit.
@denys1204 denys1204 self-assigned this Aug 18, 2026
{numeric && <NumericInput value={value} onChange={onChange} onBlur={onBlur} disabled={disabled} {...props} />}
{!numeric && <Input value={value} onChange={onChange} onBlur={onBlur} disabled={disabled} {...props} />}
</div>
<WebTooltip shouldDisplayTooltip={!valid} tooltipContent={formatMessage('openlmisForm.required')}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we derive the tooltip message from the validation result instead of always showing required? validateRow is generic and could fail for other reasons as well.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Fair point, and I would like to do it, but there is a catch outside this file.

validateRow is read as a boolean in three places: here, table.jsx validatePage() (valid = validateRow(row); if (!valid) return false;) and table-by-categories.jsx. If it starts returning a message, a non-empty string is truthy, so if (!valid) never fires and all three tables stop marking invalid pages. It is also supplied from three places: order-create-tab.jsx here and two BUQ screens in referencedata-ui.

The good news is that both producers already build the list of errors and then throw it away: requisition does !validateOrderItem(row).length, BUQ does getErrors(row).length === 0. So the clean contract is "return the errors, empty means valid", which is five mechanical edits and two of them delete a wrapper.

The catch is that BUQ returns codes (VERIFIED_CONSUMPTION, FORECASTED_DEMAND, REMARK) rather than text, so showing errors[0] would put a code in their tooltip. Doing it properly needs a code to message mapping in referencedata-ui, which means a fourth PR outside this ticket.

Two things worth knowing either way. validateOrderItem's other branch ("cannot be negative") cannot be reached from the UI, because NumericInput defaults to allowNegative = false with a ^\d+$ regex, so today the tooltip never lies. And those messages are hardcoded English, so whichever way we go they need message keys, otherwise the tooltip stops being translated.

Which do you prefer: the contract change with a fourth PR in referencedata-ui, or keeping validateRow boolean here, adding an optional message prop with the shared required message as fallback, and filing the contract change as a refactor ticket?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agreed. The tooltip doesn't currently mislead, since NumericInput prevents negative values and required is the only reachable validation failure.

Let's go with Option 2: keep validateRow returning a boolean and add an optional message prop, falling back to openlmisForm.required. The broader return-errors contract can be handled in a separate refactor ticket, including updating all three consumers and introducing message keys for the error texts. We can discuss ticket itself on next daily meeting.

I'm approving this PR, but I'd appreciate it if you could add the optional message prop before merging.

The tooltip falls back to the shared required message, which is the only
validation failure the table cells can reach today, but a consumer that
knows why its row is invalid can now say so.
The sibling packs/doses component already resolves its messages that way,
and it keeps the cell working with mocks that stub only get, which is what
the new react spec for that component does. get also stays quiet when a
locale has no translation for the key, instead of logging an error per
render.
@sonarqubecloud

Copy link
Copy Markdown

@denys1204
denys1204 merged commit 02ba2f8 into master Aug 26, 2026
4 checks passed
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