Skip to content

Commit

Permalink
Merge branch 'wip'
Browse files Browse the repository at this point in the history
  • Loading branch information
dbolotin committed Oct 7, 2024
2 parents 326b1b0 + cb277f2 commit 9da90e5
Show file tree
Hide file tree
Showing 36 changed files with 1,576 additions and 92,898 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ jobs:
build-script-name: 'build'
test: true
test-script-name: 'test'
pnpm-recursive-build: true
pnpm-recursive-tests: true
publish-to-public: 'false'
npmrc-config: |
{
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ block-pack/
dev/
work/
.test_auth.json
.turbo
vite.config.*.timestamp-*
2 changes: 1 addition & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
publish-branch=main
link-workspace-packages=false
workspace-concurrency=1
include-workspace-root=true

92,117 changes: 0 additions & 92,117 deletions log/platforma.log

This file was deleted.

4 changes: 3 additions & 1 deletion model/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
"module": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsup && vite build && block-tools build-model"
"build": "tsup && vite build && block-tools build-model",
"test": "vitest"
},
"dependencies": {
"@platforma-sdk/model": "catalog:",
"zod": "catalog:"
},
"devDependencies": {
"@platforma-sdk/block-tools": "catalog:",
"vitest": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"tsup": "catalog:"
Expand Down
39 changes: 25 additions & 14 deletions model/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,20 @@ export type PColumnResourceMapData<T> = {
function populateResourceMapData<T>(
acc: TreeNodeAccessor | undefined,
resourceParser: (acc: TreeNodeAccessor) => T | undefined,
data: PColumnResourceMapEntry<T>[],
keyPrefix: PColumnKey = []
data: PColumnResourceMapEntry<T | undefined>[],
keyPrefix: PColumnKey = [],
addEntriesWithNoData: boolean
): boolean {
if (acc === undefined) return false;
switch (acc.resourceType.name) {
case ResourceMapResourceTypeName: {
let isComplete = acc.getInputsLocked();
for (const keyStr of acc.listInputFields()) {
const value = acc.resolve({ field: keyStr, assertFieldType: 'Input' });
if (value === undefined) isComplete = false;
else {
const key = [...keyPrefix, ...JSON.parse(keyStr)] as PColumnKey;
const converted = resourceParser(value);
if (converted === undefined) isComplete = false;
else data.push({ key, value: converted });
}
const key = [...keyPrefix, ...JSON.parse(keyStr)] as PColumnKey;
const converted = value === undefined ? undefined : resourceParser(value);
if (converted === undefined) isComplete = false;
if (converted !== undefined || addEntriesWithNoData) data.push({ key, value: converted });
}
return isComplete;
}
Expand All @@ -79,7 +77,9 @@ function populateResourceMapData<T>(
if (value === undefined) isComplete = false;
else {
const key = [...keyPrefix, ...JSON.parse(keyStr)] as PColumnKey;
isComplete = isComplete && populateResourceMapData(value, resourceParser, data, key);
isComplete =
isComplete &&
populateResourceMapData(value, resourceParser, data, key, addEntriesWithNoData);
}
}
return isComplete;
Expand All @@ -91,9 +91,20 @@ function populateResourceMapData<T>(

export function parseResourceMap<T>(
acc: TreeNodeAccessor | undefined,
resourceParser: (acc: TreeNodeAccessor) => T | undefined
): PColumnResourceMapData<NonNullable<T>> {
const data: PColumnResourceMapEntry<NonNullable<T>>[] = [];
const isComplete = populateResourceMapData(acc, resourceParser, data, []);
resourceParser: (acc: TreeNodeAccessor) => T | undefined,
addEntriesWithNoData: false
): PColumnResourceMapData<NonNullable<T>>;
export function parseResourceMap<T>(
acc: TreeNodeAccessor | undefined,
resourceParser: (acc: TreeNodeAccessor) => T | undefined,
addEntriesWithNoData: true
): PColumnResourceMapData<T | undefined>;
export function parseResourceMap<T>(
acc: TreeNodeAccessor | undefined,
resourceParser: (acc: TreeNodeAccessor) => T | undefined,
addEntriesWithNoData: boolean = false
): PColumnResourceMapData<T | undefined> {
const data: PColumnResourceMapEntry<T | undefined>[] = [];
const isComplete = populateResourceMapData(acc, resourceParser, data, [], addEntriesWithNoData);
return { isComplete, data };
}
29 changes: 18 additions & 11 deletions model/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,38 +30,46 @@ export const platforma = BlockModel.create<BlockArgs>('Heavy')
)

.output('qc', (ctx) =>
parseResourceMap(ctx.outputs?.resolve({ field: 'qc', assertFieldType: 'Input' }), (acc) =>
acc.getFileHandle()
parseResourceMap(
ctx.outputs?.resolve({ field: 'qc', assertFieldType: 'Input' }),
(acc) => acc.getFileHandle(),
true
)
)

.output('reports', (ctx) =>
parseResourceMap(ctx.outputs?.resolve({ field: 'reports', assertFieldType: 'Input' }), (acc) =>
acc.getFileHandle()
acc.getFileHandle(),
false
)
)

.output('logs', (ctx) => {
return ctx.outputs !== undefined
? parseResourceMap(ctx.outputs?.resolve({ field: 'logs', assertFieldType: 'Input' }), (acc) =>
acc.getLogHandle()
acc.getLogHandle(),
false
)
: undefined;
})

.output('progress', (ctx) => {
return ctx.outputs !== undefined
? parseResourceMap(ctx.outputs?.resolve({ field: 'logs', assertFieldType: 'Input' }), (acc) =>
acc.getProgressLog(ProgressPrefix)
acc.getProgressLog(ProgressPrefix),
false
)
: undefined;
})

.output('started', (ctx) => ctx.outputs !== undefined)

.output('done', (ctx) => {
return ctx.outputs !== undefined
? parseResourceMap(
ctx.outputs?.resolve({ field: 'clns', assertFieldType: 'Input' }),
(acc) => true
(acc) => true,
false
).data.map((e) => e.key[0] as string)
: undefined;
})
Expand Down Expand Up @@ -103,7 +111,7 @@ export const platforma = BlockModel.create<BlockArgs>('Heavy')
);
})

.output('sampleLabels', (ctx) => {
.output('sampleLabels', (ctx): Record<string, string> | undefined => {
const inputRef = ctx.args.input;
if (inputRef === undefined) return undefined;
// @todo implement getSpecByRef method
Expand Down Expand Up @@ -142,10 +150,7 @@ export const platforma = BlockModel.create<BlockArgs>('Heavy')
})

.sections((ctx) => {
return [
{ type: 'link', href: '/', label: 'Settings' },
{ type: 'link', href: '/reports', label: 'Reports' }
];
return [{ type: 'link', href: '/', label: 'Main' }];
})

.inputsValid((ctx) => BlockArgsValid.safeParse(ctx.args).success)
Expand All @@ -157,4 +162,6 @@ export type Href = InferHrefType<typeof platforma>;
export * from './args';
export * from './helpers';
export * from './logs';
export * from './qc';
export * from './reports';
export { BlockArgs };
135 changes: 135 additions & 0 deletions model/src/qc.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { test } from 'vitest';
import { Qc } from './qc';

test('test simple qc parsing', ({ expect }) => {
const qc: any = [
{
step: 'align',
status: 'OK',
check: {
type: 'SuccessfullyAlignedReads',
upper: 0.85,
middle: 0.7,
label: 'Successfully aligned reads'
},
payload: {
printedValue: '90.0%',
value: 0.9
}
},
{
step: 'align',
status: 'OK',
check: {
type: 'OffTargetReads',
upper: 0.2,
middle: 0.1,
label: 'Off target (non TCR/IG) reads'
},
payload: {
printedValue: '0.0%',
value: 0.0
}
},
{
step: 'align',
status: 'OK',
check: {
type: 'ReadsWithNoVOrJHits',
upper: 0.2,
middle: 0.1,
label: 'Reads with no V or J hits'
},
payload: {
printedValue: '10.0%',
value: 0.1
}
},
{
step: 'assemble',
status: 'ALERT',
check: {
type: 'ReadsUsedInClonotypes',
upper: 0.9,
middle: 0.7,
label: 'Reads used in clonotypes'
},
payload: {
printedValue: '40.0%',
value: 0.4
}
},
{
step: 'assemble',
status: 'OK',
check: {
type: 'AlignmentsWithNoAssemblingFeature',
upper: 0.15,
middle: 0.05,
label: 'Alignments without assembling feature'
},
payload: {
labelOverride: 'Alignments that do not cover CDR3',
printedValue: '0.0%',
value: 0.0
}
},
{
step: 'assemble',
status: 'OK',
check: {
type: 'AlignmentsDroppedLowQuality',
upper: 0.05,
middle: 0.01,
label: 'Alignments dropped due to low sequence quality'
},
payload: {
printedValue: '0.0%',
value: 0.0
}
},
{
step: 'assemble',
status: 'OK',
check: {
type: 'ClonesDroppedInPostFiltering',
upper: 0.05,
middle: 0.01,
label: 'Clones dropped in post-filtering'
},
payload: {
printedValue: '0.0%',
value: 0.0
}
},
{
step: 'assemble',
status: 'OK',
check: {
type: 'AlignmentsDroppedInPostFiltering',
upper: 0.05,
middle: 0.01,
label: 'Alignments dropped in clones post-filtering'
},
payload: {
printedValue: '0.0%',
value: 0.0
}
},
{
step: 'align',
status: 'ALERT',
check: {
type: 'OverlappedReadsMoreBetter',
upper: 0.9,
middle: 0.8,
label: 'Overlapped paired-end reads'
},
payload: {
printedValue: '10.0%',
value: 0.1
}
}
];
Qc.parse(qc);
});
26 changes: 26 additions & 0 deletions model/src/qc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { z } from 'zod';

export const QcStatus = z.union([z.literal('OK'), z.literal('WARN'), z.literal('ALERT')]);

export const QcCheck = z.object({
type: z.string(),
upper: z.number().optional(),
middle: z.number().optional(),
label: z.string()
});
export type QcCheck = z.infer<typeof QcCheck>;

export const QcCheckResult = z.object({
step: z.string(),
status: QcStatus,
check: QcCheck,
payload: z.object({
printedValue: z.coerce.string().optional(),
value: z.coerce.string().optional(),
labelOverride: z.coerce.string().optional()
})
});
export type QcCheckResult = z.infer<typeof QcCheckResult>;

export const Qc = z.array(QcCheckResult);
export type Qc = z.infer<typeof Qc>;
Loading

0 comments on commit 9da90e5

Please sign in to comment.