From 40fb57a3ff548de1971fe2abc8bb83618882da6b Mon Sep 17 00:00:00 2001 From: XingY Date: Mon, 23 Mar 2026 20:02:09 -0700 Subject: [PATCH 1/9] GitHub Issue 955: limit text choice option length to 200 characters --- packages/components/releaseNotes/components.md | 4 ++++ .../TextChoiceAddValuesModal.test.tsx | 10 ++++++++++ .../TextChoiceAddValuesModal.tsx | 18 ++++++++++++++---- .../components/domainproperties/constants.ts | 1 + 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index 1b1ead72b6..643ea89633 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,6 +1,10 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages +### version 7.X +*Released*: X March 2026 +- GitHub Issue 955: limit text choice option length to 200 characters + ### version 7.23.5 *Released*: 18 March 2026 - Bump @labkye/api dependency diff --git a/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.test.tsx b/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.test.tsx index 93f43c3382..9277c665a6 100644 --- a/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.test.tsx +++ b/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.test.tsx @@ -79,6 +79,16 @@ describe('TextChoiceAddValuesModal', () => { validateCounterText('2 values', '3 new values'); }); + test('value exceeding max length disables apply and shows error', async () => { + render(); + const longValue = 'a'.repeat(201); + await userEvent.type(document.querySelector('textarea'), longValue); + expect(document.querySelector('.btn-success').hasAttribute('disabled')).toBeTruthy(); + const errorEls = document.querySelectorAll('.domain-text-choices-error'); + expect(errorEls).toHaveLength(1); + expect(errorEls[0].textContent).toContain('Value exceeds maximum of 200 characters'); + }); + test('initial already equal to max', async () => { render(); expect(document.querySelector('.btn-success').hasAttribute('disabled')).toBeTruthy(); diff --git a/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.tsx b/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.tsx index 3e6758d806..59d6d50e28 100644 --- a/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.tsx +++ b/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.tsx @@ -4,7 +4,7 @@ import { Utils } from '@labkey/api'; import { Modal } from '../../Modal'; -import { MAX_VALID_TEXT_CHOICES } from './constants'; +import { MAX_TEXT_CHOICE_VALUE_LENGTH, MAX_VALID_TEXT_CHOICES } from './constants'; import { getValidValuesFromArray } from './models'; interface Props { @@ -22,16 +22,20 @@ export const TextChoiceAddValuesModal: FC = memo(props => { return valueStr?.trim().length > 0 ? getValidValuesFromArray(valueStr.split('\n').map(v => v.trim())) : []; }, [valueStr]); const maxValuesToAdd = useMemo(() => maxValueCount - initialValueCount, [initialValueCount]); + const tooLongValue = useMemo( + () => parsedValues.find(v => v.length > MAX_TEXT_CHOICE_VALUE_LENGTH), + [parsedValues] + ); const hasFieldName = useMemo(() => fieldName?.length > 0, [fieldName]); const onChange = useCallback(evt => { setValueStr(evt.target.value); }, []); const onConfirm = useCallback(() => { - if (parsedValues.length <= maxValuesToAdd) { + if (parsedValues.length <= maxValuesToAdd && !tooLongValue) { onApply(parsedValues); } - }, [parsedValues, maxValuesToAdd, onApply]); - const canConfirm = parsedValues.length > 0 && parsedValues.length <= maxValuesToAdd; + }, [parsedValues, maxValuesToAdd, tooLongValue, onApply]); + const canConfirm = parsedValues.length > 0 && parsedValues.length <= maxValuesToAdd && !tooLongValue; const title = `Add Text Choice Values${hasFieldName ? ' for ' + fieldName : ''}`; const valueNoun = Utils.pluralize(maxValuesToAdd, 'value', 'values'); return ( @@ -52,6 +56,12 @@ export const TextChoiceAddValuesModal: FC = memo(props => { > {parsedValues.length === 1 ? '1 new value provided.' : `${parsedValues.length} new values provided.`} + {tooLongValue && ( +
+ Value exceeds maximum of {MAX_TEXT_CHOICE_VALUE_LENGTH} characters: " + {tooLongValue.substring(0, 50)}..." +
+ )} ); }); diff --git a/packages/components/src/internal/components/domainproperties/constants.ts b/packages/components/src/internal/components/domainproperties/constants.ts index a3491e2a37..eaa144c869 100644 --- a/packages/components/src/internal/components/domainproperties/constants.ts +++ b/packages/components/src/internal/components/domainproperties/constants.ts @@ -233,6 +233,7 @@ export const DERIVATION_DATA_SCOPES = { }; export const MAX_VALID_TEXT_CHOICES = 500; +export const MAX_TEXT_CHOICE_VALUE_LENGTH = 200; // GitHub Issue 955: limit option length to 200 export const LOOKUP_VALIDATOR_VALUES = { type: 'Lookup', name: 'Lookup Validator' }; From 1af32dc2055f4aa05f6fa5304360f97ebc8b0f1f Mon Sep 17 00:00:00 2001 From: XingY Date: Mon, 23 Mar 2026 20:17:52 -0700 Subject: [PATCH 2/9] GitHub Issue 947, 955 & 988 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- .../domainproperties/TextChoiceAddValuesModal.tsx | 11 ++++------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index feddea4fbe..0ae78bb1fa 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "7.23.5", + "version": "7.23.6-fb-mvtcOptions.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "7.23.5", + "version": "7.23.6-fb-mvtcOptions.1", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index d0a7b75078..f5d81c6864 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "7.23.5", + "version": "7.23.6-fb-mvtcOptions.1", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ diff --git a/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.tsx b/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.tsx index 59d6d50e28..58d4d7f06a 100644 --- a/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.tsx +++ b/packages/components/src/internal/components/domainproperties/TextChoiceAddValuesModal.tsx @@ -22,10 +22,7 @@ export const TextChoiceAddValuesModal: FC = memo(props => { return valueStr?.trim().length > 0 ? getValidValuesFromArray(valueStr.split('\n').map(v => v.trim())) : []; }, [valueStr]); const maxValuesToAdd = useMemo(() => maxValueCount - initialValueCount, [initialValueCount]); - const tooLongValue = useMemo( - () => parsedValues.find(v => v.length > MAX_TEXT_CHOICE_VALUE_LENGTH), - [parsedValues] - ); + const tooLongValue = useMemo(() => parsedValues.find(v => v.length > MAX_TEXT_CHOICE_VALUE_LENGTH), [parsedValues]); const hasFieldName = useMemo(() => fieldName?.length > 0, [fieldName]); const onChange = useCallback(evt => { setValueStr(evt.target.value); @@ -42,11 +39,11 @@ export const TextChoiceAddValuesModal: FC = memo(props => {

Enter each value on a new line. {valueNoun} can be added.