diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index abd1d95bd3..23e14067d2 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "6.72.1", + "version": "7.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "6.72.1", + "version": "7.0.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 d8a9257bee..cfdad4c6c6 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "6.72.1", + "version": "7.0.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 f66a935313..7599a5435e 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,6 +1,13 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages +### version 7.0.0 +*Released*: 1 December 2025 +- Updates for new Workflow implementation + - Update URLResolver to reference new controller for workflow-related actions + - add `WORKFLOW` schema and queries and remove legacy job schema/query references + - remove ExperimentRunResolver + ### version 6.72.1 *Released*: 25 November 2025 - QueryColumn to only apply displayWidth for multiLine columns diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index da22ed2dd6..862b90c7a3 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -268,7 +268,7 @@ import { JavaDocsLink, SAMPLE_IMPORT_TOPIC, } from './internal/util/helpLinks'; -import { ExperimentRunResolver, ListResolver } from './internal/url/AppURLResolver'; +import { ListResolver } from './internal/url/AppURLResolver'; import { NOT_ANY_FILTER_TYPE } from './internal/url/NotAnyFilterType'; import { genCellKey, incrementRowCountMetric, parseCellKey } from './internal/components/editable/utils'; import { EditableGrid } from './internal/components/editable/EditableGrid'; @@ -1268,7 +1268,6 @@ export { ExpandableContainer, ExpandableFilterToggle, EXPERIMENT_AUDIT_EVENT, - ExperimentRunResolver, ExpirationDateColumnRenderer, EXPORT_TYPES, ExtendedMap, diff --git a/packages/components/src/internal/AssayDefinitionModel.ts b/packages/components/src/internal/AssayDefinitionModel.ts index 1604ff9002..a456960dd7 100644 --- a/packages/components/src/internal/AssayDefinitionModel.ts +++ b/packages/components/src/internal/AssayDefinitionModel.ts @@ -172,7 +172,7 @@ export class AssayDefinitionModel extends ImmutableRecord({ // 44339: the SourceSamples custom query is backed by exp.materials const isTargetAllSamples = targetSQ.isEqual(SCHEMAS.SAMPLE_MANAGEMENT.SOURCE_SAMPLES) || - targetSQ.isEqual(SCHEMAS.SAMPLE_MANAGEMENT.INPUT_SAMPLES_SQ) || + targetSQ.isEqual(SCHEMAS.WORKFLOW.JOB_INPUT_SAMPLES) || (isPicklist && targetSQ.hasSchema(SCHEMAS.PICKLIST_TABLES.SCHEMA)); const findLookup = (col: QueryColumn): boolean => { if (col.isLookup()) { diff --git a/packages/components/src/internal/components/auditlog/constants.ts b/packages/components/src/internal/components/auditlog/constants.ts index 304162451f..798e014d3e 100644 --- a/packages/components/src/internal/components/auditlog/constants.ts +++ b/packages/components/src/internal/components/auditlog/constants.ts @@ -79,6 +79,7 @@ export const ASSAY_RESULT_AUDIT_QUERY: AuditQuery = { }; export const WORKFLOW_AUDIT_QUERY: AuditQuery = { hasDetail: true, + hasTransactionId: true, label: 'Sample Workflow Events', value: 'SamplesWorkflowAuditEvent', }; diff --git a/packages/components/src/internal/components/samples/utils.tsx b/packages/components/src/internal/components/samples/utils.tsx index 9a05f390eb..b7b6141172 100644 --- a/packages/components/src/internal/components/samples/utils.tsx +++ b/packages/components/src/internal/components/samples/utils.tsx @@ -278,7 +278,7 @@ export function isAllSamplesSchema(schemaQuery: SchemaQuery): boolean { if (lcSchemaName === SCHEMAS.SAMPLE_MANAGEMENT.SCHEMA) { return ( lcQueryName === SCHEMAS.SAMPLE_MANAGEMENT.SOURCE_SAMPLES.queryName.toLowerCase() || - lcQueryName === SCHEMAS.SAMPLE_MANAGEMENT.INPUT_SAMPLES_SQ.queryName.toLowerCase() + lcQueryName === SCHEMAS.WORKFLOW.JOB_INPUT_SAMPLES.queryName.toLowerCase() ); } diff --git a/packages/components/src/internal/schemas.ts b/packages/components/src/internal/schemas.ts index 47ab733e34..9d836aadb7 100644 --- a/packages/components/src/internal/schemas.ts +++ b/packages/components/src/internal/schemas.ts @@ -119,8 +119,17 @@ export const SAMPLE_MANAGEMENT = { SAMPLE_TYPE_INSIGHTS: new SchemaQuery(SAMPLE_MANAGEMENT_SCHEMA, 'SampleTypeInsights'), SAMPLE_STATUS_COUNTS: new SchemaQuery(SAMPLE_MANAGEMENT_SCHEMA, 'SampleStatusCounts'), SOURCE_SAMPLES: new SchemaQuery(SAMPLE_MANAGEMENT_SCHEMA, 'SourceSamples'), - INPUT_SAMPLES_SQ: new SchemaQuery(SAMPLE_MANAGEMENT_SCHEMA, 'InputSamples'), - JOBS: new SchemaQuery(SAMPLE_MANAGEMENT_SCHEMA, 'Jobs'), +}; + +// WORKFLOW +export const WORKFLOW_SCHEMA = "workflow"; +export const WORKFLOW = { + SCHEMA: WORKFLOW_SCHEMA, + JOB: new SchemaQuery(WORKFLOW_SCHEMA, 'Job'), + ACTION: new SchemaQuery(WORKFLOW_SCHEMA, 'Action'), + JOB_TEMPLATE: new SchemaQuery(WORKFLOW_SCHEMA, 'JobTemplate'), + JOB_PRIORITY: new SchemaQuery(WORKFLOW_SCHEMA, 'WorkflowJobPriority'), + JOB_INPUT_SAMPLES: new SchemaQuery(WORKFLOW_SCHEMA, 'JobInputSamples'), }; // STUDY @@ -178,4 +187,5 @@ export const SCHEMAS = { PICKLIST_TABLES, PLATE_TABLES, SAMPLE_MANAGEMENT, + WORKFLOW, }; diff --git a/packages/components/src/internal/url/AppURLResolver.test.ts b/packages/components/src/internal/url/AppURLResolver.test.ts index 9d7f082ce8..f3d0d2f003 100644 --- a/packages/components/src/internal/url/AppURLResolver.test.ts +++ b/packages/components/src/internal/url/AppURLResolver.test.ts @@ -19,7 +19,7 @@ import { registerDefaultURLMappers } from '../test/testHelpers'; import { QueryInfo } from '../../public/QueryInfo'; -import { ExperimentRunResolver, ListResolver } from './AppURLResolver'; +import { ListResolver } from './AppURLResolver'; import { URLResolver } from './URLResolver'; import { AppURL } from './AppURL'; import { encodeListResolverPath } from './utils'; @@ -445,25 +445,4 @@ describe('App Route Resolvers', () => { }), ]); }); - - test('Should resolve /rd/run/### routes', () => { - const jobsResolver = new ExperimentRunResolver(new Set([4, 5, 10])); - - // test regex - expect(jobsResolver.matches(undefined)).toBe(false); - expect(jobsResolver.matches('/rd/samples/4')).toBe(false); - expect(jobsResolver.matches('/rd/run/b')).toBe(false); - expect(jobsResolver.matches('/a/rd/run/b')).toBe(false); - expect(jobsResolver.matches('/rd/run/4')).toBe(true); - expect(jobsResolver.matches('/rd/run/141345')).toBe(true); - - return Promise.all([ - jobsResolver.fetch(['rd', 'runs', 'notanumber']).then(result => { - expect(result).toBe(undefined); - }), - jobsResolver.fetch(['rd', 'runs', 4]).then((result: AppURL) => { - expect(result.toString()).toBe('/workflow/4'); - }), - ]); - }); }); diff --git a/packages/components/src/internal/url/AppURLResolver.ts b/packages/components/src/internal/url/AppURLResolver.ts index 95cc986525..34367ddacb 100644 --- a/packages/components/src/internal/url/AppURLResolver.ts +++ b/packages/components/src/internal/url/AppURLResolver.ts @@ -16,7 +16,7 @@ import { Map } from 'immutable'; import { Filter } from '@labkey/api'; -import { SAMPLE_MANAGEMENT, SCHEMAS } from '../schemas'; +import { SCHEMAS } from '../schemas'; import { selectRows } from '../query/selectRows'; import { caseInsensitive } from '../util/utils'; @@ -98,58 +98,3 @@ export class ListResolver implements AppRouteResolver { return undefined; } } - -/** - * Resolves experiment runs to workflow jobs if appropriate - * /rd/run/14/... -> /workflow/14/... - * If this doesn't correspond to a job, the link won't resolve. - * - * Ideally we would resolve to the original URL if it's not a job, but since that's a link out to LKS - * it's not currently supported by AppRouteResolvers. Alternatively, and perhaps more ideally, we'd resolve - * to the lineage page for a sample, but the URL here doesn't have any info about the related entity. - */ -export class ExperimentRunResolver implements AppRouteResolver { - jobs: Set; // set of rowIds that are jobs - - constructor(jobs?: Set) { - this.jobs = jobs !== undefined ? jobs : new Set(); - } - - async fetch(parts: any[]): Promise { - const rowIdIndex = 2; - const rowId = parseInt(parts[rowIdIndex], 10); - - if (isNaN(rowId)) { - // skip it - return undefined; - } - if (this.jobs.has(rowId)) { - // resolve it - return AppURL.create(WORKFLOW_KEY, rowId); - } - try { - const result = await selectRows({ - schemaQuery: SAMPLE_MANAGEMENT.JOBS, - filterArray: [Filter.create('RowId', rowId)], - columns: 'RowId', - }); - - if (result.rows.length > 0) { - // resolve it - this.jobs.add(rowId); - return AppURL.create(WORKFLOW_KEY, rowId); - } else { - return AppURL.create('rd', 'assayrun', rowId); - } - } catch (e) { - // skip it - } - - // skip it - return undefined; - } - - matches(route: string): boolean { - return /\/rd\/run\/\d+$/.test(route); - } -} diff --git a/packages/components/src/internal/url/URLResolver.ts b/packages/components/src/internal/url/URLResolver.ts index e3f88fa276..d6aded2486 100644 --- a/packages/components/src/internal/url/URLResolver.ts +++ b/packages/components/src/internal/url/URLResolver.ts @@ -766,7 +766,7 @@ export class URLResolver { url = url.substring(0, index); } return row.set('url', this.mapURL({ url, row })); - } else if (url.indexOf('samplemanager-downloadAttachments') >= 0) { + } else if (url.indexOf('workflow-downloadAttachments') >= 0) { return row.set('url', this.mapURL({ url, row })); } else if (url.indexOf('notebook') >= 0) { return row.set('url', this.mapURL({ url, row }));