@platforma-sdk/model 1.69.0 → 1.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/columns/column_collection_builder.cjs +1 -4
- package/dist/columns/column_collection_builder.cjs.map +1 -1
- package/dist/columns/column_collection_builder.d.ts +0 -2
- package/dist/columns/column_collection_builder.d.ts.map +1 -1
- package/dist/columns/column_collection_builder.js +1 -4
- package/dist/columns/column_collection_builder.js.map +1 -1
- package/dist/columns/ctx_column_sources.cjs +5 -8
- package/dist/columns/ctx_column_sources.cjs.map +1 -1
- package/dist/columns/ctx_column_sources.d.ts +4 -7
- package/dist/columns/ctx_column_sources.d.ts.map +1 -1
- package/dist/columns/ctx_column_sources.js +5 -8
- package/dist/columns/ctx_column_sources.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +1 -4
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +1 -4
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs +1 -2
- package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js +1 -2
- package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.cjs +1 -4
- package/dist/components/PlDataTable/createPlDataTable/utils.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/utils.js +1 -4
- package/dist/components/PlDataTable/createPlDataTable/utils.js.map +1 -1
- package/dist/components/PlDatasetSelector/build_dataset_options.cjs +23 -11
- package/dist/components/PlDatasetSelector/build_dataset_options.cjs.map +1 -1
- package/dist/components/PlDatasetSelector/build_dataset_options.d.ts +9 -2
- package/dist/components/PlDatasetSelector/build_dataset_options.d.ts.map +1 -1
- package/dist/components/PlDatasetSelector/build_dataset_options.js +22 -11
- package/dist/components/PlDatasetSelector/build_dataset_options.js.map +1 -1
- package/dist/components/PlDatasetSelector/dataset_selection.cjs +20 -0
- package/dist/components/PlDatasetSelector/dataset_selection.cjs.map +1 -0
- package/dist/components/PlDatasetSelector/dataset_selection.d.ts +23 -0
- package/dist/components/PlDatasetSelector/dataset_selection.d.ts.map +1 -0
- package/dist/components/PlDatasetSelector/dataset_selection.js +19 -0
- package/dist/components/PlDatasetSelector/dataset_selection.js.map +1 -0
- package/dist/components/PlDatasetSelector/enrichment_discovery.cjs +75 -0
- package/dist/components/PlDatasetSelector/enrichment_discovery.cjs.map +1 -0
- package/dist/components/PlDatasetSelector/enrichment_discovery.js +73 -0
- package/dist/components/PlDatasetSelector/enrichment_discovery.js.map +1 -0
- package/dist/components/PlDatasetSelector/index.cjs +1 -0
- package/dist/components/PlDatasetSelector/index.d.ts +1 -0
- package/dist/components/PlDatasetSelector/index.js +1 -0
- package/dist/components/index.cjs +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/index.cjs +3 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/labels/derive_distinct_tooltips.cjs +0 -3
- package/dist/labels/derive_distinct_tooltips.cjs.map +1 -1
- package/dist/labels/derive_distinct_tooltips.js +0 -3
- package/dist/labels/derive_distinct_tooltips.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.js +1 -1
- package/package.json +9 -9
- package/src/columns/column_collection_builder.ts +0 -3
- package/src/columns/ctx_column_sources.ts +6 -12
- package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +0 -1
- package/src/components/PlDataTable/createPlDataTable/discoverColumns.ts +0 -1
- package/src/components/PlDataTable/createPlDataTable/utils.ts +0 -1
- package/src/components/PlDatasetSelector/build_dataset_options.ts +48 -17
- package/src/components/PlDatasetSelector/dataset_selection.ts +37 -0
- package/src/components/PlDatasetSelector/enrichment_discovery.ts +111 -0
- package/src/components/PlDatasetSelector/index.ts +1 -0
- package/src/labels/derive_distinct_tooltips.test.ts +6 -16
- package/src/labels/derive_distinct_tooltips.ts +0 -3
|
@@ -9,32 +9,26 @@ import { ResourceTypeName } from "@milaboratories/pl-model-common";
|
|
|
9
9
|
import type { ValueOf } from "@milaboratories/helpers";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Collect ColumnSnapshotProviders from
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - **prerun** — PFrame fields from prerun/staging results
|
|
17
|
-
*
|
|
18
|
-
* Returns an array of providers suitable for `ColumnCollectionBuilder.addSource()`.
|
|
12
|
+
* Collect ColumnSnapshotProviders from `outputs`, `prerun`, and
|
|
13
|
+
* `resultPool` in that order. Dedup keeps the first occurrence per
|
|
14
|
+
* `NativePObjectId`, so a block re-publishing its own columns keeps
|
|
15
|
+
* the `outputs`-rooted canonical id instead of the result-pool variant.
|
|
19
16
|
*/
|
|
20
17
|
export function collectCtxColumnSnapshotProviders(ctx: RenderCtxBase): ColumnSnapshotProvider[] {
|
|
21
18
|
const providers: ColumnSnapshotProvider[] = [];
|
|
22
19
|
|
|
23
|
-
// ResultPool — all upstream columns
|
|
24
|
-
providers.push(new ResultPoolColumnSnapshotProvider(ctx.resultPool));
|
|
25
|
-
|
|
26
|
-
// Outputs — each PFrame-like output field becomes a provider
|
|
27
20
|
const outputs = ctx.outputs;
|
|
28
21
|
if (outputs) {
|
|
29
22
|
providers.push(...collectPFrameProviders(outputs));
|
|
30
23
|
}
|
|
31
24
|
|
|
32
|
-
// Prerun — same treatment as outputs
|
|
33
25
|
const prerun = ctx.prerun;
|
|
34
26
|
if (prerun) {
|
|
35
27
|
providers.push(...collectPFrameProviders(prerun));
|
|
36
28
|
}
|
|
37
29
|
|
|
30
|
+
providers.push(new ResultPoolColumnSnapshotProvider(ctx.resultPool));
|
|
31
|
+
|
|
38
32
|
return providers;
|
|
39
33
|
}
|
|
40
34
|
|
|
@@ -102,7 +102,6 @@ function mapToTableColumnVariants(
|
|
|
102
102
|
path: variant.path.map((p) => ({
|
|
103
103
|
type: "linker",
|
|
104
104
|
column: p.linker.id,
|
|
105
|
-
qualifications: p.qualifications,
|
|
106
105
|
})),
|
|
107
106
|
columnQualifications: variant.qualifications.forHit,
|
|
108
107
|
queriesQualifications: variant.qualifications.forQueries,
|
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
Option,
|
|
4
|
-
PColumnSelector,
|
|
5
|
-
PObjectSpec,
|
|
6
|
-
} from "@milaboratories/pl-model-common";
|
|
1
|
+
import type { MultiColumnSelector, Option, PObjectSpec } from "@milaboratories/pl-model-common";
|
|
2
|
+
import { multiColumnSelectorsToPredicate } from "@milaboratories/pl-model-common";
|
|
7
3
|
import type { DeriveLabelsOptions } from "../../labels/derive_distinct_labels";
|
|
8
4
|
import type { RenderCtxBase } from "../../render";
|
|
9
5
|
import { ColumnCollectionBuilder } from "../../columns/column_collection_builder";
|
|
10
6
|
import { collectCtxColumnSnapshotProviders } from "../../columns/ctx_column_sources";
|
|
7
|
+
import type { DatasetOption } from "./dataset_selection";
|
|
11
8
|
import { buildRefMap, filterMatchesToOptions, findFilterColumns } from "./filter_discovery";
|
|
9
|
+
import { enrichmentVariantsToRefs, findEnrichmentColumns } from "./enrichment_discovery";
|
|
12
10
|
|
|
13
11
|
export type BuildDatasetOptions = {
|
|
14
12
|
/** Which result pool columns qualify as datasets. Defaults to all. */
|
|
15
|
-
|
|
13
|
+
primary?: MultiColumnSelector | MultiColumnSelector[] | ((spec: PObjectSpec) => boolean);
|
|
16
14
|
/** Formatting options for filter labels. */
|
|
17
15
|
labelOptions?: DeriveLabelsOptions;
|
|
16
|
+
/**
|
|
17
|
+
* Enables enrichment discovery and filters hits attached to
|
|
18
|
+
* `DatasetOption.enrichments`. Use `() => true` to accept all; omit to disable.
|
|
19
|
+
*/
|
|
20
|
+
withEnrichments?: MultiColumnSelector | MultiColumnSelector[] | ((spec: PObjectSpec) => boolean);
|
|
21
|
+
/** Maximum linker hops considered. Only used when `withEnrichments` is set. */
|
|
22
|
+
enrichmentMaxHops?: number;
|
|
18
23
|
};
|
|
19
24
|
|
|
20
25
|
/**
|
|
@@ -27,28 +32,54 @@ export function buildDatasetOptions(
|
|
|
27
32
|
ctx: RenderCtxBase,
|
|
28
33
|
opts?: BuildDatasetOptions,
|
|
29
34
|
): DatasetOption[] | undefined {
|
|
30
|
-
const
|
|
31
|
-
const
|
|
35
|
+
const primary = opts?.primary;
|
|
36
|
+
const primaryPredicate =
|
|
37
|
+
primary === undefined
|
|
38
|
+
? () => true
|
|
39
|
+
: typeof primary === "function"
|
|
40
|
+
? primary
|
|
41
|
+
: multiColumnSelectorsToPredicate(primary);
|
|
42
|
+
const options = ctx.resultPool.getOptions(primaryPredicate, { refsWithEnrichments: true });
|
|
32
43
|
if (options.length === 0) return [];
|
|
33
44
|
|
|
34
45
|
const columnSources = collectCtxColumnSnapshotProviders(ctx);
|
|
35
46
|
const refMap = buildRefMap(ctx.resultPool.getSpecs().entries);
|
|
36
47
|
const pframeSpec = ctx.getService("pframeSpec");
|
|
37
48
|
|
|
38
|
-
return options.map((
|
|
39
|
-
const datasetSpec = ctx.resultPool.getPColumnSpecByRef(
|
|
40
|
-
if (!datasetSpec) return
|
|
49
|
+
return options.map((primary: Option): DatasetOption => {
|
|
50
|
+
const datasetSpec = ctx.resultPool.getPColumnSpecByRef(primary.ref);
|
|
51
|
+
if (!datasetSpec) return { primary };
|
|
41
52
|
|
|
42
53
|
const builder = new ColumnCollectionBuilder(pframeSpec);
|
|
43
54
|
for (const src of columnSources) builder.addSource(src);
|
|
44
55
|
const collection = builder.build({ anchors: { main: datasetSpec } });
|
|
45
|
-
if (!collection) return
|
|
56
|
+
if (!collection) return { primary };
|
|
46
57
|
|
|
47
58
|
try {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
const filterMatches = findFilterColumns(collection);
|
|
60
|
+
const filters =
|
|
61
|
+
filterMatches.length === 0
|
|
62
|
+
? undefined
|
|
63
|
+
: filterMatchesToOptions(filterMatches, refMap, opts?.labelOptions);
|
|
64
|
+
|
|
65
|
+
let enrichments;
|
|
66
|
+
if (opts?.withEnrichments !== undefined) {
|
|
67
|
+
const enrichmentVariants = findEnrichmentColumns(collection, {
|
|
68
|
+
maxHops: opts.enrichmentMaxHops,
|
|
69
|
+
...(typeof opts.withEnrichments === "function"
|
|
70
|
+
? { predicate: opts.withEnrichments }
|
|
71
|
+
: { include: opts.withEnrichments }),
|
|
72
|
+
});
|
|
73
|
+
if (enrichmentVariants.length > 0) {
|
|
74
|
+
enrichments = enrichmentVariantsToRefs(enrichmentVariants, opts.labelOptions);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
primary,
|
|
80
|
+
...(filters !== undefined && filters.length > 0 ? { filters } : {}),
|
|
81
|
+
...(enrichments !== undefined && enrichments.length > 0 ? { enrichments } : {}),
|
|
82
|
+
};
|
|
52
83
|
} finally {
|
|
53
84
|
collection.dispose();
|
|
54
85
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { LabeledEnrichmentRefs, Option, PrimaryRef } from "@milaboratories/pl-model-common";
|
|
2
|
+
|
|
3
|
+
/** Dataset picker entry: user picks {@link primary}, gets {@link enrichments} attached. */
|
|
4
|
+
export type DatasetOption = {
|
|
5
|
+
readonly primary: Option;
|
|
6
|
+
readonly filters?: readonly Option[];
|
|
7
|
+
readonly enrichments?: LabeledEnrichmentRefs;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Picked dataset bundle emitted by `PlDatasetSelector`. Stored opaquely in
|
|
12
|
+
* block data; block authors unbundle inside their args resolver.
|
|
13
|
+
*/
|
|
14
|
+
export type DatasetSelection = {
|
|
15
|
+
readonly __isDatasetSelection: "v1";
|
|
16
|
+
readonly primary: PrimaryRef;
|
|
17
|
+
readonly enrichments?: LabeledEnrichmentRefs;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function isDatasetSelection(value: unknown): value is DatasetSelection {
|
|
21
|
+
return (
|
|
22
|
+
typeof value === "object" &&
|
|
23
|
+
value !== null &&
|
|
24
|
+
(value as { __isDatasetSelection?: unknown }).__isDatasetSelection === "v1" &&
|
|
25
|
+
"primary" in value
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function createDatasetSelection(
|
|
30
|
+
primary: PrimaryRef,
|
|
31
|
+
enrichments?: LabeledEnrichmentRefs,
|
|
32
|
+
): DatasetSelection {
|
|
33
|
+
if (enrichments !== undefined && enrichments.length > 0) {
|
|
34
|
+
return { __isDatasetSelection: "v1", primary, enrichments };
|
|
35
|
+
}
|
|
36
|
+
return { __isDatasetSelection: "v1", primary };
|
|
37
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Annotation, createEnrichmentRef } from "@milaboratories/pl-model-common";
|
|
2
|
+
import type {
|
|
3
|
+
EnrichmentStep,
|
|
4
|
+
LabeledEnrichmentRef,
|
|
5
|
+
LabeledEnrichmentRefs,
|
|
6
|
+
MultiColumnSelector,
|
|
7
|
+
PObjectId,
|
|
8
|
+
PObjectSpec,
|
|
9
|
+
} from "@milaboratories/pl-model-common";
|
|
10
|
+
import type {
|
|
11
|
+
AnchoredColumnCollection,
|
|
12
|
+
ColumnVariant,
|
|
13
|
+
} from "../../columns/column_collection_builder";
|
|
14
|
+
import {
|
|
15
|
+
deriveDistinctLabels,
|
|
16
|
+
type DeriveLabelsOptions,
|
|
17
|
+
type Entry,
|
|
18
|
+
} from "../../labels/derive_distinct_labels";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* True for global-form ids — `canonicalize({__isRef: true, blockId, name})` —
|
|
22
|
+
* which the workflow can resolve via bquery. Local-form ids (`resolvePath`)
|
|
23
|
+
* fail this check and are excluded from auto-discovery; prerun/outputs hops
|
|
24
|
+
* must be supplied as resolved `{spec, data}` instead.
|
|
25
|
+
*/
|
|
26
|
+
function isGloballyAddressable(id: PObjectId): boolean {
|
|
27
|
+
try {
|
|
28
|
+
const decoded = JSON.parse(id);
|
|
29
|
+
return (
|
|
30
|
+
typeof decoded === "object" &&
|
|
31
|
+
decoded !== null &&
|
|
32
|
+
decoded.__isRef === true &&
|
|
33
|
+
typeof decoded.blockId === "string" &&
|
|
34
|
+
typeof decoded.name === "string"
|
|
35
|
+
);
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Linker-reached hits attached to the anchor primary. Drops zero-hop variants
|
|
43
|
+
* (filters / the primary itself) and structural hits (subset, linker, label
|
|
44
|
+
* columns). Narrow further with `include` selectors or a `predicate`.
|
|
45
|
+
*/
|
|
46
|
+
export function findEnrichmentColumns(
|
|
47
|
+
collection: AnchoredColumnCollection,
|
|
48
|
+
options?: {
|
|
49
|
+
maxHops?: number;
|
|
50
|
+
include?: MultiColumnSelector | MultiColumnSelector[];
|
|
51
|
+
predicate?: (spec: PObjectSpec) => boolean;
|
|
52
|
+
},
|
|
53
|
+
): ColumnVariant[] {
|
|
54
|
+
const include =
|
|
55
|
+
options?.include === undefined
|
|
56
|
+
? undefined
|
|
57
|
+
: Array.isArray(options.include)
|
|
58
|
+
? options.include
|
|
59
|
+
: [options.include];
|
|
60
|
+
const variants = collection.findColumnVariants({
|
|
61
|
+
mode: "enrichment",
|
|
62
|
+
maxHops: options?.maxHops ?? 4,
|
|
63
|
+
include,
|
|
64
|
+
exclude: [
|
|
65
|
+
{ annotations: { [Annotation.IsSubset]: "true" } },
|
|
66
|
+
{ annotations: { [Annotation.IsLinkerColumn]: "true" } },
|
|
67
|
+
{ name: Annotation.Label },
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
const predicate = options?.predicate;
|
|
71
|
+
return variants.filter((v) => {
|
|
72
|
+
if (v.path.length === 0) return false;
|
|
73
|
+
if (predicate !== undefined && !predicate(v.column.spec)) return false;
|
|
74
|
+
if (!isGloballyAddressable(v.column.id)) return false;
|
|
75
|
+
if (v.path.some((p) => !isGloballyAddressable(p.linker.id))) return false;
|
|
76
|
+
return true;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Pair each variant with a path-disambiguated label (so export headers stay
|
|
82
|
+
* unique) and carry hit/linker `PObjectId`s through verbatim. Propagates
|
|
83
|
+
* `qualifications.forHit`; `forQueries` is re-derived by the table builder.
|
|
84
|
+
*/
|
|
85
|
+
export function enrichmentVariantsToRefs(
|
|
86
|
+
variants: ColumnVariant[],
|
|
87
|
+
labelOptions?: DeriveLabelsOptions,
|
|
88
|
+
): LabeledEnrichmentRefs {
|
|
89
|
+
if (variants.length === 0) return [];
|
|
90
|
+
|
|
91
|
+
const entries: Entry[] = variants.map((variant) => ({
|
|
92
|
+
spec: variant.column.spec,
|
|
93
|
+
linkerPath: variant.path.map((p) => ({ spec: p.linker.spec })),
|
|
94
|
+
qualifications: variant.qualifications,
|
|
95
|
+
}));
|
|
96
|
+
const labels = deriveDistinctLabels(entries, labelOptions);
|
|
97
|
+
|
|
98
|
+
return variants.map((variant, i): LabeledEnrichmentRef => {
|
|
99
|
+
const path: EnrichmentStep[] = variant.path.map((step) => ({
|
|
100
|
+
type: "linker",
|
|
101
|
+
linker: step.linker.id,
|
|
102
|
+
}));
|
|
103
|
+
return {
|
|
104
|
+
ref: createEnrichmentRef(variant.column.id, {
|
|
105
|
+
path,
|
|
106
|
+
qualifications: variant.qualifications.forHit,
|
|
107
|
+
}),
|
|
108
|
+
label: labels[i],
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
}
|
|
@@ -34,12 +34,8 @@ function linkerSnapshot(name: string, label?: string): ColumnSnapshot<PObjectId>
|
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function pathStep(
|
|
38
|
-
|
|
39
|
-
qualifications: AxisQualification[],
|
|
40
|
-
label?: string,
|
|
41
|
-
): MatchVariant["path"][number] {
|
|
42
|
-
return { linker: linkerSnapshot(linkerName, label), qualifications };
|
|
37
|
+
function pathStep(linkerName: string, label?: string): MatchVariant["path"][number] {
|
|
38
|
+
return { linker: linkerSnapshot(linkerName, label) };
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
describe("deriveDistinctTooltips", () => {
|
|
@@ -63,16 +59,13 @@ describe("deriveDistinctTooltips", () => {
|
|
|
63
59
|
const entries: TooltipEntry[] = [
|
|
64
60
|
{
|
|
65
61
|
spec: createSpec("hit_col", "Hit Col"),
|
|
66
|
-
linkerPath: [
|
|
67
|
-
pathStep("linker_a", [axisQualification("sample", { batch: "A" })], "Linker A"),
|
|
68
|
-
],
|
|
62
|
+
linkerPath: [pathStep("linker_a", "Linker A")],
|
|
69
63
|
},
|
|
70
64
|
];
|
|
71
65
|
const [tooltip] = deriveDistinctTooltips(entries);
|
|
72
66
|
expect(tooltip).toBeDefined();
|
|
73
67
|
expect(tooltip).toContain("Origin path");
|
|
74
68
|
expect(tooltip).toContain("linker 1: Linker A");
|
|
75
|
-
expect(tooltip).toContain("qualifies: sample context: batch=A");
|
|
76
69
|
expect(tooltip).toContain("hit column: Hit Col");
|
|
77
70
|
});
|
|
78
71
|
|
|
@@ -146,7 +139,7 @@ describe("deriveDistinctTooltips", () => {
|
|
|
146
139
|
{
|
|
147
140
|
spec: createSpec("col1", "Col 1"),
|
|
148
141
|
qualifications: { forQueries: {}, forHit: [] },
|
|
149
|
-
linkerPath: [pathStep("linker_a",
|
|
142
|
+
linkerPath: [pathStep("linker_a", "Linker A")],
|
|
150
143
|
},
|
|
151
144
|
];
|
|
152
145
|
const [tooltip] = deriveDistinctTooltips(entries);
|
|
@@ -157,10 +150,7 @@ describe("deriveDistinctTooltips", () => {
|
|
|
157
150
|
const entries: TooltipEntry[] = [
|
|
158
151
|
{
|
|
159
152
|
spec: createSpec("hit_col", "Hit Col"),
|
|
160
|
-
linkerPath: [
|
|
161
|
-
pathStep("linker_a", [], "Linker A"),
|
|
162
|
-
pathStep("linker_b", [axisQualification("sample", { batch: "B" })], "Linker B"),
|
|
163
|
-
],
|
|
153
|
+
linkerPath: [pathStep("linker_a", "Linker A"), pathStep("linker_b", "Linker B")],
|
|
164
154
|
},
|
|
165
155
|
];
|
|
166
156
|
const [tooltip] = deriveDistinctTooltips(entries);
|
|
@@ -174,7 +164,7 @@ describe("deriveDistinctTooltips", () => {
|
|
|
174
164
|
spec: createSpec("hit_col", "Hit"),
|
|
175
165
|
variantIndex: 2,
|
|
176
166
|
variantCount: 2,
|
|
177
|
-
linkerPath: [pathStep("linker_a",
|
|
167
|
+
linkerPath: [pathStep("linker_a", "LA")],
|
|
178
168
|
qualifications: {
|
|
179
169
|
forQueries: { ["main" as PObjectId]: [axisQualification("sample", { batch: "B" })] },
|
|
180
170
|
forHit: [axisQualification("sample", { batch: "B" })],
|
|
@@ -46,7 +46,6 @@ function formatTooltip(entry: TooltipEntry): undefined | string {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const BULLET_1 = " • ";
|
|
49
|
-
const SUB_BULLET = " ";
|
|
50
49
|
|
|
51
50
|
function formatHeader(entry: TooltipEntry): undefined | string {
|
|
52
51
|
const lines: string[] = [];
|
|
@@ -67,8 +66,6 @@ function formatOriginPath(entry: TooltipEntry): undefined | string {
|
|
|
67
66
|
readAnnotation(step.linker.spec, Annotation.Label) ??
|
|
68
67
|
step.linker.spec.name;
|
|
69
68
|
lines.push(`${BULLET_1}linker ${i + 1}: ${label}`);
|
|
70
|
-
const qs = formatAxisQualifications(step.qualifications);
|
|
71
|
-
if (qs !== undefined) lines.push(`${SUB_BULLET}qualifies: ${qs}`);
|
|
72
69
|
});
|
|
73
70
|
const hitName = readAnnotation(entry.spec, Annotation.Label) ?? entry.spec.name;
|
|
74
71
|
lines.push(`${BULLET_1}hit column: ${hitName}`);
|