@platforma-sdk/model 1.60.2 → 1.61.1
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/block_model.cjs +3 -1
- package/dist/block_model.cjs.map +1 -1
- package/dist/block_model.js +3 -1
- package/dist/block_model.js.map +1 -1
- package/dist/columns/column_collection_builder.cjs +15 -12
- package/dist/columns/column_collection_builder.cjs.map +1 -1
- package/dist/columns/column_collection_builder.d.ts +4 -2
- package/dist/columns/column_collection_builder.js +15 -12
- package/dist/columns/column_collection_builder.js.map +1 -1
- package/dist/columns/column_selector.cjs.map +1 -1
- package/dist/columns/column_selector.d.ts +3 -3
- package/dist/columns/column_selector.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/package.cjs +1 -1
- package/dist/package.js +1 -1
- package/dist/platforma.d.ts +3 -1
- package/dist/plugin_model.cjs +48 -2
- package/dist/plugin_model.cjs.map +1 -1
- package/dist/plugin_model.d.ts +43 -4
- package/dist/plugin_model.js +48 -2
- package/dist/plugin_model.js.map +1 -1
- package/dist/render/api.cjs +19 -10
- package/dist/render/api.cjs.map +1 -1
- package/dist/render/api.d.ts +8 -7
- package/dist/render/api.js +19 -10
- package/dist/render/api.js.map +1 -1
- package/dist/render/internal.cjs.map +1 -1
- package/dist/render/internal.d.ts +10 -2
- package/dist/render/internal.js.map +1 -1
- package/package.json +8 -7
- package/src/block_model.ts +2 -0
- package/src/columns/column_collection_builder.test.ts +24 -40
- package/src/columns/column_collection_builder.ts +17 -15
- package/src/columns/column_selector.ts +6 -5
- package/src/index.ts +1 -0
- package/src/platforma.ts +1 -1
- package/src/plugin_model.ts +74 -3
- package/src/render/api.ts +33 -13
- package/src/render/internal.ts +18 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.js","names":[],"sources":["../../src/render/internal.ts"],"sourcesContent":["import type { Optional } from \"utility-types\";\nimport type {\n Branded,\n DiscoverColumnsRequest,\n DiscoverColumnsResponse,\n StringifiedJson,\n} from \"@milaboratories/pl-model-common\";\nimport type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from \"./traversal_ops\";\nimport type {\n ArchiveFormat,\n AnyFunction,\n Option,\n PColumn,\n PColumnValues,\n PFrameDef,\n PFrameHandle,\n PObject,\n PObjectSpec,\n PSpecPredicate,\n PTableDef,\n PTableDefV2,\n PTableHandle,\n ResultCollection,\n ValueOrError,\n DataInfo,\n RangeBytes,\n PColumnSpec,\n} from \"@milaboratories/pl-model-common\";\nimport type { TreeNodeAccessor } from \"./accessor\";\n\nexport const StagingAccessorName = \"staging\";\nexport const MainAccessorName = \"main\";\n\nexport type AccessorHandle = Branded<string, \"AccessorHandle\">;\nexport type FutureHandle = Branded<string, \"FutureHandle\">;\n\nexport type PColumnDataUniversal<TreeEntry = TreeNodeAccessor> =\n | TreeEntry\n | DataInfo<TreeEntry>\n | PColumnValues;\n\nexport interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = FutureHandle> {\n //\n // Root accessor creation\n //\n\n getAccessorHandleByName(name: string): AHandle | undefined;\n\n //\n // Basic resource accessor actions\n //\n\n resolveWithCommon(\n handle: AHandle,\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): AHandle | undefined;\n\n getResourceType(handle: AHandle): ResourceType;\n\n getInputsLocked(handle: AHandle): boolean;\n\n getOutputsLocked(handle: AHandle): boolean;\n\n getIsReadyOrError(handle: AHandle): boolean;\n\n getIsFinal(handle: AHandle): boolean;\n\n getError(handle: AHandle): AHandle | undefined;\n\n listInputFields(handle: AHandle): string[];\n\n listOutputFields(handle: AHandle): string[];\n\n listDynamicFields(handle: AHandle): string[];\n\n getKeyValueBase64(handle: AHandle, key: string): string | undefined;\n\n getKeyValueAsString(handle: AHandle, key: string): string | undefined;\n\n getDataBase64(handle: AHandle): string | undefined;\n\n getDataAsString(handle: AHandle): string | undefined;\n\n /** If not final returns undefined */\n parsePObjectCollection(\n handle: AHandle,\n errorOnUnknownField: boolean,\n prefix: string,\n ...resolvePath: string[]\n ): Record<string, PObject<AHandle>> | undefined;\n\n //\n // Blob\n //\n\n getBlobContentAsBase64(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getBlobContentAsString(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getDownloadedBlobContentHandle(handle: AHandle): FHandle; // LocalBlobHandleAndSize | undefined;\n\n getOnDemandBlobContentHandle(handle: AHandle): FHandle; // RemoteBlobHandleAndSize | undefined;\n\n //\n // Blobs to URLs\n //\n\n extractArchiveAndGetURL(handle: AHandle, format: ArchiveFormat): FHandle;\n\n //\n // Import progress\n //\n\n getImportProgress(handle: AHandle): FHandle; // ImportProgress;\n\n //\n // Logs\n //\n\n getLastLogs(handle: AHandle, nLines: number): FHandle; // string | undefined;\n\n getProgressLog(handle: AHandle, patternToSearch: string): FHandle; // string | undefined;\n\n getProgressLogWithInfo(handle: AHandle, patternToSearch: string): FHandle; // ProgressLogWithInfo | undefined;\n\n getLogHandle(handle: AHandle): FHandle; // AnyLogHandle | undefined;\n\n //\n // Blocks\n //\n\n /** @deprecated at some point will stop working and will return dummy values */\n getBlockLabel(blockId: string): string;\n\n //\n // Result Pool\n //\n\n getDataFromResultPool(): ResultCollection<PObject<AHandle>>;\n\n getDataWithErrorsFromResultPool(): ResultCollection<\n Optional<PObject<ValueOrError<AHandle, Error>>, \"id\">\n >;\n\n getSpecsFromResultPool(): ResultCollection<PObjectSpec>;\n\n getSpecFromResultPoolByRef(blockId: string, exportName: string): PObjectSpec | undefined;\n\n getDataFromResultPoolByRef(blockId: string, exportName: string): PObject<AHandle> | undefined;\n\n calculateOptions(predicate: PSpecPredicate): Option[];\n\n //\n // PFrame / PTable\n //\n\n createPFrame(def: PFrameDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PFrameHandle;\n\n createPTable(def: PTableDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PTableHandle;\n\n createPTableV2(\n def: PTableDefV2<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>,\n ): PTableHandle;\n\n //\n // Spec Frames (synchronous WASM-based PFrame for spec-level operations)\n //\n\n createSpecFrame(specs: Record<string, PColumnSpec>): string;\n\n specFrameDiscoverColumns(\n handle: string,\n request: DiscoverColumnsRequest,\n ): DiscoverColumnsResponse;\n\n
|
|
1
|
+
{"version":3,"file":"internal.js","names":[],"sources":["../../src/render/internal.ts"],"sourcesContent":["import type { Optional } from \"utility-types\";\nimport type {\n AxesId,\n AxesSpec,\n Branded,\n DiscoverColumnsRequest,\n DiscoverColumnsResponse,\n PTableColumnId,\n PTableColumnSpec,\n SingleAxisSelector,\n StringifiedJson,\n} from \"@milaboratories/pl-model-common\";\nimport type { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from \"./traversal_ops\";\nimport type {\n ArchiveFormat,\n AnyFunction,\n Option,\n PColumn,\n PColumnValues,\n PFrameDef,\n PFrameHandle,\n PObject,\n PObjectSpec,\n PSpecPredicate,\n PTableDef,\n PTableDefV2,\n PTableHandle,\n ResultCollection,\n ValueOrError,\n DataInfo,\n RangeBytes,\n PColumnSpec,\n} from \"@milaboratories/pl-model-common\";\nimport type { TreeNodeAccessor } from \"./accessor\";\n\nexport const StagingAccessorName = \"staging\";\nexport const MainAccessorName = \"main\";\n\nexport type AccessorHandle = Branded<string, \"AccessorHandle\">;\nexport type FutureHandle = Branded<string, \"FutureHandle\">;\n\nexport type PColumnDataUniversal<TreeEntry = TreeNodeAccessor> =\n | TreeEntry\n | DataInfo<TreeEntry>\n | PColumnValues;\n\nexport interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = FutureHandle> {\n //\n // Root accessor creation\n //\n\n getAccessorHandleByName(name: string): AHandle | undefined;\n\n //\n // Basic resource accessor actions\n //\n\n resolveWithCommon(\n handle: AHandle,\n commonOptions: CommonFieldTraverseOps,\n ...steps: (FieldTraversalStep | string)[]\n ): AHandle | undefined;\n\n getResourceType(handle: AHandle): ResourceType;\n\n getInputsLocked(handle: AHandle): boolean;\n\n getOutputsLocked(handle: AHandle): boolean;\n\n getIsReadyOrError(handle: AHandle): boolean;\n\n getIsFinal(handle: AHandle): boolean;\n\n getError(handle: AHandle): AHandle | undefined;\n\n listInputFields(handle: AHandle): string[];\n\n listOutputFields(handle: AHandle): string[];\n\n listDynamicFields(handle: AHandle): string[];\n\n getKeyValueBase64(handle: AHandle, key: string): string | undefined;\n\n getKeyValueAsString(handle: AHandle, key: string): string | undefined;\n\n getDataBase64(handle: AHandle): string | undefined;\n\n getDataAsString(handle: AHandle): string | undefined;\n\n /** If not final returns undefined */\n parsePObjectCollection(\n handle: AHandle,\n errorOnUnknownField: boolean,\n prefix: string,\n ...resolvePath: string[]\n ): Record<string, PObject<AHandle>> | undefined;\n\n //\n // Blob\n //\n\n getBlobContentAsBase64(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getBlobContentAsString(handle: AHandle, range?: RangeBytes): FHandle; // string | undefined\n\n getDownloadedBlobContentHandle(handle: AHandle): FHandle; // LocalBlobHandleAndSize | undefined;\n\n getOnDemandBlobContentHandle(handle: AHandle): FHandle; // RemoteBlobHandleAndSize | undefined;\n\n //\n // Blobs to URLs\n //\n\n extractArchiveAndGetURL(handle: AHandle, format: ArchiveFormat): FHandle;\n\n //\n // Import progress\n //\n\n getImportProgress(handle: AHandle): FHandle; // ImportProgress;\n\n //\n // Logs\n //\n\n getLastLogs(handle: AHandle, nLines: number): FHandle; // string | undefined;\n\n getProgressLog(handle: AHandle, patternToSearch: string): FHandle; // string | undefined;\n\n getProgressLogWithInfo(handle: AHandle, patternToSearch: string): FHandle; // ProgressLogWithInfo | undefined;\n\n getLogHandle(handle: AHandle): FHandle; // AnyLogHandle | undefined;\n\n //\n // Blocks\n //\n\n /** @deprecated at some point will stop working and will return dummy values */\n getBlockLabel(blockId: string): string;\n\n //\n // Result Pool\n //\n\n getDataFromResultPool(): ResultCollection<PObject<AHandle>>;\n\n getDataWithErrorsFromResultPool(): ResultCollection<\n Optional<PObject<ValueOrError<AHandle, Error>>, \"id\">\n >;\n\n getSpecsFromResultPool(): ResultCollection<PObjectSpec>;\n\n getSpecFromResultPoolByRef(blockId: string, exportName: string): PObjectSpec | undefined;\n\n getDataFromResultPoolByRef(blockId: string, exportName: string): PObject<AHandle> | undefined;\n\n calculateOptions(predicate: PSpecPredicate): Option[];\n\n //\n // PFrame / PTable\n //\n\n createPFrame(def: PFrameDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PFrameHandle;\n\n createPTable(def: PTableDef<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>): PTableHandle;\n\n createPTableV2(\n def: PTableDefV2<PColumn<AHandle | PColumnValues | DataInfo<AHandle>>>,\n ): PTableHandle;\n\n //\n // Spec Frames (synchronous WASM-based PFrame for spec-level operations)\n //\n\n createSpecFrame(specs: Record<string, PColumnSpec>): string;\n\n specFrameDiscoverColumns(\n handle: string,\n request: DiscoverColumnsRequest,\n ): DiscoverColumnsResponse;\n\n disposeSpecFrame(handle: string): void;\n\n /** Expand index-based parentAxes in AxesSpec to resolved AxisId parents in AxesId. */\n expandAxes(spec: AxesSpec): AxesId;\n\n /** Collapse resolved AxisId parents back to index-based parentAxes in AxesSpec. */\n collapseAxes(ids: AxesId): AxesSpec;\n\n /** Find the index of an axis matching the given selector. Returns -1 if not found. */\n findAxis(spec: AxesSpec, selector: SingleAxisSelector): number;\n\n /** Find the flat index of a table column matching the given selector. Returns -1 if not found. */\n findTableColumn(tableSpec: PTableColumnSpec[], selector: PTableColumnId): number;\n\n //\n // Computable\n //\n\n getCurrentUnstableMarker(): string | undefined;\n\n //\n // Logging\n //\n\n logInfo(message: string): void;\n\n logWarn(message: string): void;\n\n logError(message: string): void;\n}\n\nexport const GlobalCfgRenderCtxFeatureFlags = {\n explicitColumnsSupport: true as const,\n inlineColumnsSupport: true as const,\n activeArgs: true as const,\n pTablePartitionFiltersSupport: true as const,\n pFrameInSetFilterSupport: true as const,\n};\n\nexport interface GlobalCfgRenderCtx extends GlobalCfgRenderCtxMethods {\n //\n // State: Args, UI State, Active Args\n //\n // Old runtime injects these values as strings, new runtime injects them as functions\n // that return strings, if block declares supportsLazyState flag.\n // If function not called in lazy state API, then resulting output will not depend on these values,\n // and thus will not be recalculated on corresponding state change.\n //\n\n readonly args: string | (() => string);\n /** @deprecated Use `data` instead. Optional for backward compatibility - falls back to `data` if not injected. */\n readonly uiState?: string | (() => string);\n readonly data: string | (() => string);\n readonly activeArgs: undefined | string | (() => string | undefined);\n\n readonly blockStorage: () => StringifiedJson;\n\n // Note: strings below are used because, anyway, using strings is the only way\n // to get data inside the QuickJS context, as it is implemented now. With this\n // approach deserialization can be lazily postponed until it is actually needed.\n readonly callbackRegistry: Record<string, AnyFunction>;\n readonly featureFlags?: typeof GlobalCfgRenderCtxFeatureFlags;\n}\n\nexport type FutureAwait = {\n __awaited_futures__: FutureHandle[];\n};\n\nexport function isFutureAwait(obj: unknown): obj is FutureAwait {\n return typeof obj === \"object\" && obj !== null && \"__awaited_futures__\" in obj;\n}\n\nfunction addAllFutureAwaits(set: Set<string>, visited: Set<unknown>, node: unknown) {\n if (visited.has(node)) return;\n visited.add(node);\n\n const type = typeof node;\n if (type === \"object\") {\n if (isFutureAwait(node)) node.__awaited_futures__.forEach((a) => set.add(a));\n else if (Array.isArray(node))\n for (const nested of node) addAllFutureAwaits(set, visited, nested);\n else\n for (const [, nested] of Object.entries(node as object))\n if (nested !== node) addAllFutureAwaits(set, visited, nested);\n }\n}\n\nexport function getAllFutureAwaits(obj: unknown): Set<string> {\n const set = new Set<string>();\n addAllFutureAwaits(set, new Set(), obj);\n return set;\n}\n"],"mappings":";;;;;;;;;;AAmCA,MAAa,sBAAsB;AACnC,MAAa,mBAAmB;AAgLhC,MAAa,iCAAiC;CAC5C,wBAAwB;CACxB,sBAAsB;CACtB,YAAY;CACZ,+BAA+B;CAC/B,0BAA0B;CAC3B;AA+BD,SAAgB,cAAc,KAAkC;AAC9D,QAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,yBAAyB;;AAG7E,SAAS,mBAAmB,KAAkB,SAAuB,MAAe;AAClF,KAAI,QAAQ,IAAI,KAAK,CAAE;AACvB,SAAQ,IAAI,KAAK;AAGjB,KADa,OAAO,SACP,UACX;MAAI,cAAc,KAAK,CAAE,MAAK,oBAAoB,SAAS,MAAM,IAAI,IAAI,EAAE,CAAC;WACnE,MAAM,QAAQ,KAAK,CAC1B,MAAK,MAAM,UAAU,KAAM,oBAAmB,KAAK,SAAS,OAAO;MAEnE,MAAK,MAAM,GAAG,WAAW,OAAO,QAAQ,KAAe,CACrD,KAAI,WAAW,KAAM,oBAAmB,KAAK,SAAS,OAAO;;;AAIrE,SAAgB,mBAAmB,KAA2B;CAC5D,MAAM,sBAAM,IAAI,KAAa;AAC7B,oBAAmB,qBAAK,IAAI,KAAK,EAAE,IAAI;AACvC,QAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/model",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.61.1",
|
|
4
4
|
"description": "Platforma.bio SDK / Block Model",
|
|
5
5
|
"files": [
|
|
6
6
|
"./dist/**/*",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"fast-json-patch": "^3.1.1",
|
|
31
31
|
"utility-types": "^3.11.0",
|
|
32
32
|
"zod": "~3.23.8",
|
|
33
|
-
"@milaboratories/pl-model-common": "1.28.0",
|
|
34
|
-
"@milaboratories/pl-error-like": "1.12.9",
|
|
35
|
-
"@milaboratories/ptabler-expression-js": "1.2.1",
|
|
36
33
|
"@milaboratories/helpers": "1.14.0",
|
|
37
|
-
"@milaboratories/pl-model-
|
|
34
|
+
"@milaboratories/pl-model-common": "1.29.0",
|
|
35
|
+
"@milaboratories/pl-model-middle-layer": "1.16.0",
|
|
36
|
+
"@milaboratories/ptabler-expression-js": "1.2.2",
|
|
37
|
+
"@milaboratories/pl-error-like": "1.12.9"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@vitest/coverage-istanbul": "^4.0.18",
|
|
@@ -42,9 +42,10 @@
|
|
|
42
42
|
"typescript": "~5.9.3",
|
|
43
43
|
"vitest": "^4.0.18",
|
|
44
44
|
"@milaboratories/build-configs": "1.5.2",
|
|
45
|
+
"@milaboratories/pf-spec-driver": "1.1.0",
|
|
46
|
+
"@milaboratories/pf-driver": "1.2.0",
|
|
45
47
|
"@milaboratories/ts-configs": "1.2.2",
|
|
46
|
-
"@milaboratories/ts-builder": "1.3.0"
|
|
47
|
-
"@milaboratories/pf-driver": "1.1.1"
|
|
48
|
+
"@milaboratories/ts-builder": "1.3.0"
|
|
48
49
|
},
|
|
49
50
|
"scripts": {
|
|
50
51
|
"build": "ts-builder build --target node",
|
package/src/block_model.ts
CHANGED
|
@@ -549,11 +549,13 @@ export class BlockModelV3<
|
|
|
549
549
|
|
|
550
550
|
// Register plugin outputs (in config pack, evaluated by middle layer)
|
|
551
551
|
const outputs = model.outputs as Record<string, (ctx: PluginRenderCtx) => unknown>;
|
|
552
|
+
const { outputFlags } = model;
|
|
552
553
|
for (const [outputKey, outputFn] of Object.entries(outputs)) {
|
|
553
554
|
const key = pluginOutputKey(handle, outputKey);
|
|
554
555
|
pluginOutputs[key] = createAndRegisterRenderLambda({
|
|
555
556
|
handle: key,
|
|
556
557
|
lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs)),
|
|
558
|
+
withStatus: outputFlags[outputKey]?.withStatus,
|
|
557
559
|
});
|
|
558
560
|
}
|
|
559
561
|
}
|
|
@@ -5,44 +5,26 @@ import type {
|
|
|
5
5
|
SUniversalPColumnId,
|
|
6
6
|
} from "@milaboratories/pl-model-common";
|
|
7
7
|
import { AnchoredIdDeriver } from "@milaboratories/pl-model-common";
|
|
8
|
+
import { SpecDriver } from "@milaboratories/pf-spec-driver";
|
|
8
9
|
|
|
9
|
-
import { describe, expect, test } from "vitest";
|
|
10
|
+
import { afterEach, describe, expect, test } from "vitest";
|
|
10
11
|
import type { ColumnSnapshotProvider } from "./column_snapshot_provider";
|
|
11
12
|
import type { ColumnSnapshot } from "./column_snapshot";
|
|
12
13
|
import { ColumnCollectionBuilder } from "./column_collection_builder";
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
const drivers: SpecDriver[] = [];
|
|
15
16
|
|
|
16
17
|
function createSpecFrameCtx() {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
createSpecFrame: (specs: Record<string, PColumnSpec>) => {
|
|
22
|
-
const handle = `frame-${nextId++}`;
|
|
23
|
-
frames.set(handle, specs);
|
|
24
|
-
return handle;
|
|
25
|
-
},
|
|
26
|
-
specFrameDiscoverColumns: (handle: string, _request: any) => {
|
|
27
|
-
const specs = frames.get(handle)!;
|
|
28
|
-
return {
|
|
29
|
-
hits: Object.entries(specs).map(([columnId, spec]) => ({
|
|
30
|
-
hit: { columnId: columnId as PObjectId, spec },
|
|
31
|
-
mappingVariants: [
|
|
32
|
-
{
|
|
33
|
-
qualifications: { forQueries: [], forHit: [] },
|
|
34
|
-
distinctiveQualifications: { forQueries: [], forHit: [] },
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
})),
|
|
38
|
-
};
|
|
39
|
-
},
|
|
40
|
-
specFrameDispose: (handle: string) => {
|
|
41
|
-
frames.delete(handle);
|
|
42
|
-
},
|
|
43
|
-
};
|
|
18
|
+
const driver = new SpecDriver();
|
|
19
|
+
drivers.push(driver);
|
|
20
|
+
return driver;
|
|
44
21
|
}
|
|
45
22
|
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
for (const driver of drivers) driver.dispose();
|
|
25
|
+
drivers.length = 0;
|
|
26
|
+
});
|
|
27
|
+
|
|
46
28
|
// --- Helpers ---
|
|
47
29
|
|
|
48
30
|
/** Default axis used when none specified — WASM requires at least one axis. */
|
|
@@ -173,15 +155,16 @@ describe("ColumnCollection.findColumns", () => {
|
|
|
173
155
|
expect(collection.findColumns()).toHaveLength(2);
|
|
174
156
|
});
|
|
175
157
|
|
|
176
|
-
test("exclude
|
|
158
|
+
test("exclude filters out matching columns", () => {
|
|
177
159
|
const s1 = createSnapshot("id1", createSpec("col1"));
|
|
160
|
+
const s2 = createSnapshot("id2", createSpec("col2"));
|
|
178
161
|
const builder = new ColumnCollectionBuilder(createSpecFrameCtx());
|
|
179
|
-
builder.addSource([s1]);
|
|
162
|
+
builder.addSource([s1, s2]);
|
|
180
163
|
|
|
181
164
|
const collection = builder.build()!;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
);
|
|
165
|
+
const results = collection.findColumns({ exclude: { name: "col1" } });
|
|
166
|
+
expect(results).toHaveLength(1);
|
|
167
|
+
expect(results[0].spec.name).toBe("col2");
|
|
185
168
|
});
|
|
186
169
|
});
|
|
187
170
|
|
|
@@ -377,15 +360,16 @@ describe("AnchoredColumnCollection", () => {
|
|
|
377
360
|
expect(matches[0].variants).toBeDefined();
|
|
378
361
|
});
|
|
379
362
|
|
|
380
|
-
test("findColumns exclude
|
|
381
|
-
const
|
|
363
|
+
test("findColumns exclude filters out matching columns", () => {
|
|
364
|
+
const snap1 = createSnapshot("id1", createSpec("col1", { axesSpec: [sampleAxis("sample")] }));
|
|
365
|
+
const snap2 = createSnapshot("id2", createSpec("col2", { axesSpec: [sampleAxis("sample")] }));
|
|
382
366
|
const builder = new ColumnCollectionBuilder(createSpecFrameCtx());
|
|
383
|
-
builder.addSource([
|
|
367
|
+
builder.addSource([snap1, snap2]);
|
|
384
368
|
|
|
385
369
|
const collection = builder.build({ anchors: { main: anchorSpec } })!;
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
);
|
|
370
|
+
const results = collection.findColumns({ exclude: { name: "col1" } });
|
|
371
|
+
expect(results).toHaveLength(1);
|
|
372
|
+
expect(results[0].column.spec.name).toBe("col2");
|
|
389
373
|
});
|
|
390
374
|
|
|
391
375
|
test("allowPartialColumnList with anchors tracks completeness", () => {
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
AxisQualification,
|
|
3
3
|
ColumnAxesWithQualifications,
|
|
4
4
|
DiscoverColumnsConstraints,
|
|
5
|
+
DiscoverColumnsStepInfo,
|
|
5
6
|
MultiColumnSelector,
|
|
6
7
|
NativePObjectId,
|
|
7
8
|
PColumnSpec,
|
|
@@ -23,7 +24,7 @@ import type { GlobalCfgRenderCtxMethods } from "../render/internal";
|
|
|
23
24
|
/** Subset of render context methods needed for spec frame operations. */
|
|
24
25
|
type SpecFrameCtx = Pick<
|
|
25
26
|
GlobalCfgRenderCtxMethods,
|
|
26
|
-
"createSpecFrame" | "specFrameDiscoverColumns" | "
|
|
27
|
+
"createSpecFrame" | "specFrameDiscoverColumns" | "disposeSpecFrame"
|
|
27
28
|
>;
|
|
28
29
|
|
|
29
30
|
// --- FindColumnsOptions ---
|
|
@@ -79,6 +80,8 @@ export interface ColumnMatch {
|
|
|
79
80
|
readonly originalId: PObjectId;
|
|
80
81
|
/** Match variants — different paths/qualifications that reach this column. */
|
|
81
82
|
readonly variants: MatchVariant[];
|
|
83
|
+
/** Linker steps traversed to reach this hit; empty for direct matches. */
|
|
84
|
+
readonly path: DiscoverColumnsStepInfo[];
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
/** Qualifications needed for both query (already-integrated) columns and the hit column. */
|
|
@@ -253,24 +256,23 @@ class ColumnCollectionImpl implements ColumnCollection {
|
|
|
253
256
|
}
|
|
254
257
|
|
|
255
258
|
findColumns(options?: FindColumnsOptions): ColumnSnapshot<PObjectId>[] {
|
|
256
|
-
const
|
|
259
|
+
const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;
|
|
260
|
+
const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;
|
|
257
261
|
|
|
258
262
|
const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
|
|
259
|
-
|
|
263
|
+
includeColumns,
|
|
264
|
+
excludeColumns,
|
|
260
265
|
axes: [],
|
|
266
|
+
maxHops: 0,
|
|
261
267
|
constraints: PLAIN_CONSTRAINTS,
|
|
262
268
|
});
|
|
263
269
|
|
|
264
270
|
// Map hits back to snapshots
|
|
265
|
-
|
|
271
|
+
const results = response.hits
|
|
266
272
|
.map((hit) => this.columns.get(hit.hit.columnId as PObjectId))
|
|
267
273
|
.filter((col): col is ColumnSnapshot<PObjectId> => col !== undefined)
|
|
268
274
|
.map((col) => this.toSnapshot(col));
|
|
269
275
|
|
|
270
|
-
if (options?.exclude) {
|
|
271
|
-
throw new Error("Exclude filter is not yet implemented for plain ColumnCollection");
|
|
272
|
-
}
|
|
273
|
-
|
|
274
276
|
return results;
|
|
275
277
|
}
|
|
276
278
|
|
|
@@ -336,16 +338,19 @@ class AnchoredColumnCollectionImpl implements AnchoredColumnCollection {
|
|
|
336
338
|
findColumns(options?: AnchoredFindColumnsOptions): ColumnMatch[] {
|
|
337
339
|
const mode = options?.mode ?? "enrichment";
|
|
338
340
|
const constraints = matchingModeToConstraints(mode);
|
|
339
|
-
const
|
|
341
|
+
const includeColumns = options?.include ? toMultiColumnSelectors(options.include) : undefined;
|
|
342
|
+
const excludeColumns = options?.exclude ? toMultiColumnSelectors(options.exclude) : undefined;
|
|
340
343
|
|
|
341
344
|
const response = this.ctx.specFrameDiscoverColumns(this.specFrameHandle, {
|
|
342
|
-
|
|
345
|
+
includeColumns,
|
|
346
|
+
excludeColumns,
|
|
343
347
|
constraints,
|
|
344
348
|
axes: this.anchorAxes,
|
|
349
|
+
maxHops: options?.maxHops ?? 4,
|
|
345
350
|
});
|
|
346
351
|
|
|
347
352
|
// Map hits back to ColumnMatch entries
|
|
348
|
-
|
|
353
|
+
const results = response.hits
|
|
349
354
|
.map((hit) => {
|
|
350
355
|
const origId = hit.hit.columnId as PObjectId;
|
|
351
356
|
const col = this.columns.get(origId);
|
|
@@ -360,14 +365,11 @@ class AnchoredColumnCollectionImpl implements AnchoredColumnCollection {
|
|
|
360
365
|
distinctiveQualifications: v.distinctiveQualifications,
|
|
361
366
|
}),
|
|
362
367
|
),
|
|
368
|
+
path: hit.path,
|
|
363
369
|
} satisfies ColumnMatch;
|
|
364
370
|
})
|
|
365
371
|
.filter((m): m is ColumnMatch => m !== undefined);
|
|
366
372
|
|
|
367
|
-
if (options?.exclude) {
|
|
368
|
-
throw new Error("Exclude filter is not yet implemented for AnchoredColumnCollection");
|
|
369
|
-
}
|
|
370
|
-
|
|
371
373
|
return results;
|
|
372
374
|
}
|
|
373
375
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
AxisValueType,
|
|
3
|
+
ColumnValueType,
|
|
2
4
|
MultiAxisSelector,
|
|
3
5
|
MultiColumnSelector,
|
|
4
6
|
PColumnSpec,
|
|
5
7
|
StringMatcher,
|
|
6
|
-
ValueType,
|
|
7
8
|
} from "@milaboratories/pl-model-common";
|
|
8
9
|
|
|
9
10
|
export type { StringMatcher } from "@milaboratories/pl-model-common";
|
|
@@ -19,7 +20,7 @@ export type RelaxedRecord = Record<string, RelaxedStringMatchers>;
|
|
|
19
20
|
/** Relaxed axis selector — accepts plain strings where strict requires StringMatcher[]. */
|
|
20
21
|
export interface RelaxedAxisSelector {
|
|
21
22
|
name?: RelaxedStringMatchers;
|
|
22
|
-
type?:
|
|
23
|
+
type?: AxisValueType | AxisValueType[];
|
|
23
24
|
domain?: RelaxedRecord;
|
|
24
25
|
contextDomain?: RelaxedRecord;
|
|
25
26
|
annotations?: RelaxedRecord;
|
|
@@ -28,7 +29,7 @@ export interface RelaxedAxisSelector {
|
|
|
28
29
|
/** Relaxed column selector — convenient hand-written form. */
|
|
29
30
|
export interface RelaxedColumnSelector {
|
|
30
31
|
name?: RelaxedStringMatchers;
|
|
31
|
-
type?:
|
|
32
|
+
type?: ColumnValueType | ColumnValueType[];
|
|
32
33
|
domain?: RelaxedRecord;
|
|
33
34
|
contextDomain?: RelaxedRecord;
|
|
34
35
|
annotations?: RelaxedRecord;
|
|
@@ -57,7 +58,7 @@ function normalizeRecord(input: RelaxedRecord): Record<string, StringMatcher[]>
|
|
|
57
58
|
return result;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
function normalizeTypes(input:
|
|
61
|
+
function normalizeTypes<T>(input: T | T[]): T[] {
|
|
61
62
|
return Array.isArray(input) ? input : [input];
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -140,7 +141,7 @@ function matchAxisSelector(
|
|
|
140
141
|
selector: MultiAxisSelector,
|
|
141
142
|
): boolean {
|
|
142
143
|
if (selector.name !== undefined && !matchStringValue(axis.name, selector.name)) return false;
|
|
143
|
-
if (selector.type !== undefined && !selector.type.includes(axis.type
|
|
144
|
+
if (selector.type !== undefined && !selector.type.includes(axis.type)) return false;
|
|
144
145
|
if (selector.domain !== undefined && !matchRecordField(axis.domain, selector.domain))
|
|
145
146
|
return false;
|
|
146
147
|
if (
|
package/src/index.ts
CHANGED
package/src/platforma.ts
CHANGED
|
@@ -149,6 +149,6 @@ export type InferPluginData<Pl, PluginId extends string> =
|
|
|
149
149
|
*/
|
|
150
150
|
export type InferPluginHandles<T extends Record<string, unknown>> = {
|
|
151
151
|
readonly [K in keyof T]: T[K] extends PluginRecord<infer Data, infer Params, infer Outputs>
|
|
152
|
-
? PluginHandle<PluginFactoryLike<Data, Params, Outputs>>
|
|
152
|
+
? { handle: PluginHandle<PluginFactoryLike<Data, Params, Outputs>> }
|
|
153
153
|
: never;
|
|
154
154
|
};
|
package/src/plugin_model.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module plugin_model
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { BlockCodeKnownFeatureFlags } from "@milaboratories/pl-model-common";
|
|
10
|
+
import type { BlockCodeKnownFeatureFlags, OutputWithStatus } from "@milaboratories/pl-model-common";
|
|
11
11
|
import {
|
|
12
12
|
type DataModel,
|
|
13
13
|
DataModelBuilder,
|
|
@@ -79,6 +79,11 @@ type PluginChainState = {
|
|
|
79
79
|
recoverAtIndex?: number;
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
+
/** Version → persisted data shape for each migration step (third generic of `PluginModel.define` when `data` is a `PluginDataModel`). */
|
|
83
|
+
export type PluginDataModelVersions<
|
|
84
|
+
M extends PluginDataModel<PluginData, Record<string, unknown>, unknown>,
|
|
85
|
+
> = M extends PluginDataModel<PluginData, infer Versions, unknown> ? Versions : never;
|
|
86
|
+
|
|
82
87
|
/**
|
|
83
88
|
* Builder for creating PluginDataModel with type-safe migrations.
|
|
84
89
|
* Mirrors DataModelBuilder — same .from(), .migrate(), .recover(), .init() chain.
|
|
@@ -280,8 +285,8 @@ export class PluginInstance<
|
|
|
280
285
|
> implements TransferTarget<Id, TransferData> {
|
|
281
286
|
readonly id: Id;
|
|
282
287
|
readonly transferVersion: string;
|
|
283
|
-
/** @internal */
|
|
284
|
-
readonly
|
|
288
|
+
/** @internal Phantom for type inference of Data/Params/Outputs; never set at runtime. */
|
|
289
|
+
readonly __instanceTypes?: { data: Data; params: Params; outputs: Outputs };
|
|
285
290
|
private readonly factory: PluginModelFactory<Data, Params, Outputs, any, any>;
|
|
286
291
|
private readonly config: any;
|
|
287
292
|
|
|
@@ -336,6 +341,8 @@ export class PluginModel<
|
|
|
336
341
|
readonly outputs: {
|
|
337
342
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
338
343
|
};
|
|
344
|
+
/** Per-output flags (e.g. withStatus) */
|
|
345
|
+
readonly outputFlags: Record<string, { withStatus: boolean }>;
|
|
339
346
|
/** Feature flags declared by this plugin */
|
|
340
347
|
readonly featureFlags?: BlockCodeKnownFeatureFlags;
|
|
341
348
|
/** Create fresh default data. Config (if any) is captured at creation time. */
|
|
@@ -347,12 +354,14 @@ export class PluginModel<
|
|
|
347
354
|
outputs: {
|
|
348
355
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
349
356
|
};
|
|
357
|
+
outputFlags: Record<string, { withStatus: boolean }>;
|
|
350
358
|
featureFlags?: BlockCodeKnownFeatureFlags;
|
|
351
359
|
getDefaultData: () => DataVersioned<Data>;
|
|
352
360
|
}) {
|
|
353
361
|
this.name = options.name;
|
|
354
362
|
this.dataModel = options.dataModel;
|
|
355
363
|
this.outputs = options.outputs;
|
|
364
|
+
this.outputFlags = options.outputFlags;
|
|
356
365
|
this.featureFlags = options.featureFlags;
|
|
357
366
|
this.getDefaultData = options.getDefaultData;
|
|
358
367
|
}
|
|
@@ -372,6 +381,7 @@ export class PluginModel<
|
|
|
372
381
|
outputs: {
|
|
373
382
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
374
383
|
};
|
|
384
|
+
outputFlags: Record<string, { withStatus: boolean }>;
|
|
375
385
|
featureFlags?: BlockCodeKnownFeatureFlags;
|
|
376
386
|
getDefaultData: () => DataVersioned<Data>;
|
|
377
387
|
}): PluginModel<Data, Params, Outputs> {
|
|
@@ -485,6 +495,7 @@ class PluginModelFactory<
|
|
|
485
495
|
readonly outputs: {
|
|
486
496
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
487
497
|
};
|
|
498
|
+
private readonly outputFlags: Record<string, { withStatus: boolean }>;
|
|
488
499
|
private readonly featureFlags?: BlockCodeKnownFeatureFlags;
|
|
489
500
|
|
|
490
501
|
private constructor(options: {
|
|
@@ -494,12 +505,14 @@ class PluginModelFactory<
|
|
|
494
505
|
outputs: {
|
|
495
506
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
496
507
|
};
|
|
508
|
+
outputFlags: Record<string, { withStatus: boolean }>;
|
|
497
509
|
featureFlags?: BlockCodeKnownFeatureFlags;
|
|
498
510
|
}) {
|
|
499
511
|
this.name = options.name;
|
|
500
512
|
this.dataFn = options.dataFn;
|
|
501
513
|
this.getDefaultDataFn = options.getDefaultDataFn;
|
|
502
514
|
this.outputs = options.outputs;
|
|
515
|
+
this.outputFlags = options.outputFlags;
|
|
503
516
|
this.featureFlags = options.featureFlags;
|
|
504
517
|
}
|
|
505
518
|
|
|
@@ -517,6 +530,7 @@ class PluginModelFactory<
|
|
|
517
530
|
outputs: {
|
|
518
531
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
519
532
|
};
|
|
533
|
+
outputFlags: Record<string, { withStatus: boolean }>;
|
|
520
534
|
featureFlags?: BlockCodeKnownFeatureFlags;
|
|
521
535
|
}): PluginModelFactory<Data, Params, Outputs, Config, Versions> {
|
|
522
536
|
return new PluginModelFactory(options);
|
|
@@ -544,6 +558,7 @@ class PluginModelFactory<
|
|
|
544
558
|
name: this.name,
|
|
545
559
|
dataModel,
|
|
546
560
|
outputs: this.outputs,
|
|
561
|
+
outputFlags: this.outputFlags,
|
|
547
562
|
featureFlags: this.featureFlags,
|
|
548
563
|
getDefaultData: getDefaultDataFn
|
|
549
564
|
? () => getDefaultDataFn(config)
|
|
@@ -584,6 +599,7 @@ class PluginModelBuilder<
|
|
|
584
599
|
private readonly outputs: {
|
|
585
600
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
586
601
|
};
|
|
602
|
+
private readonly outputFlags: Record<string, { withStatus: boolean }>;
|
|
587
603
|
private readonly featureFlags?: BlockCodeKnownFeatureFlags;
|
|
588
604
|
|
|
589
605
|
private constructor(options: {
|
|
@@ -593,6 +609,7 @@ class PluginModelBuilder<
|
|
|
593
609
|
outputs?: {
|
|
594
610
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
595
611
|
};
|
|
612
|
+
outputFlags?: Record<string, { withStatus: boolean }>;
|
|
596
613
|
featureFlags?: BlockCodeKnownFeatureFlags;
|
|
597
614
|
}) {
|
|
598
615
|
this.name = options.name;
|
|
@@ -603,6 +620,7 @@ class PluginModelBuilder<
|
|
|
603
620
|
({} as {
|
|
604
621
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
605
622
|
});
|
|
623
|
+
this.outputFlags = options.outputFlags ?? {};
|
|
606
624
|
this.featureFlags = options.featureFlags;
|
|
607
625
|
}
|
|
608
626
|
|
|
@@ -620,6 +638,7 @@ class PluginModelBuilder<
|
|
|
620
638
|
outputs?: {
|
|
621
639
|
[K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];
|
|
622
640
|
};
|
|
641
|
+
outputFlags?: Record<string, { withStatus: boolean }>;
|
|
623
642
|
featureFlags?: BlockCodeKnownFeatureFlags;
|
|
624
643
|
}): PluginModelBuilder<Data, Params, Outputs, Config, Versions> {
|
|
625
644
|
return new PluginModelBuilder(options);
|
|
@@ -653,6 +672,57 @@ class PluginModelBuilder<
|
|
|
653
672
|
ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,
|
|
654
673
|
) => (Outputs & { [P in Key]: T })[K];
|
|
655
674
|
},
|
|
675
|
+
outputFlags: { ...this.outputFlags, [key]: { withStatus: false } },
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Adds an output wrapped with status information to the plugin.
|
|
681
|
+
*
|
|
682
|
+
* The UI receives the full {@link OutputWithStatus} object instead of an unwrapped value,
|
|
683
|
+
* allowing it to distinguish between pending, success, and error states.
|
|
684
|
+
*
|
|
685
|
+
* @param key - Output name
|
|
686
|
+
* @param fn - Function that computes the output value from plugin context
|
|
687
|
+
* @returns PluginModel with the new status-wrapped output added
|
|
688
|
+
*
|
|
689
|
+
* @example
|
|
690
|
+
* .outputWithStatus('table', (ctx) => {
|
|
691
|
+
* const pCols = ctx.params.pFrame?.getPColumns();
|
|
692
|
+
* if (pCols === undefined) return undefined;
|
|
693
|
+
* return createPlDataTableV2(ctx, pCols, ctx.data.tableState);
|
|
694
|
+
* })
|
|
695
|
+
*/
|
|
696
|
+
outputWithStatus<const Key extends string, T>(
|
|
697
|
+
key: Key,
|
|
698
|
+
fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T,
|
|
699
|
+
): PluginModelBuilder<
|
|
700
|
+
Data,
|
|
701
|
+
Params,
|
|
702
|
+
Outputs & { [K in Key]: OutputWithStatus<T> },
|
|
703
|
+
Config,
|
|
704
|
+
Versions
|
|
705
|
+
> {
|
|
706
|
+
return new PluginModelBuilder<
|
|
707
|
+
Data,
|
|
708
|
+
Params,
|
|
709
|
+
Outputs & { [K in Key]: OutputWithStatus<T> },
|
|
710
|
+
Config,
|
|
711
|
+
Versions
|
|
712
|
+
>({
|
|
713
|
+
name: this.name,
|
|
714
|
+
dataFn: this.dataFn,
|
|
715
|
+
getDefaultDataFn: this.getDefaultDataFn,
|
|
716
|
+
featureFlags: this.featureFlags,
|
|
717
|
+
outputs: {
|
|
718
|
+
...this.outputs,
|
|
719
|
+
[key]: fn,
|
|
720
|
+
} as {
|
|
721
|
+
[K in keyof (Outputs & { [P in Key]: OutputWithStatus<T> })]: (
|
|
722
|
+
ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,
|
|
723
|
+
) => (Outputs & { [P in Key]: OutputWithStatus<T> })[K];
|
|
724
|
+
},
|
|
725
|
+
outputFlags: { ...this.outputFlags, [key]: { withStatus: true } },
|
|
656
726
|
});
|
|
657
727
|
}
|
|
658
728
|
|
|
@@ -675,6 +745,7 @@ class PluginModelBuilder<
|
|
|
675
745
|
dataFn: this.dataFn,
|
|
676
746
|
getDefaultDataFn: this.getDefaultDataFn,
|
|
677
747
|
outputs: this.outputs,
|
|
748
|
+
outputFlags: this.outputFlags,
|
|
678
749
|
featureFlags: this.featureFlags,
|
|
679
750
|
});
|
|
680
751
|
}
|
package/src/render/api.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AnchoredPColumnSelector,
|
|
3
3
|
AnyFunction,
|
|
4
|
+
AxesId,
|
|
5
|
+
AxesSpec,
|
|
4
6
|
AxisId,
|
|
5
7
|
DataInfo,
|
|
6
8
|
DiscoverColumnsRequest,
|
|
@@ -17,6 +19,8 @@ import type {
|
|
|
17
19
|
PObjectId,
|
|
18
20
|
PObjectSpec,
|
|
19
21
|
PSpecPredicate,
|
|
22
|
+
PTableColumnId,
|
|
23
|
+
PTableColumnSpec,
|
|
20
24
|
PTableDef,
|
|
21
25
|
PTableDefV2,
|
|
22
26
|
PTableHandle,
|
|
@@ -25,6 +29,7 @@ import type {
|
|
|
25
29
|
PlRef,
|
|
26
30
|
ResolveAnchorsOptions,
|
|
27
31
|
ResultCollection,
|
|
32
|
+
SingleAxisSelector,
|
|
28
33
|
SUniversalPColumnId,
|
|
29
34
|
ValueOrError,
|
|
30
35
|
} from "@milaboratories/pl-model-common";
|
|
@@ -727,8 +732,24 @@ export abstract class RenderCtxBase<Args = unknown, Data = unknown> {
|
|
|
727
732
|
return this.ctx.specFrameDiscoverColumns(handle, request);
|
|
728
733
|
}
|
|
729
734
|
|
|
730
|
-
public
|
|
731
|
-
this.ctx.
|
|
735
|
+
public disposeSpecFrame(handle: string): void {
|
|
736
|
+
this.ctx.disposeSpecFrame(handle);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
public expandAxes(spec: AxesSpec): AxesId {
|
|
740
|
+
return this.ctx.expandAxes(spec);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
public collapseAxes(ids: AxesId): AxesSpec {
|
|
744
|
+
return this.ctx.collapseAxes(ids);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
public findAxis(spec: AxesSpec, selector: SingleAxisSelector): number {
|
|
748
|
+
return this.ctx.findAxis(spec, selector);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
public findTableColumn(tableSpec: PTableColumnSpec[], selector: PTableColumnId): number {
|
|
752
|
+
return this.ctx.findTableColumn(tableSpec, selector);
|
|
732
753
|
}
|
|
733
754
|
|
|
734
755
|
public getCurrentUnstableMarker(): string | undefined {
|
|
@@ -798,26 +819,28 @@ export class RenderCtxLegacy<Args = unknown, UiState = unknown> extends RenderCt
|
|
|
798
819
|
*
|
|
799
820
|
* @typeParam F - PluginFactoryLike phantom carrying data/params/outputs types
|
|
800
821
|
*/
|
|
801
|
-
export class PluginRenderCtx<F extends PluginFactoryLike = PluginFactoryLike>
|
|
802
|
-
|
|
822
|
+
export class PluginRenderCtx<F extends PluginFactoryLike = PluginFactoryLike> extends RenderCtxBase<
|
|
823
|
+
unknown,
|
|
824
|
+
InferFactoryData<F>
|
|
825
|
+
> {
|
|
803
826
|
private readonly handle: PluginHandle<F>;
|
|
804
827
|
private readonly wrappedInputs: Record<string, () => unknown>;
|
|
805
828
|
|
|
806
829
|
constructor(handle: PluginHandle<F>, wrappedInputs: Record<string, () => unknown>) {
|
|
807
|
-
|
|
830
|
+
super();
|
|
808
831
|
this.handle = handle;
|
|
809
832
|
this.wrappedInputs = wrappedInputs;
|
|
810
833
|
}
|
|
811
834
|
|
|
812
|
-
private
|
|
835
|
+
private pluginDataCache?: { v: InferFactoryData<F> };
|
|
813
836
|
|
|
814
837
|
/** Plugin's persistent data from blockStorage.__plugins.{pluginId}.__data */
|
|
815
|
-
public get data(): InferFactoryData<F> {
|
|
816
|
-
if (this.
|
|
838
|
+
public override get data(): InferFactoryData<F> {
|
|
839
|
+
if (this.pluginDataCache === undefined) {
|
|
817
840
|
const raw = this.ctx.blockStorage();
|
|
818
|
-
this.
|
|
841
|
+
this.pluginDataCache = { v: getPluginData(parseJson(raw), this.handle) };
|
|
819
842
|
}
|
|
820
|
-
return this.
|
|
843
|
+
return this.pluginDataCache.v;
|
|
821
844
|
}
|
|
822
845
|
|
|
823
846
|
private paramsCache?: { v: InferFactoryParams<F> };
|
|
@@ -833,9 +856,6 @@ export class PluginRenderCtx<F extends PluginFactoryLike = PluginFactoryLike> {
|
|
|
833
856
|
}
|
|
834
857
|
return this.paramsCache.v;
|
|
835
858
|
}
|
|
836
|
-
|
|
837
|
-
/** Result pool — same as block, from cfgRenderCtx methods */
|
|
838
|
-
public readonly resultPool = new ResultPool();
|
|
839
859
|
}
|
|
840
860
|
|
|
841
861
|
/** @deprecated Use BlockRenderCtx instead */
|