Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions src/components/renderer/LookupButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import MaterialIcon from '../MaterialIcon'

type Props = {
value: unknown | undefined
readOnly: boolean
validationMessage: string | undefined
hasMarginTop?: boolean
isInputButton?: boolean
Expand All @@ -17,15 +16,20 @@ type Props = {

function LookupButton({
value,
readOnly,
validationMessage,
hasMarginTop,
isInputButton,
lookupButtonConfig,
overrideRequiredMessage,
}: Props) {
const { isLookup, onLookup, isDisabled, isLoading, allowLookupOnEmptyValue } =
useLookupNotification(value)
const {
isLookup,
onLookup,
isLookupRequestInFlight,
isLoading,
allowLookupOnEmptyValue,
areLookupsDisallowed,
} = useLookupNotification(value)
if (!isLookup) {
return null
}
Expand All @@ -46,10 +50,11 @@ function LookupButton({
)}
onClick={() => onLookup()}
disabled={
// Element-level readOnly only disables the button. Auto-lookups still
// run from LookupNotification when the field is locked but has a value.
readOnly ||
isDisabled ||
// Deliberately not the element's own `readOnly` flag: a locked field
// populated by a previous lookup still needs its button to run the
// next lookup in the chain.
areLookupsDisallowed ||
isLookupRequestInFlight ||
isLoading ||
(isEmptyValue && !allowLookupOnEmptyValue) ||
(!isEmptyValue &&
Expand Down
43 changes: 26 additions & 17 deletions src/components/renderer/LookupNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ function LookupNotificationComponent({
const [hasLookupFailed, setHasLookupFailed] = React.useState(false)
const [hasLookupSucceeded, setHasLookupSucceeded] = React.useState(false)
const [isCancellable, setIsCancellable] = React.useState(false)
const [isDisabled, setIsDisabled] = React.useState(false)
const [isLookupRequestInFlight, setIsLookupRequestInFlight] =
React.useState(false)
const [lookupErrorHTML, setLookupErrorHTML] = React.useState<string | null>(
null,
)
Expand Down Expand Up @@ -174,6 +175,15 @@ function LookupNotificationComponent({
[element, injectPagesAfter, onLookup],
)

// Definition-level `readOnly` must not suppress lookups for a submitter:
// prefills and defaults still need to populate related fields, and a locked
// field can still be the input to a chained lookup. Approver locks are
// different. Re-running a lookup from an existing submitted value could
// overwrite persisted answers merely by opening the review, so only approver
// editable elements may run one.
const areLookupsDisallowed =
formIsReadOnly || isElementReadOnlyForAudience(element, audience)

const isNotStaticLookup = React.useMemo(() => {
return (
(formElementDataLookup && formElementDataLookup.type !== 'STATIC_DATA') ||
Expand All @@ -186,15 +196,7 @@ function LookupNotificationComponent({
LookupNotificationContextValue['onLookup']
>(
async ({ newValue, abortController, continueLookupOnAbort }) => {
// Definition-level `readOnly` must not suppress auto-lookups for a
// submitter: prefills and defaults still need to populate related
// fields. Approver locks are different. Re-running a lookup from an
// existing submitted value could overwrite persisted answers merely by
// opening the review, so only approver-editable elements may run one.
if (
formIsReadOnly ||
isElementReadOnlyForAudience(element, audience)
) {
if (areLookupsDisallowed) {
return
}

Expand All @@ -205,7 +207,7 @@ function LookupNotificationComponent({
return
}

setIsDisabled(true)
setIsLookupRequestInFlight(true)
setIsCancellable(false)
setHasLookupFailed(false)
setHasLookupSucceeded(false)
Expand Down Expand Up @@ -290,19 +292,18 @@ function LookupNotificationComponent({
} finally {
clearTimeout(isCancellableTimeout)
if (isMounted.current) {
setIsDisabled(false)
setIsLookupRequestInFlight(false)
setOnCancelLookup(undefined)
}
}
},
[
audience,
definition,
element,
excludeDefinition,
formElementDataLookup,
formElementElementLookup,
formIsReadOnly,
areLookupsDisallowed,
isMounted,
isNotStaticLookup,
isOffline,
Expand Down Expand Up @@ -367,13 +368,21 @@ function LookupNotificationComponent({
const contextValue = React.useMemo(
() => ({
isLookup: true,
isDisabled,
isLookupRequestInFlight,
isLoading,
onLookup: triggerLookup,
allowLookupOnEmptyValue: runLookupOnClear,
isLookingUp,
areLookupsDisallowed,
}),
[isDisabled, isLoading, runLookupOnClear, triggerLookup, isLookingUp],
[
isLookupRequestInFlight,
isLoading,
runLookupOnClear,
triggerLookup,
isLookingUp,
areLookupsDisallowed,
],
)

return (
Expand Down Expand Up @@ -444,7 +453,7 @@ function LookupNotificationComponent({
'fade-in button is-primary ob-lookup__retry-button cypress-retry-lookup-button has-margin-top-8',
)}
onClick={() => retryLookup()}
disabled={isDisabled || isLoading}
disabled={isLookupRequestInFlight || isLoading}
aria-label="lookup-retry-button"
>
<span></span>
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementABN.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ function FormElementABN({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementBSB.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ function FormElementBSB({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementBarcodeScanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ function FormElementBarcodeScanner({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementCheckBoxes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ function FormElementCheckboxes({
)}

<LookupButton
readOnly={readOnly}
hasMarginTop
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementDate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ function FormElementDate({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementDateTime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ function FormElementDateTime({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementEmail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ function FormElementEmail({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementLookupButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ function FormElementLookupButton({
required={false}
>
<LookupButton
readOnly={readOnly}
value={value}
validationMessage={validationMessage}
lookupButtonConfig={element.lookupButton}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementNumber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ function FormElementNumber({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ function FormElementSelect({
</select>

<LookupButton
readOnly={readOnly}
hasMarginTop
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementTelephone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ function FormElementTelephone({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ function FormElementText({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementTextarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ function FormElementTextarea({
)}
{isDisplayingLookupButton && (
<LookupButton
readOnly={readOnly}
value={value}
validationMessage={validationMessage}
lookupButtonConfig={element.lookupButton}
Expand Down
1 change: 0 additions & 1 deletion src/form-elements/FormElementTime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ function FormElementTime({
</div>
)}
<LookupButton
readOnly={readOnly}
isInputButton
value={value}
validationMessage={validationMessage}
Expand Down
15 changes: 13 additions & 2 deletions src/hooks/useLookupNotification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ import * as React from 'react'

export type LookupNotificationContextValue = {
isLookup: boolean
isDisabled: boolean
/**
* A lookup HTTP request is in flight. Used to disable lookup/retry buttons
* so a second request cannot be started until the current one finishes.
*/
isLookupRequestInFlight: boolean
isLoading: boolean
allowLookupOnEmptyValue: boolean
/**
* Lookups must not run for this element, e.g. a read-only form or a field
* an approver cannot edit. The lookup button is disabled and `onLookup` is
* a no-op.
*/
areLookupsDisallowed: boolean
onLookup: (options: {
newValue: unknown
abortController: AbortController
Expand All @@ -15,9 +25,10 @@ export type LookupNotificationContextValue = {

const defaultContext = {
isLookup: false,
isDisabled: false,
isLookupRequestInFlight: false,
isLoading: false,
allowLookupOnEmptyValue: false,
areLookupsDisallowed: false,
onLookup: async () => undefined,
isLookingUp: false,
}
Expand Down
Loading