diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 3d2731ffc7..4451bc391f 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "7.23.2", + "version": "7.23.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "7.23.2", + "version": "7.23.3", "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 6dc494e538..eedec7b0d9 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "7.23.2", + "version": "7.23.3", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index d25fba0549..cbe4bd1687 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,6 +1,12 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages +### version 7.23.3 +*Released*: 19 March 2026 +- GitHub Issue 942: Add error for duplicate values for MVTC fields +- GitHub Issue 961: Clicking the "Allow multiple selections" label doesn't toggle the checkbox +- GitHub Issue 932: No help text for disabled Multi-Value checkbox in designer + ### version 7.23.2 *Released*: 18 March 2026 - Merge from release26.3-SNAPSHOT to develop diff --git a/packages/components/src/internal/OverlayTrigger.tsx b/packages/components/src/internal/OverlayTrigger.tsx index e5d11057a2..39f7223827 100644 --- a/packages/components/src/internal/OverlayTrigger.tsx +++ b/packages/components/src/internal/OverlayTrigger.tsx @@ -126,6 +126,7 @@ interface Props extends PropsWithChildren { className?: string; delay?: number; id?: string; + noShow?: boolean; overlay: ReactElement; // See note in doc string below style?: CSSProperties; triggerType?: TriggerType; @@ -155,6 +156,7 @@ export const OverlayTrigger: FC = ({ overlay, triggerType = 'hover', style, + noShow, }) => { const id_ = useMemo(() => id ?? generateId(), [id]); const { onMouseEnter, onMouseLeave, onClick, portalEl, show, targetRef } = useOverlayTriggerState( @@ -167,6 +169,8 @@ export const OverlayTrigger: FC = ({ const className_ = classNames('overlay-trigger', className); const clonedContent = cloneElement(overlay, { targetRef }); + if (noShow) return children; + return (
{ const multiCheckbox = document.querySelector('input.domain-text-choice-multi') as HTMLInputElement; expect(multiCheckbox).toBeInTheDocument(); expect(multiCheckbox).toBeDisabled(); - const labelSpan = screen.getByText('Allow multiple selections'); - expect(labelSpan.getAttribute('title')).toBe('Multiple values are currently used by at least one data row.'); }); test('multi-choice checkbox not present', () => { diff --git a/packages/components/src/internal/components/domainproperties/TextChoiceOptions.tsx b/packages/components/src/internal/components/domainproperties/TextChoiceOptions.tsx index dbc05aee17..f34e1989f2 100644 --- a/packages/components/src/internal/components/domainproperties/TextChoiceOptions.tsx +++ b/packages/components/src/internal/components/domainproperties/TextChoiceOptions.tsx @@ -27,6 +27,8 @@ import { getTextChoiceInUseValues, TextChoiceInUseValues } from './actions'; import { createFormInputId } from './utils'; import { isFieldFullyLocked } from './propertiesUtil'; import { MULTI_CHOICE_TYPE, TEXT_CHOICE_TYPE } from './PropDescType'; +import { Popover } from '../../Popover'; +import { OverlayTrigger } from '../../OverlayTrigger'; const MIN_VALUES_FOR_SEARCH_COUNT = 2; const HELP_TIP_BODY =

The set of values to be used as drop-down options to restrict data entry into this field.

; @@ -100,6 +102,7 @@ export const TextChoiceOptionsImpl: FC = memo(props => { const [showAddValuesModal, setShowAddValuesModal] = useState(); const [search, setSearch] = useState(''); const fieldTypeId = createFormInputId(DOMAIN_FIELD_TYPE, domainIndex, index); + const mvPopOverId = useMemo(() => createFormInputId('mv-in-use-popover', domainIndex, index), [domainIndex, index]); const isMultiChoiceField = field.dataType.name === MULTI_CHOICE_TYPE.name; // keep a map from the updated values for the in-use field values to their original values @@ -280,25 +283,26 @@ export const TextChoiceOptionsImpl: FC = memo(props => { title={`Add Values (max ${maxValueCount})`} /> {allowMultiChoice && ( - <> - - - Allow multiple selections - - + + Multiple values are currently used by at least one data row. + + } + > + + )}
diff --git a/packages/components/src/internal/components/editable/actions.ts b/packages/components/src/internal/components/editable/actions.ts index ade88a24df..581c245866 100644 --- a/packages/components/src/internal/components/editable/actions.ts +++ b/packages/components/src/internal/components/editable/actions.ts @@ -1530,13 +1530,22 @@ async function insertPastedData( const unmatched: string[] = []; const values = []; + const foundValues = new Set(); + // GitHub Issue 942: Add error for duplicate values + const dupValues = new Set(); parsedValues.forEach(v => { const vt = v.trim(); if (!vt) return; - const vd = col.validValues?.find(d => d === vt); values.push({ display: vt, raw: vt }); + if (foundValues.has(vt)) { + dupValues.add(vt); + } else { + foundValues.add(vt); + } + + const vd = col.validValues?.find(d => d === vt); if (vd) return; unmatched.push(vt); @@ -1548,6 +1557,12 @@ async function insertPastedData( .map(u => '"' + u + '"') .join(', '); msg = { message: lookupValidationErrorMessage(valueStr, true) }; + } else if (dupValues.size > 0) { + const valueStr = Array.from(dupValues) + .slice(0, 4) + .map(u => '"' + u + '"') + .join(', '); + msg = { message: `Duplicate values not allowed: ${valueStr}.` }; } cv = List(values); } else {