From e291a4457ebdcefbf1b2a52fe1c7cba420da8678 Mon Sep 17 00:00:00 2001 From: Nick Kerr Date: Thu, 3 Jul 2025 09:39:36 -0700 Subject: [PATCH 1/5] Issue 53153: Disable value validation for expInput, aliquotParent columns (#1824) --- packages/components/package-lock.json | 4 +- packages/components/package.json | 2 +- .../components/releaseNotes/components.md | 4 ++ .../components/forms/BulkAddUpdateForm.tsx | 4 +- .../components/forms/QueryFormInputs.tsx | 57 ++++++++++--------- .../components/forms/QueryInfoForm.tsx | 13 ++--- .../components/forms/detail/DetailDisplay.tsx | 33 +++++------ 7 files changed, 61 insertions(+), 56 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index f53f279e7e..ffb1076379 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.53.0", + "version": "6.53.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.53.0", + "version": "6.53.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 32e7a0ef85..8127bf64b1 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.53.0", + "version": "6.53.1", "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 79f643d78a..b3400b15be 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 6.53.1 +*Released*: 3 July 2025 +- Issue 53153: Disable value validation for expInput, aliquotParent columns + ### version 6.53.0 *Released*: 1 July 2025 - Remove AssayResultsForSamplesButton, AssayResultsForSamplesMenuItem diff --git a/packages/components/src/internal/components/forms/BulkAddUpdateForm.tsx b/packages/components/src/internal/components/forms/BulkAddUpdateForm.tsx index bb19edca5e..168204848c 100644 --- a/packages/components/src/internal/components/forms/BulkAddUpdateForm.tsx +++ b/packages/components/src/internal/components/forms/BulkAddUpdateForm.tsx @@ -1,5 +1,5 @@ import React, { FC, useMemo } from 'react'; -import { List, Map } from 'immutable'; +import { List } from 'immutable'; import { Operation } from '../../../public/QueryColumn'; @@ -18,9 +18,9 @@ type BaseProps = Omit< | 'hideButtons' | 'includeCountField' | 'initiallyDisableFields' + | 'queryInfo' | 'showLabelAsterisk' | 'title' - | 'queryInfo' >; interface BulkAddUpdateFormProps extends BaseProps { diff --git a/packages/components/src/internal/components/forms/QueryFormInputs.tsx b/packages/components/src/internal/components/forms/QueryFormInputs.tsx index bd1c158a1b..bef8859b08 100644 --- a/packages/components/src/internal/components/forms/QueryFormInputs.tsx +++ b/packages/components/src/internal/components/forms/QueryFormInputs.tsx @@ -270,7 +270,6 @@ export class QueryFormInputs extends React.Component @@ -303,6 +304,7 @@ export class QueryFormInputs extends React.Component ); @@ -320,80 +321,80 @@ export class QueryFormInputs extends React.Component ); } else if (col.inputType === 'file' && renderFileInputs) { return ( ); } switch (col.jsonType) { - case 'date': - case 'time': + case 'boolean': return ( - ); - case 'boolean': + case 'date': + case 'time': return ( - ); default: return ( {internalSpacesWarningFieldKeys?.indexOf(fieldKey.toLowerCase()) > -1 && (
diff --git a/packages/components/src/internal/components/forms/QueryInfoForm.tsx b/packages/components/src/internal/components/forms/QueryInfoForm.tsx index 03af0bb615..6be87e342e 100644 --- a/packages/components/src/internal/components/forms/QueryInfoForm.tsx +++ b/packages/components/src/internal/components/forms/QueryInfoForm.tsx @@ -27,7 +27,6 @@ import { FormButtons } from '../../FormButtons'; import { EntityCreationTypeModel } from '../samples/models'; import { QueryInfo } from '../../../public/QueryInfo'; -import { formatDate, formatDateTime, formatTime } from '../../util/Date'; import { Alert } from '../base/Alert'; import { LoadingSpinner } from '../base/LoadingSpinner'; @@ -56,7 +55,7 @@ export const getUpdatedFields = ( for (const key in data) { if (data.hasOwnProperty(key)) { if (fieldsToUpdate.has(key.toLowerCase()) || (additionalFields && additionalFields?.indexOf(key) !== -1)) { - const col = queryInfo?.getColumn(key); + const col = queryInfo.getColumn(key); if (col?.jsonType === 'string' && typeof data[key] === 'string') { filteredData = filteredData.set(key, data[key]?.trim()); } else { @@ -72,8 +71,8 @@ export const getUpdatedFields = ( export interface QueryInfoFormProps extends Omit { api?: ComponentsAPIWrapper; asModal?: boolean; - canSubmitNotDirty?: boolean; cancelText?: string; + canSubmitNotDirty?: boolean; countText?: string; creationTypeOptions?: EntityCreationTypeModel[]; disabled?: boolean; @@ -347,9 +346,9 @@ export class QueryInfoForm extends PureComponent { )} @@ -434,17 +433,17 @@ export class QueryInfoForm extends PureComponent { {!showErrorsAtBottom && this.renderError()} {(header || showQuantityHeader) &&
} diff --git a/packages/components/src/internal/components/forms/detail/DetailDisplay.tsx b/packages/components/src/internal/components/forms/detail/DetailDisplay.tsx index bb397b9c57..d8039fb481 100644 --- a/packages/components/src/internal/components/forms/detail/DetailDisplay.tsx +++ b/packages/components/src/internal/components/forms/detail/DetailDisplay.tsx @@ -341,6 +341,7 @@ export function resolveDetailEditRenderer( maxRows={10} multiple={multiple} name={col.fieldKey} + notFoundValuesEnabled={!(col.isExpInput() || col.isAliquotParent())} // Issue 53153 onBlur={options?.onBlur} onQSChange={options?.onSelectChange} placeholder={options?.placeholder ?? 'Select or type to search...'} @@ -358,15 +359,15 @@ export function resolveDetailEditRenderer( if (col.validValues) { return ( ); } @@ -425,6 +426,7 @@ export function resolveDetailEditRenderer( return ( ; - break; case 'aliasrenderer': renderer = d => ; break; case 'appendunits': - renderer = d => ; + renderer = d => ; break; case 'assayrunreference': renderer = d => ; break; - case 'labelcolorrenderer': - renderer = d => ; + case 'expirationdatecolumnrenderer': + renderer = d => ; break; case 'filecolumnrenderer': renderer = d => ; @@ -470,24 +468,27 @@ export function resolveDetailRenderer(column: QueryColumn): Renderer { case 'foldercolumnrenderer': renderer = d => ; break; + case 'labelcolorrenderer': + renderer = d => ; + break; + case 'multivaluedetailrenderer': + renderer = d => ; + break; case 'nolinkrenderer': renderer = d => ; break; + case 'samplestatusrenderer': + renderer = (d, r) => ; + break; case 'sampletypeimportaliasrenderer': renderer = d => ; break; case 'sourcetypeimportaliasrenderer': renderer = d => ; break; - case 'samplestatusrenderer': - renderer = (d, r) => ; - break; case 'userdetailsrenderer': renderer = d => ; break; - case 'expirationdatecolumnrenderer': - renderer = d => ; - break; default: break; } From 258bdc38c8b69b440f42fe56c95d211880442fa5 Mon Sep 17 00:00:00 2001 From: Alan Vezina Date: Thu, 3 Jul 2025 14:06:01 -0500 Subject: [PATCH 2/5] Alan's 25.7 Issues (#1823) * Fix Issue 53141 --- packages/components/package-lock.json | 4 +- packages/components/package.json | 2 +- .../components/releaseNotes/components.md | 4 + .../src/internal/FilterCriteriaModal.tsx | 21 ++- .../assay/AssayDesignerPanels.tsx | 121 +++++++++--------- 5 files changed, 86 insertions(+), 66 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index ffb1076379..98524082c8 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.53.1", + "version": "6.53.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.53.1", + "version": "6.53.2", "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 8127bf64b1..b9be0f31e5 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.53.1", + "version": "6.53.2", "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 b3400b15be..d6db1cd6d0 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 6.53.2 +*Released*: 3 July 2025 +* Issue 53141: Should set a dirty bit when setting or updating the hit selection criteria for an assay + ### version 6.53.1 *Released*: 3 July 2025 - Issue 53153: Disable value validation for expInput, aliquotParent columns diff --git a/packages/components/src/internal/FilterCriteriaModal.tsx b/packages/components/src/internal/FilterCriteriaModal.tsx index 772887ef76..454aa70a4a 100644 --- a/packages/components/src/internal/FilterCriteriaModal.tsx +++ b/packages/components/src/internal/FilterCriteriaModal.tsx @@ -12,10 +12,10 @@ import { useLoadableState } from './useLoadableState'; import { LoadingSpinner } from './components/base/LoadingSpinner'; import { ChoicesListItem } from './components/base/ChoicesListItem'; import { FilterExpressionView } from './components/search/FilterExpressionView'; -import { useAppContext } from './AppContext'; import { FilterCriteriaColumns } from './components/assay/models'; import { AssayProtocolModel } from './components/domainproperties/assay/models'; import { Alert } from './components/base/Alert'; +import { ComponentsAPIWrapper, getDefaultAPIWrapper } from './APIWrapper'; type BaseFilterCriteriaField = Omit; interface FilterCriteriaField extends BaseFilterCriteriaField { @@ -100,16 +100,21 @@ FilterCriteriaChoice.displayName = 'FilterCriteriaChoice'; * openTo: The propertyId of the domain field you want to open the modal to */ interface Props { + api?: ComponentsAPIWrapper; onClose: () => void; onSave: (filterCriteria: FilterCriteriaMap) => void; openTo?: number; protocolModel: AssayProtocolModel; } -export const FilterCriteriaModal: FC = memo(({ onClose, onSave, openTo, protocolModel }) => { - const { api } = useAppContext(); +export const FilterCriteriaModal: FC = memo(props => { + // Note: we cannot fetch api from useAppContext, because this component can be rendered in LKS, which does not set + // up an AppContext + const { api = getDefaultAPIWrapper(), onClose, onSave, openTo, protocolModel } = props; const { protocolId, container } = protocolModel; const domain = useMemo(() => protocolModel.getDomainByNameSuffix('Data'), [protocolModel]); + // Intentionally not using withRouteLeave, that is handled above this component, after onSave is called + const [isDirty, setIsDirty] = useState(false); const [filterCriteria, setFilterCriteria] = useState(() => { return domain.fields.reduce((result, field) => { if (field.filterCriteria) result.set(field.propertyId, [...field.filterCriteria]); @@ -135,6 +140,7 @@ export const FilterCriteriaModal: FC = memo(({ onClose, onSave, openTo, p const onFieldFilterUpdate = useCallback( (newFilters: Filter.IFilter[]) => { + setIsDirty(true); setFilterCriteria(current => { const filterCriteriaField = filterCriteriaFields.find(field => field.propertyId === selectedFieldId); // Use the referencePropertyId if it exists, because all filterCriteria are stored on the parent field @@ -186,7 +192,14 @@ export const FilterCriteriaModal: FC = memo(({ onClose, onSave, openTo, p const hasFields = fieldsToRender !== undefined && fieldsToRender.length > 0; return ( - + {loading && } {!loading && !error && (
diff --git a/packages/components/src/internal/components/domainproperties/assay/AssayDesignerPanels.tsx b/packages/components/src/internal/components/domainproperties/assay/AssayDesignerPanels.tsx index 81af223700..1d4ebdf723 100644 --- a/packages/components/src/internal/components/domainproperties/assay/AssayDesignerPanels.tsx +++ b/packages/components/src/internal/components/domainproperties/assay/AssayDesignerPanels.tsx @@ -123,27 +123,27 @@ const AssayDomainForm: FC = memo(props => { ]); return (
{domain.description}
@@ -336,40 +336,43 @@ export class AssayDesignerPanelsImpl extends React.PureComponent { }; saveFilterCriteria = (filterCriteria: FilterCriteriaMap) => { - this.setState(current => { - const protocolModel = current.protocolModel; - const resultsIndex = current.protocolModel.domains.findIndex((domain: DomainDesign): boolean => - domain.isNameSuffixMatch('Data') - ); - const domains = current.protocolModel.domains; - let resultsDomain = domains.get(resultsIndex); - // Clear the existing values first - let fields = resultsDomain.fields.map(f => f.set('filterCriteria', []) as DomainField).toList(); - - filterCriteria.forEach((fieldCriteria, propertyId) => { - const domainFieldIdx = fields.findIndex(d => d.propertyId === propertyId); - - if (domainFieldIdx < 0) { - console.warn(`Unable to find domain field with property id ${propertyId}`); - return; - } + this.setState( + current => { + const protocolModel = current.protocolModel; + const resultsIndex = current.protocolModel.domains.findIndex((domain: DomainDesign): boolean => + domain.isNameSuffixMatch('Data') + ); + const domains = current.protocolModel.domains; + let resultsDomain = domains.get(resultsIndex); + // Clear the existing values first + let fields = resultsDomain.fields.map(f => f.set('filterCriteria', []) as DomainField).toList(); - let domainField = fields.get(domainFieldIdx); - domainField = domainField.set('filterCriteria', fieldCriteria) as DomainField; - fields = fields.set(domainFieldIdx, domainField); - }); + filterCriteria.forEach((fieldCriteria, propertyId) => { + const domainFieldIdx = fields.findIndex(d => d.propertyId === propertyId); - resultsDomain = resultsDomain.set('fields', fields) as DomainDesign; + if (domainFieldIdx < 0) { + console.warn(`Unable to find domain field with property id ${propertyId}`); + return; + } - return { - modalOpen: false, - openTo: undefined, - protocolModel: protocolModel.set( - 'domains', - protocolModel.domains.set(resultsIndex, resultsDomain) - ) as AssayProtocolModel, - }; - }); + let domainField = fields.get(domainFieldIdx); + domainField = domainField.set('filterCriteria', fieldCriteria) as DomainField; + fields = fields.set(domainFieldIdx, domainField); + }); + + resultsDomain = resultsDomain.set('fields', fields) as DomainDesign; + + return { + modalOpen: false, + openTo: undefined, + protocolModel: protocolModel.set( + 'domains', + protocolModel.domains.set(resultsIndex, resultsDomain) + ) as AssayProtocolModel, + }; + }, + () => this.props.onChange?.(this.state.protocolModel) + ); }; togglePropertiesPanel = (collapsed, callback): void => { @@ -409,32 +412,32 @@ export class AssayDesignerPanelsImpl extends React.PureComponent { return ( {/* Note: We cannot filter this array because onChange needs the correct index for each domain */} {protocolModel.domains.toArray().map((domain, i) => { @@ -445,16 +448,16 @@ export class AssayDesignerPanelsImpl extends React.PureComponent { @@ -463,8 +466,8 @@ export class AssayDesignerPanelsImpl extends React.PureComponent { {modalOpen && ( )} @@ -472,8 +475,8 @@ export class AssayDesignerPanelsImpl extends React.PureComponent { {appPropertiesOnly && allowFolderExclusion && ( Date: Mon, 7 Jul 2025 08:47:56 -0500 Subject: [PATCH 3/5] Issue 53394: FileInput revert removal of the "-fileUpload" suffix from inputId (#1825) ### version 6.53.3 *Released*: 7 July 2025 - Issue 53394: FileInput revert removal of the "-fileUpload" suffix from inputId --- packages/components/package-lock.json | 4 +-- packages/components/package.json | 2 +- .../components/releaseNotes/components.md | 4 +++ .../components/forms/input/FileInput.tsx | 25 ++++++++++--------- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 98524082c8..976d2939e5 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.53.2", + "version": "6.53.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.53.2", + "version": "6.53.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 b9be0f31e5..91753e4d0a 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.53.2", + "version": "6.53.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 d6db1cd6d0..8647e23ac6 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 6.53.3 +*Released*: 7 July 2025 +- Issue 53394: FileInput revert removal of the "-fileUpload" suffix from inputId + ### version 6.53.2 *Released*: 3 July 2025 * Issue 53141: Should set a dirty bit when setting or updating the hit selection criteria for an assay diff --git a/packages/components/src/internal/components/forms/input/FileInput.tsx b/packages/components/src/internal/components/forms/input/FileInput.tsx index a3374914d1..9e557cd9f3 100644 --- a/packages/components/src/internal/components/forms/input/FileInput.tsx +++ b/packages/components/src/internal/components/forms/input/FileInput.tsx @@ -199,7 +199,8 @@ class FileInputImpl extends DisableableInput { } = this.props; const { data, file, isDisabled, isHover } = this.state; - const inputId = this.getInputName(); + const name = this.getInputName(); + const inputId = `${name}-fileUpload`; // Issue 53394: needs to be a distinct input id so it doesn't collide with other elements on the page for this fieldKey let body; if (file) { @@ -209,10 +210,10 @@ class FileInputImpl extends DisableableInput { body = (
@@ -223,8 +224,8 @@ class FileInputImpl extends DisableableInput { } else if (data?.get('value')) { body = ( ); @@ -232,14 +233,14 @@ class FileInputImpl extends DisableableInput { body = ( <> {/* We render a label here so click and drag events propagate to the input above */} @@ -249,12 +250,12 @@ class FileInputImpl extends DisableableInput { 'file-upload__is-hover': isHover && !isDisabled, })} htmlFor={inputId} - onDrop={this.onDrop} onDragEnter={this.onDrag} - onDragOver={this.onDrag} onDragLeave={this.onDragLeave} + onDragOver={this.onDrag} + onDrop={this.onDrop} > -