From ca213d242063fad388eccd9e0d1ad7e4ec18cd13 Mon Sep 17 00:00:00 2001 From: alanv Date: Thu, 2 Oct 2025 12:10:48 -0500 Subject: [PATCH 1/4] Move IQueryColumn to its own file Gets rid of circular dependency between QueryColumn and ViewInfo. --- packages/components/src/internal/ViewInfo.ts | 2 +- .../components/src/public/IQueryColumn.ts | 77 +++++++++++++++++++ packages/components/src/public/QueryColumn.ts | 76 +----------------- 3 files changed, 79 insertions(+), 76 deletions(-) create mode 100644 packages/components/src/public/IQueryColumn.ts diff --git a/packages/components/src/internal/ViewInfo.ts b/packages/components/src/internal/ViewInfo.ts index 341635d31b..abf23db200 100644 --- a/packages/components/src/internal/ViewInfo.ts +++ b/packages/components/src/internal/ViewInfo.ts @@ -1,5 +1,5 @@ import { Filter } from '@labkey/api'; -import { IQueryColumn } from '../public/QueryColumn'; +import { IQueryColumn } from '../public/IQueryColumn'; import { QuerySort, QuerySortJson } from '../public/QuerySort'; import { QueryInfo } from '../public/QueryInfo'; diff --git a/packages/components/src/public/IQueryColumn.ts b/packages/components/src/public/IQueryColumn.ts new file mode 100644 index 0000000000..826af56686 --- /dev/null +++ b/packages/components/src/public/IQueryColumn.ts @@ -0,0 +1,77 @@ +// Note: it is necessary to put IQueryColumn in its own file in order to get rid of circular dependencies between +// ViewInfo and QueryColumn via the schemas.ts + +export interface IQueryColumn { + addToSystemView: boolean; + align: string; + // autoIncrement: boolean; + // calculated: boolean; + caption: string; + conceptSubtree: string; + conceptURI: string; + defaultValue: any; + derivationDataScope: string; + description: string; + dimension: boolean; + displayAsLookup: boolean; + // defaultScale: string; + displayField?: string; + displayFieldJsonType?: string; + displayFieldSqlType?: string; + // excludeFromShifting: boolean; + // ext: any; + facetingBehaviorType: string; + fieldKey: string; + fieldKeyArray: string[]; + fieldKeyPath: string; + filterable: boolean; + format: string; + // friendlyType: string; + hasSortKey: boolean; + hidden: boolean; + inputType: string; + // isAutoIncrement: boolean; // DUPLICATE + // isHidden: boolean; // DUPLICATE + isKeyField: boolean; + // isMvEnabled: boolean; + // isNullable: boolean; + // isReadOnly: boolean; + // isSelectable: boolean; // DUPLICATE + // isUserEditable: boolean; // DUPLICATE + // isVersionField: boolean; + jsonType: string; + // keyField: boolean; + lookup: Record; + measure: boolean; + multiValue: boolean; + // mvEnabled: boolean; + name: string; + nameExpression: string; + // nullable: boolean; + phiProtected: boolean; + protected: boolean; + rangeURI: string; + readOnly: boolean; + removeFromViewCustomization: boolean; + removeFromViews: boolean; // strips this column from all ViewInfo definitions + // recommendedVariable: boolean; + required: boolean; + scale: number; + selectable: boolean; + shortCaption: string; + shownInDetailsView: boolean; + shownInInsertView: boolean; + shownInLookupView: boolean; + shownInUpdateView: boolean; + sortable: boolean; + // versionField: boolean; + sorts: '+' | '-'; + sourceOntology: string; + // sqlType: string; + tableCell: boolean; + type: string; + units: string; + userEditable: boolean; + validValues: string[]; + width: number; +} diff --git a/packages/components/src/public/QueryColumn.ts b/packages/components/src/public/QueryColumn.ts index f8d666a328..e241ecb1b5 100644 --- a/packages/components/src/public/QueryColumn.ts +++ b/packages/components/src/public/QueryColumn.ts @@ -17,6 +17,7 @@ import { isAllSamplesSchema } from '../internal/components/samples/utils'; import { SAMPLES_WITH_TYPES_FILTER } from '../internal/components/samples/constants'; import { SchemaQuery } from './SchemaQuery'; +import { IQueryColumn } from './IQueryColumn'; export enum Operation { insert = 'insert', @@ -113,81 +114,6 @@ const defaultQueryColumn = { removeFromViews: false, }; -export interface IQueryColumn { - addToSystemView: boolean; - align: string; - // autoIncrement: boolean; - // calculated: boolean; - caption: string; - conceptSubtree: string; - conceptURI: string; - defaultValue: any; - derivationDataScope: string; - description: string; - dimension: boolean; - displayAsLookup: boolean; - // defaultScale: string; - displayField?: string; - displayFieldJsonType?: string; - displayFieldSqlType?: string; - // excludeFromShifting: boolean; - // ext: any; - facetingBehaviorType: string; - fieldKey: string; - fieldKeyArray: string[]; - fieldKeyPath: string; - filterable: boolean; - format: string; - // friendlyType: string; - hasSortKey: boolean; - hidden: boolean; - inputType: string; - // isAutoIncrement: boolean; // DUPLICATE - // isHidden: boolean; // DUPLICATE - isKeyField: boolean; - // isMvEnabled: boolean; - // isNullable: boolean; - // isReadOnly: boolean; - // isSelectable: boolean; // DUPLICATE - // isUserEditable: boolean; // DUPLICATE - // isVersionField: boolean; - jsonType: string; - // keyField: boolean; - lookup: Record; - measure: boolean; - multiValue: boolean; - // mvEnabled: boolean; - name: string; - nameExpression: string; - // nullable: boolean; - phiProtected: boolean; - protected: boolean; - rangeURI: string; - readOnly: boolean; - removeFromViewCustomization: boolean; - removeFromViews: boolean; // strips this column from all ViewInfo definitions - // recommendedVariable: boolean; - required: boolean; - scale: number; - selectable: boolean; - shortCaption: string; - shownInDetailsView: boolean; - shownInInsertView: boolean; - shownInLookupView: boolean; - shownInUpdateView: boolean; - sortable: boolean; - // versionField: boolean; - sorts: '+' | '-'; - sourceOntology: string; - // sqlType: string; - tableCell: boolean; - type: string; - units: string; - userEditable: boolean; - validValues: string[]; - width: number; -} - export class QueryColumn implements IQueryColumn { declare align: string; // declare autoIncrement: boolean; From bcc19d4e6663855935525051695829ff7880aefa Mon Sep 17 00:00:00 2001 From: alanv Date: Fri, 3 Oct 2025 15:13:46 -0500 Subject: [PATCH 2/4] AssayDefinitionModel: Add plateEnabled flag, lint file --- .../components/releaseNotes/components.md | 4 +++ .../src/internal/AssayDefinitionModel.ts | 26 ++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index 71f7c76aff..54c3ce1c83 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -20,6 +20,10 @@ Components, models, actions, and utility functions for LabKey applications and p *Released*: 3 October 2025 - Issue 53328: AssayDefinitionModel.hasLookup to only consider the first sample lookup column for assay import cases +### version 6.62.7 +*Released*: 29 September 2025 +- AssayDefinitionModel: add plateEnabled flag + ### version 6.62.7 *Released*: 29 September 2025 - Enumerate plate, plate set auditing events diff --git a/packages/components/src/internal/AssayDefinitionModel.ts b/packages/components/src/internal/AssayDefinitionModel.ts index 04589a7bd6..a073da74d5 100644 --- a/packages/components/src/internal/AssayDefinitionModel.ts +++ b/packages/components/src/internal/AssayDefinitionModel.ts @@ -48,6 +48,7 @@ export class AssayDefinitionModel extends ImmutableRecord({ importController: undefined, links: Map(), name: undefined, + plateEnabled: undefined, projectLevel: undefined, protocolSchemaName: undefined, requireCommentOnQCStateChange: undefined, @@ -64,6 +65,7 @@ export class AssayDefinitionModel extends ImmutableRecord({ declare importController: string; declare links: Map; declare name: string; + declare plateEnabled: boolean; declare projectLevel: boolean; declare protocolSchemaName: string; declare requireCommentOnQCStateChange: boolean; @@ -230,11 +232,18 @@ export class AssayDefinitionModel extends ImmutableRecord({ return this.getSampleColumns(domainType)[0]; } + private isWellLsidColumn(domain: AssayDomainTypes, col: QueryColumn): boolean { + return this.plateEnabled && domain === AssayDomainTypes.RESULT && col.fieldKey.toLowerCase() === 'welllsid'; + } + /** * returns the FieldKey string of the sample column relative from the assay Results table. */ sampleColumnFieldKey(sampleCol: ScopedSampleColumn): string { if (sampleCol.domain === AssayDomainTypes.RESULT) { + // Note: The Results Domain will never have the Well column on it, only WellLsid and WellLocation, but this + // column is present when querying the data, so this does work when used to create filters on a grid. + if (this.isWellLsidColumn(sampleCol.domain, sampleCol.column)) return `Well/SampleId`; return sampleCol.column.fieldKey; } else if (sampleCol.domain === AssayDomainTypes.RUN) { return `Run/${sampleCol.column.fieldKey}`; @@ -248,7 +257,7 @@ export class AssayDefinitionModel extends ImmutableRecord({ * returns the FieldKey string of the sample columns relative from the assay Results table. */ getSampleColumnFieldKeys(domainType?: AssayDomainTypes): string[] { - return this.getSampleColumns(domainType).map(this.sampleColumnFieldKey); + return this.getSampleColumns(domainType).map(scopedCol => this.sampleColumnFieldKey(scopedCol)); } getDomainColumns(type: AssayDomainTypes): ExtendedMap { @@ -267,16 +276,13 @@ export class AssayDefinitionModel extends ImmutableRecord({ return this.getDomainColumns(type).filter(col => col.isFileInput).valueArray; } - private getSampleColumnsByDomain(domainType: AssayDomainTypes): ScopedSampleColumn[] { - const columns: ScopedSampleColumn[] = []; + private getSampleColumnsByDomain(domain: AssayDomainTypes): ScopedSampleColumn[] { + const columns = this.getDomainByType(domain) + ?.filter(column => column.isSampleLookup() || this.isWellLsidColumn(domain, column)) + .map(column => ({ column, domain })) + .toArray(); - this.getDomainByType(domainType)?.forEach(column => { - if (column.isSampleLookup()) { - columns.push({ column, domain: domainType }); - } - }); - - return columns; + return columns ?? []; } isSampleColInResults(column: QueryColumn, domain: AssayDomainTypes): boolean { From d25d93632014863e5563fa79aa992227e69c42f1 Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 6 Oct 2025 17:43:07 -0500 Subject: [PATCH 3/4] TabbedGridPanel - Add displayName to components --- packages/components/src/public/QueryModel/TabbedGridPanel.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/components/src/public/QueryModel/TabbedGridPanel.tsx b/packages/components/src/public/QueryModel/TabbedGridPanel.tsx index 0d9ee541b1..ef31a951a4 100644 --- a/packages/components/src/public/QueryModel/TabbedGridPanel.tsx +++ b/packages/components/src/public/QueryModel/TabbedGridPanel.tsx @@ -58,6 +58,7 @@ const GridTab: FC = memo(({ isActive, model, onSelect, pullRight, ); }); +GridTab.displayName = 'GridTab'; export interface TabbedGridPanelProps extends GridPanelProps { /** @@ -326,3 +327,4 @@ export const TabbedGridPanel: FC = m ); }); +TabbedGridPanel.displayName = 'TabbedGridPanel'; From 4a7e5e10d18ae2bd6c91ca1bf45ff80475653859 Mon Sep 17 00:00:00 2001 From: alanv Date: Thu, 9 Oct 2025 14:34:51 -0500 Subject: [PATCH 4/4] Prep for release --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- packages/components/releaseNotes/components.md | 9 +++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index cb3ef7cb0d..faef0eb9b5 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.63.2", + "version": "6.64.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.63.2", + "version": "6.64.0", "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 85fe139a50..25ccecc6ef 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.63.2", + "version": "6.64.0", "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 54c3ce1c83..84972f70bd 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,6 +1,11 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages +### version 6.64.0 +*Released*: 9 October 2025 +- AssayDefinitionModel: add plateEnabled flag +- Fix circular dependency caused by IQueryColumn interface + ### version 6.63.2 *Released*: 8 October 2025 - Issue 53324: LKSM: Custom Grid View Column Limit @@ -20,10 +25,6 @@ Components, models, actions, and utility functions for LabKey applications and p *Released*: 3 October 2025 - Issue 53328: AssayDefinitionModel.hasLookup to only consider the first sample lookup column for assay import cases -### version 6.62.7 -*Released*: 29 September 2025 -- AssayDefinitionModel: add plateEnabled flag - ### version 6.62.7 *Released*: 29 September 2025 - Enumerate plate, plate set auditing events