fix(ui-models): stop the shared hint contradicting a filled-in field
The line under the create form names the one blocked gate worth naming, and its fallback arm reads "no models yet". An unmet Provider ID gate fell through to that arm, so a card with two models listed right above it was told it needed one. The key gate was already excluded for this reason; the route gate was assumed excluded because its field explains itself, and was not. Tightening the route rule in the previous commit is what made this easy to hit — a digit-leading id now fails the gate — but the fallthrough predates it and fires for an empty or taken id just the same.
This commit is contained in:
@@ -112,14 +112,17 @@ export function CustomProviderCard(props: CustomProviderCardProps): ReactNode {
|
||||
const ready = route.length > 0 && !routeInvalid && !routeTaken
|
||||
&& baseURL.length > 0 && models.length > 0 && modelFailure === undefined
|
||||
&& keyFailure === undefined
|
||||
// The one blocked gate worth a line under the form. The route id is omitted
|
||||
// because its own field already explains itself, and a satisfied card says
|
||||
// The one blocked gate worth a line under the form. A satisfied card says
|
||||
// nothing at all rather than printing an empty paragraph.
|
||||
const hint = failure !== undefined || ready
|
||||
// The key field prints its own failure directly beneath itself, so a card
|
||||
// blocked only by the key stays silent here rather than answering with the
|
||||
// next unmet gate — which is satisfied, and reads as a second, false fault.
|
||||
|| keyFailure !== undefined
|
||||
// Same for the route id, and it must be tested rather than assumed: the
|
||||
// fallback arm below reads "no models yet", so an unmet route gate used to
|
||||
// fall through to it and contradict the filled-in list right above.
|
||||
|| route.length === 0 || routeInvalid || routeTaken
|
||||
? undefined
|
||||
: baseURL.length === 0
|
||||
? t('customNeedsBaseUrl')
|
||||
|
||||
@@ -790,6 +790,26 @@ describe('hand-declared providers', () => {
|
||||
expect(onClose).toHaveBeenCalledWith(true)
|
||||
})
|
||||
|
||||
it('never contradicts a filled-in field with the next gate\u2019s copy', () => {
|
||||
mountCard()
|
||||
const routeField = screen.getByLabelText(en.customRoute)
|
||||
fireEvent.change(routeField, { target: { value: '2' } })
|
||||
fireEvent.change(screen.getByLabelText(en.baseUrl), { target: { value: 'https://acme.test/v1' } })
|
||||
fireEvent.click(screen.getByRole('button', { name: en.addModel }))
|
||||
fireEvent.change(screen.getByLabelText(`${en.modelId} 1`), { target: { value: 'm' } })
|
||||
|
||||
// The route field explains itself right under the input; the shared line
|
||||
// must stay silent rather than falling through to "no models yet" while
|
||||
// the list above plainly has one.
|
||||
expect(screen.getByText(en.customRouteInvalid)).toBeTruthy()
|
||||
expect(screen.queryByText(en.customNeedsModels)).toBeNull()
|
||||
|
||||
// Fixing the route hands the line back to the gate that is actually unmet.
|
||||
fireEvent.change(routeField, { target: { value: 'acme' } })
|
||||
expect(screen.queryByText(en.customNeedsModels)).toBeNull()
|
||||
expect(buttonNamed(en.create).disabled).toBe(false)
|
||||
})
|
||||
|
||||
it('refuses a route id whose derived credential reference would be illegal', () => {
|
||||
mountCard()
|
||||
const routeField = screen.getByLabelText(en.customRoute)
|
||||
|
||||
Reference in New Issue
Block a user