@platforma-sdk/model 1.61.1 → 1.63.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.
Files changed (88) hide show
  1. package/dist/block_model.cjs +17 -10
  2. package/dist/block_model.cjs.map +1 -1
  3. package/dist/block_model.d.ts +22 -5
  4. package/dist/block_model.js +16 -10
  5. package/dist/block_model.js.map +1 -1
  6. package/dist/columns/column_collection_builder.cjs +26 -14
  7. package/dist/columns/column_collection_builder.cjs.map +1 -1
  8. package/dist/columns/column_collection_builder.d.ts +9 -8
  9. package/dist/columns/column_collection_builder.js +26 -14
  10. package/dist/columns/column_collection_builder.js.map +1 -1
  11. package/dist/columns/ctx_column_sources.cjs.map +1 -1
  12. package/dist/columns/ctx_column_sources.d.ts +1 -1
  13. package/dist/columns/ctx_column_sources.js.map +1 -1
  14. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +93 -89
  15. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
  16. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts +2 -2
  17. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +93 -89
  18. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
  19. package/dist/components/PlDataTable/createPlDataTable/index.cjs.map +1 -1
  20. package/dist/components/PlDataTable/createPlDataTable/index.d.ts +2 -1
  21. package/dist/components/PlDataTable/createPlDataTable/index.js.map +1 -1
  22. package/dist/components/PlMultiSequenceAlignment.cjs +1 -1
  23. package/dist/components/PlMultiSequenceAlignment.cjs.map +1 -1
  24. package/dist/components/PlMultiSequenceAlignment.js +2 -2
  25. package/dist/components/PlMultiSequenceAlignment.js.map +1 -1
  26. package/dist/components/PlSelectionModel.cjs.map +1 -1
  27. package/dist/components/PlSelectionModel.d.ts +1 -1
  28. package/dist/components/PlSelectionModel.js.map +1 -1
  29. package/dist/index.cjs +7 -0
  30. package/dist/index.d.ts +6 -2
  31. package/dist/index.js +4 -1
  32. package/dist/package.cjs +1 -1
  33. package/dist/package.js +1 -1
  34. package/dist/pframe_utils/index.cjs +2 -5
  35. package/dist/pframe_utils/index.cjs.map +1 -1
  36. package/dist/pframe_utils/index.js +2 -5
  37. package/dist/pframe_utils/index.js.map +1 -1
  38. package/dist/platforma.d.ts +8 -4
  39. package/dist/plugin_handle.cjs.map +1 -1
  40. package/dist/plugin_handle.d.ts +13 -7
  41. package/dist/plugin_handle.js.map +1 -1
  42. package/dist/plugin_model.cjs +37 -11
  43. package/dist/plugin_model.cjs.map +1 -1
  44. package/dist/plugin_model.d.ts +80 -39
  45. package/dist/plugin_model.js +37 -11
  46. package/dist/plugin_model.js.map +1 -1
  47. package/dist/render/api.cjs +13 -24
  48. package/dist/render/api.cjs.map +1 -1
  49. package/dist/render/api.d.ts +11 -14
  50. package/dist/render/api.js +13 -24
  51. package/dist/render/api.js.map +1 -1
  52. package/dist/render/internal.cjs.map +1 -1
  53. package/dist/render/internal.d.ts +3 -14
  54. package/dist/render/internal.js.map +1 -1
  55. package/dist/services/block_services.cjs +18 -0
  56. package/dist/services/block_services.cjs.map +1 -0
  57. package/dist/services/block_services.d.ts +18 -0
  58. package/dist/services/block_services.js +16 -0
  59. package/dist/services/block_services.js.map +1 -0
  60. package/dist/services/index.cjs +2 -0
  61. package/dist/services/index.d.ts +3 -0
  62. package/dist/services/index.js +2 -0
  63. package/dist/services/service_bridge.cjs +35 -0
  64. package/dist/services/service_bridge.cjs.map +1 -0
  65. package/dist/services/service_bridge.d.ts +18 -0
  66. package/dist/services/service_bridge.js +33 -0
  67. package/dist/services/service_bridge.js.map +1 -0
  68. package/dist/services/service_resolve.d.ts +13 -0
  69. package/package.json +9 -9
  70. package/src/block_model.ts +47 -14
  71. package/src/columns/column_collection_builder.test.ts +23 -2
  72. package/src/columns/column_collection_builder.ts +38 -30
  73. package/src/columns/ctx_column_sources.ts +2 -2
  74. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +159 -153
  75. package/src/components/PlDataTable/createPlDataTable/index.ts +5 -4
  76. package/src/components/PlMultiSequenceAlignment.ts +1 -2
  77. package/src/components/PlSelectionModel.ts +1 -1
  78. package/src/index.ts +1 -0
  79. package/src/pframe_utils/index.ts +2 -6
  80. package/src/platforma.ts +14 -2
  81. package/src/plugin_handle.ts +24 -6
  82. package/src/plugin_model.ts +252 -84
  83. package/src/render/api.ts +50 -51
  84. package/src/render/internal.ts +3 -38
  85. package/src/services/block_services.ts +17 -0
  86. package/src/services/index.ts +3 -0
  87. package/src/services/service_bridge.ts +71 -0
  88. package/src/services/service_resolve.ts +71 -0
