diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 960d7b58cb..2032d97a7e 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "7.35.2", + "version": "7.35.3-fb-moleculeImport.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "7.35.2", + "version": "7.35.3-fb-moleculeImport.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 ff80056fbf..3833c8830c 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "7.35.2", + "version": "7.35.3-fb-moleculeImport.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 0ac7264c99..0576363ec8 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 7.X +*Released*: X May 2026 +- Molecule and PS bulk import by file + - TODO + ### version 7.35.2 *Released*: 12 May 2026 - Package updates diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index ba0b3643db..d561fa752a 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -194,6 +194,7 @@ import { } from './internal/components/editable/actions'; import { clearSelected, + getDataClassesFromTransactionIds, getGridIdsFromTransactionId, getSampleTypesFromTransactionIds, getSelected, @@ -1338,7 +1339,6 @@ export { genCellKey, GENERAL_ASSAY_PROVIDER_NAME, generateId, - stringToHtmlId, generateNameWithTimestamp, getActionErrorMessage, getActionValuesForFilterProps, @@ -1352,6 +1352,7 @@ export { getContainerFilterForLookups, getContainersForPermission, getDataClassDetails, + getDataClassesFromTransactionIds, getDataDeleteConfirmationData, getDateFNSDateFormat, getDateTimeInputOptions, @@ -1717,6 +1718,7 @@ export { StorageAmountInput, StorageStatusRenderer, STORED_AMOUNT_FIELDS, + stringToHtmlId, SVGIcon, Tab, TabbedGridPanel, diff --git a/packages/components/src/internal/actions.ts b/packages/components/src/internal/actions.ts index 77a10200dd..2d94822afe 100644 --- a/packages/components/src/internal/actions.ts +++ b/packages/components/src/internal/actions.ts @@ -43,8 +43,10 @@ import { resolveErrorMessage } from './util/messaging'; import { ViewInfo } from './ViewInfo'; import { createGridModelId } from './models'; -import { SAMPLES_KEY } from './app/constants'; +import { SAMPLES_KEY, SOURCES_KEY } from './app/constants'; import { SCHEMAS } from './schemas'; +import { selectRows } from './query/selectRows'; +import { caseInsensitive } from './util/utils'; export function selectAll( key: string, @@ -62,12 +64,19 @@ export function selectAll( }); } +type DataTypeRowIdsFromTransactionIds = { + dataTypeRowCounts: Record; // todo rename to count + typeNameRowCounts?: Record; + dataTypes?: string[]; + rowIds: string[]; +}; + export async function getGridIdsFromTransactionId( transactionAuditId: number | string, dataType: string, containerPath?: string -): Promise { - if (!transactionAuditId) return; +): Promise { + if (!transactionAuditId) return { rowIds: [], dataTypeRowCounts: {} }; const failureMsg = `There was a problem retrieving the ${dataType} from the last action.`; const errorLogMsg = `${failureMsg} (transactionAuditId = ${transactionAuditId})`; @@ -88,7 +97,11 @@ export async function getGridIdsFromTransactionId( } // The server returns numbers, so we coerce to string; If we don't, it can lead to bugs (and has). - return response.rowIds.map(rowId => rowId.toString()); + const rowIds = response.rowIds.map(rowId => rowId.toString()); + return { + rowIds, + dataTypeRowCounts: response['dataTypeRowCounts'], + }; } export async function selectGridIdsFromTransactionId( @@ -97,32 +110,81 @@ export async function selectGridIdsFromTransactionId( transactionAuditId: number | string, dataType: string, actions: Actions -): Promise { - if (!transactionAuditId) return undefined; +): Promise { + if (!transactionAuditId) return { rowIds: [], dataTypeRowCounts: {} }; const modelId = createGridModelId(gridIdPrefix, schemaQuery); const selected = await getGridIdsFromTransactionId(transactionAuditId, dataType); - actions.replaceSelections(modelId, selected); + actions.replaceSelections(modelId, selected.rowIds); return selected; } -type SampleTypesFromTransactionIds = { rowIds: string[]; sampleTypes: string[] }; - -export async function getSampleTypesFromTransactionIds( - transactionAuditId: number | string -): Promise { - if (!transactionAuditId) return undefined; - - const rowIds = await getGridIdsFromTransactionId(transactionAuditId, SAMPLES_KEY); - const sampleTypes = await selectDistinctRows({ - schemaName: SCHEMAS.EXP_TABLES.MATERIALS.schemaName, - queryName: SCHEMAS.EXP_TABLES.MATERIALS.queryName, - column: 'SampleSet/Name', +async function getDataTypesFromTransactionId( + transactionAuditId: number | string, + auditDataType: string, + schemaName: string, + queryName: string, + typeColumn: string +): Promise { + if (!transactionAuditId) return { rowIds: [], dataTypeRowCounts: {}, dataTypes: [] }; + + const { rowIds, dataTypeRowCounts } = await getGridIdsFromTransactionId(transactionAuditId, auditDataType); + const distinct = await selectDistinctRows({ + schemaName, + queryName, + column: typeColumn, filterArray: [Filter.create('RowId', rowIds, Filter.Types.IN)], }); + return { rowIds, dataTypeRowCounts, dataTypes: distinct.values }; +} + +export function getSampleTypesFromTransactionIds( + transactionAuditId: number | string +): Promise { + return getDataTypesFromTransactionId( + transactionAuditId, + SAMPLES_KEY, + SCHEMAS.EXP_TABLES.MATERIALS.schemaName, + SCHEMAS.EXP_TABLES.MATERIALS.queryName, + 'SampleSet/Name' + ); +} + +export async function getDataClassesFromTransactionIds( + transactionAuditId: number | string +): Promise { + const results = await getDataTypesFromTransactionId( + transactionAuditId, + SOURCES_KEY, + SCHEMAS.EXP_TABLES.DATA.schemaName, + SCHEMAS.EXP_TABLES.DATA.queryName, + 'DataClass/Name' + ); + + if (!results.rowIds.length) return { ...results, typeNameRowCounts: {} }; + + const { dataTypeRowCounts, dataTypes } = results; + const dataTypeLcMap = Object.fromEntries((dataTypes ?? []).map(dt => [dt.toLowerCase(), dt])); + + const typeNameRowCounts = {}; + if (Object.keys(dataTypeRowCounts).length > 0) { + const dataClasses = await selectRows({ + schemaQuery: SCHEMAS.EXP_TABLES.DATA_CLASSES, + columns: ['Name', 'RowId'], + filterArray: [Filter.create('rowId', Object.keys(dataTypeRowCounts), Filter.Types.IN)], + containerFilter: Query.containerFilter.currentPlusProjectAndShared, + }); + + dataClasses.rows.forEach(row => { + const dataClassLc = caseInsensitive(row, 'Name')?.value?.toLowerCase(); + const rowId = caseInsensitive(row, 'RowId').value; + typeNameRowCounts[dataTypeLcMap[dataClassLc]] = dataTypeRowCounts[rowId]; + }); + } + return { - rowIds, - sampleTypes: sampleTypes.values, + ...results, + typeNameRowCounts, }; }