@@ -41,6 +41,7 @@ import type { PlDataTableFilters, PlDataTableModel } from "../typesV5";
41
41
  import { upgradePlDataTableStateV2 } from "../state-migration";
42
42
  import type { PlDataTableStateV2 } from "../state-migration";
43
43
  import type { ColumnSource, MatchingMode } from "../../../columns";
44
+ import { Services, type RequireServices } from "@milaboratories/pl-model-common";
44
45
  import { ColumnCollectionBuilder } from "../../../columns";
45
46
  import { isColumnSnapshotProvider } from "../../../columns/column_snapshot_provider";
46
47
  import { collectCtxColumnSnapshotProviders } from "../../../columns/ctx_column_sources";
@@ -184,8 +185,8 @@ export type createPlDataTableOptionsV3 = {
184
185
  // | { annotation: Record<string, string> }
185
186
  // | { ids: Set<string> };
186
187
 
187
- export function createPlDataTableV3<A, U>(
188
- ctx: RenderCtxBase<A, U>,
188
+ export function createPlDataTableV3<A, U, S extends RequireServices<typeof Services.PFrameSpec>>(
189
+ ctx: RenderCtxBase<A, U, S>,
189
190
  options: createPlDataTableOptionsV3,
190
191
  ): PlDataTableModel | undefined {
191
192
  const providers = options.source
@@ -195,170 +196,175 @@ export function createPlDataTableV3<A, U>(
195
196
  if (providers.length === 0) return undefined;
196
197
 
197
198
  // Step 1: Build collection from sources
198
- const builder = new ColumnCollectionBuilder(ctx).addSources(providers);
199
+ const builder = new ColumnCollectionBuilder(ctx.services.pframeSpec).addSources(providers);
199
200
  const anchors = options.columns.anchors;
200
201
  const collection = isNil(anchors) ? builder.build() : builder.build({ anchors });
201
202
 
202
203
  if (!collection) return undefined;
204
+ try {
205
+ // Step 2: Get data columns, excluding annotation-hidden ones
206
+ const findOptions = options.columns
207
+ ? {
208
+ include: options.columns.include,
209
+ exclude: options.columns.exclude,
210
+ mode: options.columns.mode,
211
+ maxHops: options.columns.maxHops,
212
+ }
213
+ : undefined;
214
+ const findResult = collection.findColumns(findOptions);
215
+ const snapshots = findResult.map((v) => ("column" in v ? v.column : v));
216
+ const dataSnapshots = snapshots.filter((s) => !isColumnHidden(s.spec));
217
+ if (dataSnapshots.length === 0) return undefined;
218
+
219
+ // Convert snapshots to PColumn<PColumnDataUniversal>[]
220
+ const columns: PColumn<PColumnDataUniversal>[] = [];
221
+ for (const snap of dataSnapshots) {
222
+ if (!snap.data) return undefined;
223
+ const data = snap.data.get();
224
+ if (data === undefined) return undefined;
225
+ columns.push({ id: snap.id, spec: snap.spec, data });
226
+ }
203
227
 
204
- // Step 2: Get data columns, excluding annotation-hidden ones
205
- const findOptions = options.columns
206
- ? {
207
- include: options.columns.include,
208
- exclude: options.columns.exclude,
209
- mode: options.columns.mode,
210
- maxHops: options.columns.maxHops,
211
- }
212
- : undefined;
213
- const findResult = collection.findColumns(findOptions);
214
- const snapshots = findResult.map((v) => ("column" in v ? v.column : v));
215
- const dataSnapshots = snapshots.filter((s) => !isColumnHidden(s.spec));
216
- if (dataSnapshots.length === 0) return undefined;
217
-
218
- // Convert snapshots to PColumn<PColumnDataUniversal>[]
219
- const columns: PColumn<PColumnDataUniversal>[] = [];
220
- for (const snap of dataSnapshots) {
221
- if (!snap.data) return undefined;
222
- const data = snap.data.get();
223
- if (data === undefined) return undefined;
224
- columns.push({ id: snap.id, spec: snap.spec, data });
225
- }
228
+ // Step 3: Normalize table state
229
+ const tableStateNormalized = upgradePlDataTableStateV2(options.state);
230
+
231
+ // Step 4: Get label columns from result pool and match to data columns
232
+ const allLabelColumns = getAllLabelColumns(ctx.resultPool);
233
+ if (!allLabelColumns) return undefined;
226
234
 
227
- // Step 3: Normalize table state
228
- const tableStateNormalized = upgradePlDataTableStateV2(options.state);
229
-
230
- // Step 4: Get label columns from result pool and match to data columns
231
- const allLabelColumns = getAllLabelColumns(ctx.resultPool);
232
- if (!allLabelColumns) return undefined;
233
-
234
- const fullLabelColumns = getMatchingLabelColumns(
235
- columns.map(getColumnIdAndSpec),
236
- allLabelColumns,
237
- );
238
-
239
- const fullColumns = [...columns, ...fullLabelColumns];
240
-
241
- // Step 5: Build column ID set for filter/sorting validation
242
- const fullColumnsAxes = uniqueBy(
243
- fullColumns.flatMap((c) => c.spec.axesSpec.map((a) => getAxisId(a))),
244
- (a) => canonicalizeJson<AxisId>(a),
245
- );
246
- const fullColumnsIds: PTableColumnId[] = [
247
- ...fullColumnsAxes.map((a) => ({ type: "axis", id: a }) satisfies PTableColumnIdAxis),
248
- ...fullColumns.map((c) => ({ type: "column", id: c.id }) satisfies PTableColumnIdColumn),
249
- ];
250
- const fullColumnsIdsSet = new Set(fullColumnsIds.map((c) => canonicalizeJson<PTableColumnId>(c)));
251
- const isValidColumnId = (id: string): boolean =>
252
- fullColumnsIdsSet.has(id as CanonicalizedJson<PTableColumnId>);
253
-
254
- // Step 6: Filtering validation
255
- const stateFilters = tableStateNormalized.pTableParams.filters;
256
- const opsFilters = options?.filters ?? null;
257
- const filters: null | PlDataTableFilters =
258
- stateFilters != null && opsFilters != null
259
- ? { type: "and", filters: [stateFilters, opsFilters] }
260
- : (stateFilters ?? opsFilters);
261
- const filterColumns = filters ? collectFilterSpecColumns(filters) : [];
262
- const firstInvalidFilterColumn = filterColumns.find((col) => !isValidColumnId(col));
263
- if (firstInvalidFilterColumn)
264
- throw new Error(
265
- `Invalid filter column ${firstInvalidFilterColumn}: column reference does not match the table columns`,
235
+ const fullLabelColumns = getMatchingLabelColumns(
236
+ columns.map(getColumnIdAndSpec),
237
+ allLabelColumns,
266
238
  );
267
239
 
268
- // Step 7: Sorting validation
269
- const userSorting = tableStateNormalized.pTableParams.sorting;
270
- const sorting = (isEmpty(userSorting) ? options?.sorting : userSorting) ?? [];
271
- const firstInvalidSortingColumn = sorting.find(
272
- (s) => !isValidColumnId(canonicalizeJson<PTableColumnId>(s.column)),
273
- );
274
- if (firstInvalidSortingColumn)
275
- throw new Error(
276
- `Invalid sorting column ${JSON.stringify(firstInvalidSortingColumn.column)}: column reference does not match the table columns`,
240
+ const fullColumns = [...columns, ...fullLabelColumns];
241
+
242
+ // Step 5: Build column ID set for filter/sorting validation
243
+ const fullColumnsAxes = uniqueBy(
244
+ fullColumns.flatMap((c) => c.spec.axesSpec.map((a) => getAxisId(a))),
245
+ (a) => canonicalizeJson<AxisId>(a),
246
+ );
247
+ const fullColumnsIds: PTableColumnId[] = [
248
+ ...fullColumnsAxes.map((a) => ({ type: "axis", id: a }) satisfies PTableColumnIdAxis),
249
+ ...fullColumns.map((c) => ({ type: "column", id: c.id }) satisfies PTableColumnIdColumn),
250
+ ];
251
+ const fullColumnsIdsSet = new Set(
252
+ fullColumnsIds.map((c) => canonicalizeJson<PTableColumnId>(c)),
253
+ );
254
+ const isValidColumnId = (id: string): boolean =>
255
+ fullColumnsIdsSet.has(id as CanonicalizedJson<PTableColumnId>);
256
+
257
+ // Step 6: Filtering validation
258
+ const stateFilters = tableStateNormalized.pTableParams.filters;
259
+ const opsFilters = options?.filters ?? null;
260
+ const filters: null | PlDataTableFilters =
261
+ stateFilters != null && opsFilters != null
262
+ ? { type: "and", filters: [stateFilters, opsFilters] }
263
+ : (stateFilters ?? opsFilters);
264
+ const filterColumns = filters ? collectFilterSpecColumns(filters) : [];
265
+ const firstInvalidFilterColumn = filterColumns.find((col) => !isValidColumnId(col));
266
+ if (firstInvalidFilterColumn)
267
+ throw new Error(
268
+ `Invalid filter column ${firstInvalidFilterColumn}: column reference does not match the table columns`,
269
+ );
270
+
271
+ // Step 7: Sorting validation
272
+ const userSorting = tableStateNormalized.pTableParams.sorting;
273
+ const sorting = (isEmpty(userSorting) ? options?.sorting : userSorting) ?? [];
274
+ const firstInvalidSortingColumn = sorting.find(
275
+ (s) => !isValidColumnId(canonicalizeJson<PTableColumnId>(s.column)),
276
+ );
277
+ if (firstInvalidSortingColumn)
278
+ throw new Error(
279
+ `Invalid sorting column ${JSON.stringify(firstInvalidSortingColumn.column)}: column reference does not match the table columns`,
280
+ );
281
+
282
+ // Step 8: Build full table definition and handles
283
+ const coreJoinType = options?.coreJoinType ?? "full";
284
+ const fullDef = createPTableDef({
285
+ columns,
286
+ labelColumns: fullLabelColumns,
287
+ coreJoinType,
288
+ filters,
289
+ sorting,
290
+ coreColumnPredicate: options?.coreColumnPredicate,
291
+ });
292
+
293
+ const fullHandle = ctx.createPTableV2(fullDef);
294
+ const pframeHandle = ctx.createPFrame(fullColumns);
295
+ if (!fullHandle || !pframeHandle) return undefined;
296
+
297
+ // Step 9: Determine hidden columns
298
+ const hiddenColumns = new Set<PObjectId>(
299
+ ((): PObjectId[] => {
300
+ // Inner join works as a filter — all columns must be present
301
+ if (coreJoinType === "inner") return [];
302
+
303
+ const hiddenColIds = tableStateNormalized.pTableParams.hiddenColIds;
304
+ if (hiddenColIds) return hiddenColIds;
305
+
306
+ return columns.filter((c) => isColumnOptional(c.spec)).map((c) => c.id);
307
+ })(),
277
308
  );
278
309
 
279
- // Step 8: Build full table definition and handles
280
- const coreJoinType = options?.coreJoinType ?? "full";
281
- const fullDef = createPTableDef({
282
- columns,
283
- labelColumns: fullLabelColumns,
284
- coreJoinType,
285
- filters,
286
- sorting,
287
- coreColumnPredicate: options?.coreColumnPredicate,
288
- });
289
-
290
- const fullHandle = ctx.createPTableV2(fullDef);
291
- const pframeHandle = ctx.createPFrame(fullColumns);
292
- if (!fullHandle || !pframeHandle) return undefined;
293
-
294
- // Step 9: Determine hidden columns
295
- const hiddenColumns = new Set<PObjectId>(
296
- ((): PObjectId[] => {
297
- // Inner join works as a filter — all columns must be present
298
- if (coreJoinType === "inner") return [];
299
-
300
- const hiddenColIds = tableStateNormalized.pTableParams.hiddenColIds;
301
- if (hiddenColIds) return hiddenColIds;
302
-
303
- return columns.filter((c) => isColumnOptional(c.spec)).map((c) => c.id);
304
- })(),
305
- );
306
-
307
- // Preserve linker columns
308
- columns.filter((c) => isLinkerColumn(c.spec)).forEach((c) => hiddenColumns.delete(c.id));
309
-
310
- // Preserve core columns as they change the shape of join
311
- const coreColumnPredicate = options?.coreColumnPredicate;
312
- if (coreColumnPredicate) {
313
- const coreColumns = columns.flatMap((c) =>
314
- coreColumnPredicate(getColumnIdAndSpec(c)) ? [c.id] : [],
310
+ // Preserve linker columns
311
+ columns.filter((c) => isLinkerColumn(c.spec)).forEach((c) => hiddenColumns.delete(c.id));
312
+
313
+ // Preserve core columns as they change the shape of join
314
+ const coreColumnPredicate = options?.coreColumnPredicate;
315
+ if (coreColumnPredicate) {
316
+ const coreColumns = columns.flatMap((c) =>
317
+ coreColumnPredicate(getColumnIdAndSpec(c)) ? [c.id] : [],
318
+ );
319
+ coreColumns.forEach((c) => hiddenColumns.delete(c));
320
+ }
321
+
322
+ // Preserve sorted columns from being hidden
323
+ sorting
324
+ .map((s) => s.column)
325
+ .filter((c): c is PTableColumnIdColumn => c.type === "column")
326
+ .forEach((c) => hiddenColumns.delete(c.id));
327
+
328
+ // Preserve filter columns from being hidden
329
+ if (filters) {
330
+ collectFilterSpecColumns(filters)
331
+ .flatMap((c) => {
332
+ const obj = parseJson(c);
333
+ return obj.type === "column" ? [obj.id] : [];
334
+ })
335
+ .forEach((c) => hiddenColumns.delete(c));
336
+ }
337
+
338
+ // Step 10: Build visible table definition
339
+ const visibleColumns = columns.filter((c) => !hiddenColumns.has(c.id));
340
+ const visibleLabelColumns = getMatchingLabelColumns(
341
+ visibleColumns.map(getColumnIdAndSpec),
342
+ allLabelColumns,
315
343
  );
316
- coreColumns.forEach((c) => hiddenColumns.delete(c));
317
- }
318
344
 
319
- // Preserve sorted columns from being hidden
320
- sorting
321
- .map((s) => s.column)
322
- .filter((c): c is PTableColumnIdColumn => c.type === "column")
323
- .forEach((c) => hiddenColumns.delete(c.id));
324
-
325
- // Preserve filter columns from being hidden
326
- if (filters) {
327
- collectFilterSpecColumns(filters)
328
- .flatMap((c) => {
329
- const obj = parseJson(c);
330
- return obj.type === "column" ? [obj.id] : [];
331
- })
332
- .forEach((c) => hiddenColumns.delete(c));
345
+ if (!allPColumnsReady([...visibleColumns, ...visibleLabelColumns])) return undefined;
346
+
347
+ const visibleDef = createPTableDef({
348
+ columns: visibleColumns,
349
+ labelColumns: visibleLabelColumns,
350
+ coreJoinType,
351
+ filters,
352
+ sorting,
353
+ coreColumnPredicate,
354
+ });
355
+ const visibleHandle = ctx.createPTableV2(visibleDef);
356
+
357
+ if (!visibleHandle) return undefined;
358
+
359
+ return {
360
+ sourceId: tableStateNormalized.pTableParams.sourceId,
361
+ fullTableHandle: fullHandle,
362
+ fullPframeHandle: pframeHandle,
363
+ visibleTableHandle: visibleHandle,
364
+ } satisfies PlDataTableModel;
365
+ } finally {
366
+ collection.dispose();
333
367
  }
334
-
335
- // Step 10: Build visible table definition
336
- const visibleColumns = columns.filter((c) => !hiddenColumns.has(c.id));
337
- const visibleLabelColumns = getMatchingLabelColumns(
338
- visibleColumns.map(getColumnIdAndSpec),
339
- allLabelColumns,
340
- );
341
-
342
- if (!allPColumnsReady([...visibleColumns, ...visibleLabelColumns])) return undefined;
343
-
344
- const visibleDef = createPTableDef({
345
- columns: visibleColumns,
346
- labelColumns: visibleLabelColumns,
347
- coreJoinType,
348
- filters,
349
- sorting,
350
- coreColumnPredicate,
351
- });
352
- const visibleHandle = ctx.createPTableV2(visibleDef);
353
-
354
- if (!visibleHandle) return undefined;
355
-
356
- return {
357
- sourceId: tableStateNormalized.pTableParams.sourceId,
358
- fullTableHandle: fullHandle,
359
- fullPframeHandle: pframeHandle,
360
- visibleTableHandle: visibleHandle,
361
- } satisfies PlDataTableModel;
362
368
  }
363
369
 
364
370
  /** Normalize raw ColumnSource | ColumnSource[] into a flat list of sources. */
@@ -1,3 +1,4 @@
1
+ import { Services, type RequireServices } from "@milaboratories/pl-model-common";
1
2
  import type { RenderCtxBase } from "../../../render";
2
3
  import type { PlDataTableModel } from "../typesV5";
3
4
  import { createPlDataTableOptionsV2, createPlDataTableV2 } from "./createPlDataTableV2";
@@ -8,12 +9,12 @@ export function createPlDataTable<A, U>(
8
9
  ctx: RenderCtxBase<A, U>,
9
10
  options: { version: "v2" } & createPlDataTableOptionsV2,
10
11
  ): ReturnType<typeof createPlDataTableV2>;
11
- export function createPlDataTable<A, U>(
12
- ctx: RenderCtxBase<A, U>,
12
+ export function createPlDataTable<A, U, S extends RequireServices<typeof Services.PFrameSpec>>(
13
+ ctx: RenderCtxBase<A, U, S>,
13
14
  options: { version?: "v3" } & createPlDataTableOptionsV3,
14
15
  ): ReturnType<typeof createPlDataTableV3>;
15
- export function createPlDataTable<A, U>(
16
- ctx: RenderCtxBase<A, U>,
16
+ export function createPlDataTable<A, U, S extends RequireServices<typeof Services.PFrameSpec>>(
17
+ ctx: RenderCtxBase<A, U, S>,
17
18
  options:
18
19
  | ({ version: "v2" } & createPlDataTableOptionsV2)
19
20
  | ({ version?: "v3" } & createPlDataTableOptionsV3),
@@ -8,7 +8,6 @@ import type {
8
8
  } from "@milaboratories/pl-model-common";
9
9
  import {
10
10
  Annotation,
11
- isPTableAbsent,
12
11
  PColumnName,
13
12
  stringifyJson,
14
13
  uniquePlId,
@@ -56,7 +55,7 @@ export function createRowSelectionColumn({
56
55
  return;
57
56
  }
58
57
  const data: PColumnValues = selection.selectedKeys
59
- .filter((r): r is PColumnKey => r.every((v) => !isPTableAbsent(v)))
58
+ .filter((r): r is PColumnKey => r.every((v) => v !== null))
60
59
  .map((r) => ({ key: r, val: 1 }));
61
60
  if (!data.length) {
62
61
  return;
@@ -1,7 +1,7 @@
1
1
  import type { AxesSpec, PTableValueAxis } from "@milaboratories/pl-model-common";
2
2
 
3
3
  /** Key is a set of all axes values, which means it is unique across rows */
4
- export type PTableKey = PTableValueAxis[];
4
+ export type PTableKey = (PTableValueAxis | null)[];
5
5
 
6
6
  /**
7
7
  * Information on selected rows.
package/src/index.ts CHANGED
@@ -54,6 +54,7 @@ export * from "./block_api_v2";
54
54
  export * from "./filters";
55
55
  export * from "./annotations";
56
56
  export * from "./pframe_utils";
57
+ export * from "./services";
57
58
 
58
59
  // reexporting everything from SDK model
59
60
  export * from "@milaboratories/pl-model-common";
@@ -80,17 +80,13 @@ const UNIQUE_VALUES_LIMIT = 1000000;
80
80
  const sortValuesPredicate = (a: { label: string }, b: { label: string }) =>
81
81
  a.label.localeCompare(b.label, "en", { numeric: true });
82
82
 
83
- function convertColumnData(
84
- type: ValueType,
85
- response: PTableVector,
86
- absentValue: number | null = null,
87
- ): PValue[] {
83
+ function convertColumnData(type: ValueType, response: PTableVector): PValue[] {
88
84
  if (type === "String") {
89
85
  return response.data as PValue[];
90
86
  }
91
87
  const res: PValue[] = new Array(response.data.length);
92
88
  for (let i = 0; i < response.data.length; i++) {
93
- res[i] = pTableValue(response, i, { absent: absentValue, na: null }) as PValue;
89
+ res[i] = pTableValue(response, i) as PValue;
94
90
  }
95
91
  return res;
96
92
  }
package/src/platforma.ts CHANGED
@@ -9,6 +9,7 @@ import type {
9
9
  OutputWithStatus,
10
10
  } from "@milaboratories/pl-model-common";
11
11
  import type { SdkInfo } from "./version";
12
+ import type { ServiceDispatch, UiServices as AllUiServices } from "@milaboratories/pl-model-common";
12
13
  import type { BlockStatePatch } from "./block_state_patch";
13
14
  import type { PluginRecord } from "./block_model";
14
15
  import type { PluginHandle, PluginFactoryLike } from "./plugin_handle";
@@ -54,13 +55,18 @@ export interface PlatformaV3<
54
55
  >,
55
56
  Href extends `/${string}` = `/${string}`,
56
57
  Plugins extends Record<string, unknown> = Record<string, unknown>,
58
+ UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,
57
59
  >
58
60
  extends BlockApiV3<Data, Args, Outputs, Href>, DriverKit {
59
61
  /** Information about SDK version current platforma environment was compiled with. */
60
62
  readonly sdkInfo: SdkInfo;
61
63
  readonly apiVersion: 3;
64
+ /** Service dispatch — lists available services, their methods, and invokes them. */
65
+ readonly serviceDispatch: ServiceDispatch;
62
66
  /** @internal Type brand for plugin type inference. Not used at runtime. */
63
67
  readonly __pluginsBrand?: Plugins;
68
+ /** @internal Type brand for UI service type inference. Not used at runtime. */
69
+ readonly __uiServicesBrand?: UiServices;
64
70
  }
65
71
 
66
72
  export type Platforma<
@@ -148,7 +154,13 @@ export type InferPluginData<Pl, PluginId extends string> =
148
154
  * because PluginRecord doesn't carry Config (lost after factory.create()).
149
155
  */
150
156
  export type InferPluginHandles<T extends Record<string, unknown>> = {
151
- readonly [K in keyof T]: T[K] extends PluginRecord<infer Data, infer Params, infer Outputs>
152
- ? { handle: PluginHandle<PluginFactoryLike<Data, Params, Outputs>> }
157
+ readonly [K in keyof T]: T[K] extends PluginRecord<
158
+ infer Data,
159
+ infer Params,
160
+ infer Outputs,
161
+ infer ModelServices,
162
+ infer UiServices
163
+ >
164
+ ? { handle: PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>> }
153
165
  : never;
154
166
  };
@@ -23,37 +23,55 @@ export interface PluginFactoryLike<
23
23
  Data extends Record<string, unknown> = Record<string, unknown>,
24
24
  Params extends undefined | Record<string, unknown> = undefined | Record<string, unknown>,
25
25
  Outputs extends Record<string, unknown> = Record<string, unknown>,
26
+ ModelServices = unknown,
27
+ UiServices = unknown,
26
28
  > {
27
29
  readonly __types?: {
28
30
  data: Data;
29
31
  params: Params;
30
32
  outputs: Outputs;
33
+ modelServices: ModelServices;
34
+ uiServices: UiServices;
31
35
  };
32
36
  }
33
37
 
34
38
  /** Extract the Data type from a PluginFactoryLike phantom. */
35
39
  export type InferFactoryData<F extends PluginFactoryLike> = NonNullable<
36
- F extends PluginFactoryLike<infer D, any, any> ? D : Record<string, unknown>
40
+ F extends PluginFactoryLike<infer D, any, any, any, any> ? D : Record<string, unknown>
37
41
  >;
38
42
 
39
43
  /** Extract the Params type from a PluginFactoryLike phantom. */
40
44
  export type InferFactoryParams<F extends PluginFactoryLike> = NonNullable<
41
- F extends PluginFactoryLike<any, infer P, any> ? P : undefined
45
+ F extends PluginFactoryLike<any, infer P, any, any, any> ? P : undefined
42
46
  >;
43
47
 
44
48
  /** Extract the Outputs type from a PluginFactoryLike phantom. */
45
49
  export type InferFactoryOutputs<F extends PluginFactoryLike> = NonNullable<
46
- F extends PluginFactoryLike<any, any, infer O> ? O : Record<string, unknown>
50
+ F extends PluginFactoryLike<any, any, infer O, any, any> ? O : Record<string, unknown>
47
51
  >;
48
52
 
53
+ /** Extract the pre-resolved model services type from a PluginFactoryLike phantom. */
54
+ export type InferFactoryModelServices<F extends PluginFactoryLike> =
55
+ F extends PluginFactoryLike<any, any, any, infer ModelServices, any> ? ModelServices : {};
56
+
57
+ /** Extract the pre-resolved UI services type from a PluginFactoryLike phantom. */
58
+ export type InferFactoryUiServices<F extends PluginFactoryLike> =
59
+ F extends PluginFactoryLike<any, any, any, any, infer UiServices> ? UiServices : {};
60
+
49
61
  /**
50
62
  * Derive a typed PluginHandle from a PluginFactory type.
51
- * Normalizes the brand to only data/params/outputs (strips config) so handles
63
+ * Normalizes the brand to data/params/outputs/services (strips config) so handles
52
64
  * from InferPluginHandles match handles from InferPluginHandle.
53
65
  */
54
66
  export type InferPluginHandle<F extends PluginFactoryLike> = NonNullable<
55
- F extends PluginFactoryLike<infer Data, infer Params, infer Outputs>
56
- ? PluginHandle<PluginFactoryLike<Data, Params, Outputs>>
67
+ F extends PluginFactoryLike<
68
+ infer Data,
69
+ infer Params,
70
+ infer Outputs,
71
+ infer ModelServices,
72
+ infer UiServices
73
+ >
74
+ ? PluginHandle<PluginFactoryLike<Data, Params, Outputs, ModelServices, UiServices>>
57
75
  : PluginHandle
58
76
  >;
59
77