@milaboratories/pl-middle-layer 1.14.32 → 1.15.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 (48) hide show
  1. package/dist/block_registry/registry.d.ts.map +1 -1
  2. package/dist/cfg_render/executor.d.ts.map +1 -1
  3. package/dist/index.js +6 -6
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +898 -825
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/js_render/context.d.ts +3 -0
  8. package/dist/js_render/context.d.ts.map +1 -1
  9. package/dist/js_render/index.d.ts +2 -2
  10. package/dist/js_render/index.d.ts.map +1 -1
  11. package/dist/middle_layer/active_cfg.d.ts.map +1 -1
  12. package/dist/middle_layer/project.d.ts +0 -2
  13. package/dist/middle_layer/project.d.ts.map +1 -1
  14. package/dist/middle_layer/project_overview.d.ts.map +1 -1
  15. package/dist/middle_layer/render.d.ts +3 -2
  16. package/dist/middle_layer/render.d.ts.map +1 -1
  17. package/dist/middle_layer/util.d.ts +3 -2
  18. package/dist/middle_layer/util.d.ts.map +1 -1
  19. package/dist/model/block_pack.d.ts +2 -2
  20. package/dist/model/block_pack_spec.d.ts +2 -2
  21. package/dist/model/block_pack_spec.d.ts.map +1 -1
  22. package/dist/model/project_model.d.ts +4 -1
  23. package/dist/model/project_model.d.ts.map +1 -1
  24. package/dist/mutator/block-pack/block_pack.d.ts +2 -2
  25. package/dist/mutator/block-pack/block_pack.d.ts.map +1 -1
  26. package/dist/mutator/project.d.ts +1 -1
  27. package/dist/mutator/project.d.ts.map +1 -1
  28. package/dist/pool/result_pool.d.ts +3 -1
  29. package/dist/pool/result_pool.d.ts.map +1 -1
  30. package/package.json +11 -11
  31. package/src/block_registry/registry.ts +12 -2
  32. package/src/cfg_render/executor.ts +2 -1
  33. package/src/js_render/context.ts +46 -0
  34. package/src/js_render/index.ts +12 -4
  35. package/src/middle_layer/active_cfg.ts +6 -9
  36. package/src/middle_layer/middle_layer.test.ts +9 -9
  37. package/src/middle_layer/project.ts +13 -13
  38. package/src/middle_layer/project_overview.ts +17 -6
  39. package/src/middle_layer/render.ts +9 -3
  40. package/src/middle_layer/util.ts +5 -3
  41. package/src/model/block_pack.ts +2 -2
  42. package/src/model/block_pack_spec.ts +2 -2
  43. package/src/model/project_model.ts +4 -1
  44. package/src/mutator/block-pack/block_pack.test.ts +1 -1
  45. package/src/mutator/block-pack/block_pack.ts +10 -10
  46. package/src/mutator/project.test.ts +7 -0
  47. package/src/mutator/project.ts +20 -13
  48. package/src/pool/result_pool.ts +45 -3
@@ -24,7 +24,7 @@ import {
24
24
  import { constructBlockContextArgsOnly } from './block_ctx';
25
25
  import { ifNotUndef } from '../cfg_render/util';
26
26
  import { BlockPackInfo } from '../model/block_pack';
27
- import { BlockSection, normalizeBlockConfig } from '@platforma-sdk/model';
27
+ import { BlockSection, extractConfig } from '@platforma-sdk/model';
28
28
  import { computableFromCfgOrRF } from './render';
29
29
  import { NavigationStates } from './navigation_states';
30
30
 
@@ -121,7 +121,7 @@ export function projectOverview(
121
121
 
122
122
  const limbo = new Set(renderingState.blocksInLimbo);
123
123
 
124
- const blocks = [...allBlocks(structure)].map(({ id, label, renderingMode }) => {
124
+ const blocks = [...allBlocks(structure)].map(({ id, label: defaultLabel, renderingMode }) => {
125
125
  const info = notEmpty(infos.get(id));
126
126
  const gNode = notEmpty(currentGraph.nodes.get(id));
127
127
  let calculationStatus: BlockCalculationStatus = 'NotCalculated';
@@ -142,9 +142,9 @@ export function projectOverview(
142
142
 
143
143
  // sections
144
144
  const bpInfo = blockPack?.getDataAsJson<BlockPackInfo>();
145
- const { sections, inputsValid, sdkVersion } =
146
- ifNotUndef(bpInfo?.config, (blockConfU) => {
147
- const blockConf = normalizeBlockConfig(blockConfU);
145
+ const { sections, title, inputsValid, sdkVersion } =
146
+ ifNotUndef(bpInfo?.config, (blockConfContainer) => {
147
+ const blockConf = extractConfig(blockConfContainer);
148
148
  const blockCtxArgsOnly = constructBlockContextArgsOnly(prj, id);
149
149
  return {
150
150
  sections: computableFromCfgOrRF(
@@ -153,6 +153,16 @@ export function projectOverview(
153
153
  blockConf.sections,
154
154
  blockConf.code
155
155
  ) as ComputableStableDefined<BlockSection[]>,
156
+ title: ifNotUndef(
157
+ blockConf.title,
158
+ (title) =>
159
+ computableFromCfgOrRF(
160
+ env,
161
+ blockCtxArgsOnly,
162
+ title,
163
+ blockConf.code
164
+ ) as ComputableStableDefined<string>
165
+ ),
156
166
  inputsValid: computableFromCfgOrRF(
157
167
  env,
158
168
  blockCtxArgsOnly,
@@ -169,7 +179,8 @@ export function projectOverview(
169
179
 
170
180
  return {
171
181
  id,
172
- label,
182
+ label: title ?? defaultLabel,
183
+ title: title ?? defaultLabel,
173
184
  renderingMode,
174
185
  stale: info.prod?.stale !== false || calculationStatus === 'Limbo',
175
186
  missingReference: gNode.missingReferences,
@@ -1,18 +1,24 @@
1
- import { Code, isFunctionHandle, TypedConfigOrFunctionHandle } from '@platforma-sdk/model';
1
+ import { Code, isConfigLambda, TypedConfigOrConfigLambda } from '@platforma-sdk/model';
2
2
  import { Computable, ComputableRenderingOps } from '@milaboratories/computable';
3
3
  import { computableFromCfg } from '../cfg_render/executor';
4
4
  import { MiddleLayerEnvironment } from './middle_layer';
5
5
  import { computableFromRF } from '../js_render';
6
6
  import { BlockContextAny } from './block_ctx';
7
+ import { hasActiveCfgComponents } from '../cfg_render/util';
8
+
9
+ export function isActive(cfg: TypedConfigOrConfigLambda): boolean {
10
+ if (isConfigLambda(cfg)) return cfg.isActive === true;
11
+ else return hasActiveCfgComponents(cfg);
12
+ }
7
13
 
8
14
  export function computableFromCfgOrRF(
9
15
  env: MiddleLayerEnvironment,
10
16
  ctx: BlockContextAny,
11
- cfgOrFh: TypedConfigOrFunctionHandle,
17
+ cfgOrFh: TypedConfigOrConfigLambda,
12
18
  code: Code | undefined,
13
19
  ops: Partial<ComputableRenderingOps> = {}
14
20
  ): Computable<unknown> {
15
- if (isFunctionHandle(cfgOrFh)) {
21
+ if (isConfigLambda(cfgOrFh)) {
16
22
  if (code === undefined) throw new Error('No code bundle.');
17
23
  return computableFromRF(env, ctx, cfgOrFh, code, ops);
18
24
  } else return computableFromCfg(env.driverKit, ctx, cfgOrFh, ops);
@@ -3,9 +3,9 @@ import { projectFieldName } from '../model/project_model';
3
3
  import { Pl } from '@milaboratories/pl-client';
4
4
  import { ifNotUndef } from '../cfg_render/util';
5
5
  import { BlockPackInfo } from '../model/block_pack';
6
- import { normalizeBlockConfig } from '@platforma-sdk/model';
6
+ import { BlockConfig, extractConfig } from '@platforma-sdk/model';
7
7
 
8
- export function getBlockCfg(prj: PlTreeNodeAccessor, blockId: string) {
8
+ export function getBlockCfg(prj: PlTreeNodeAccessor, blockId: string): BlockConfig | undefined {
9
9
  return ifNotUndef(
10
10
  prj
11
11
  .traverse(
@@ -17,6 +17,8 @@ export function getBlockCfg(prj: PlTreeNodeAccessor, blockId: string) {
17
17
  { field: Pl.HolderRefField, assertFieldType: 'Input', errorIfFieldNotFound: true }
18
18
  )
19
19
  ?.getDataAsJson<BlockPackInfo>()?.config,
20
- (cfg) => normalizeBlockConfig(cfg)
20
+ (cfg) => extractConfig(cfg)
21
21
  );
22
22
  }
23
+
24
+ export const LogOutputStatus = process.env.MI_LOG_OUTPUT_STATUS;
@@ -1,8 +1,8 @@
1
- import { BlockConfigUniversal } from '@platforma-sdk/model';
1
+ import { BlockConfigContainer } from '@platforma-sdk/model';
2
2
  import { BlockPackSpec } from '@milaboratories/pl-model-middle-layer';
3
3
 
4
4
  /** Define structure of block-pack data section */
5
5
  export interface BlockPackInfo {
6
6
  readonly source: BlockPackSpec;
7
- readonly config: BlockConfigUniversal;
7
+ readonly config: BlockConfigContainer;
8
8
  }
@@ -1,6 +1,6 @@
1
1
  import { ExplicitTemplate } from './template_spec';
2
2
  import { ResourceType } from '@milaboratories/pl-client';
3
- import { BlockConfig } from '@platforma-sdk/model';
3
+ import { BlockConfigContainer } from '@platforma-sdk/model';
4
4
  import { BlockPackSpec } from '@milaboratories/pl-model-middle-layer';
5
5
 
6
6
  export type FrontendSpec = FrontendFromUrl | FrontendFromFolder;
@@ -40,7 +40,7 @@ export interface FrontendFromFolder extends FrontendFromFolderData {
40
40
  export interface BlockPackExplicit {
41
41
  type: 'explicit';
42
42
  template: ExplicitTemplate;
43
- config: BlockConfig;
43
+ config: BlockConfigContainer;
44
44
  frontend: FrontendSpec;
45
45
  source: BlockPackSpec;
46
46
  }
@@ -15,7 +15,10 @@ export interface Block {
15
15
  /** Unique block id */
16
16
  readonly id: string;
17
17
 
18
- /** Label shown to the user */
18
+ /**
19
+ * Label shown to the user
20
+ * @deprecated
21
+ * */
19
22
  label: string;
20
23
 
21
24
  /** How to approach block rendering */
@@ -30,7 +30,7 @@ test.each([
30
30
  } as BlockPackSpecAny
31
31
  }
32
32
  ])('test load template from $spec.type', async ({ spec }) => {
33
- const config = await preparation.getBlockConfig(spec);
33
+ const config = await preparation.getBlockConfigContainer(spec);
34
34
  expect(config).toBeDefined();
35
35
  expect(config.renderingMode).toEqual('Heavy');
36
36
 
@@ -5,7 +5,7 @@ import { assertNever, Signer } from '@milaboratories/ts-helpers';
5
5
  import fs from 'node:fs';
6
6
  import { Dispatcher, request } from 'undici';
7
7
  import { createFrontend } from './frontend';
8
- import { BlockConfig } from '@platforma-sdk/model';
8
+ import { BlockConfig, BlockConfigContainer } from '@platforma-sdk/model';
9
9
  import { loadPackDescription, RegistryV1 } from '@platforma-sdk/block-tools';
10
10
  import { BlockPackInfo } from '../../model/block_pack';
11
11
  import { resolveDevPacket } from '../../dev_env';
@@ -29,7 +29,7 @@ export class BlockPackPreparer {
29
29
  private readonly http?: Dispatcher
30
30
  ) {}
31
31
 
32
- public async getBlockConfig(spec: BlockPackSpecAny): Promise<BlockConfig> {
32
+ public async getBlockConfigContainer(spec: BlockPackSpecAny): Promise<BlockConfigContainer> {
33
33
  switch (spec.type) {
34
34
  case 'explicit':
35
35
  return spec.config;
@@ -37,7 +37,7 @@ export class BlockPackPreparer {
37
37
  case 'dev-v1': {
38
38
  const devPaths = await resolveDevPacket(spec.folder, false);
39
39
  const configContent = await fs.promises.readFile(devPaths.config, { encoding: 'utf-8' });
40
- return JSON.parse(configContent) as BlockConfig;
40
+ return JSON.parse(configContent) as BlockConfigContainer;
41
41
  }
42
42
 
43
43
  case 'dev-v2': {
@@ -45,7 +45,7 @@ export class BlockPackPreparer {
45
45
  const configContent = await fs.promises.readFile(description.components.model.file, {
46
46
  encoding: 'utf-8'
47
47
  });
48
- return JSON.parse(configContent) as BlockConfig;
48
+ return JSON.parse(configContent) as BlockConfigContainer;
49
49
  }
50
50
 
51
51
  case 'from-registry-v1': {
@@ -55,7 +55,7 @@ export class BlockPackPreparer {
55
55
 
56
56
  const configResponse = await request(`${urlPrefix}/config.json`, httpOptions);
57
57
 
58
- return (await configResponse.body.json()) as BlockConfig;
58
+ return (await configResponse.body.json()) as BlockConfigContainer;
59
59
  }
60
60
 
61
61
  case 'from-registry-v2': {
@@ -64,7 +64,7 @@ export class BlockPackPreparer {
64
64
  const components = await registry.getComponents(spec.id);
65
65
  return (await (
66
66
  await request(components.model.url, httpOptions)
67
- ).body.json()) as BlockConfig;
67
+ ).body.json()) as BlockConfigContainer;
68
68
  }
69
69
 
70
70
  default:
@@ -86,7 +86,7 @@ export class BlockPackPreparer {
86
86
  // config
87
87
  const config = JSON.parse(
88
88
  await fs.promises.readFile(devPaths.config, 'utf-8')
89
- ) as BlockConfig;
89
+ ) as BlockConfigContainer;
90
90
 
91
91
  // frontend
92
92
  const frontendPath = devPaths.ui;
@@ -113,7 +113,7 @@ export class BlockPackPreparer {
113
113
  await fs.promises.readFile(description.components.model.file, {
114
114
  encoding: 'utf-8'
115
115
  })
116
- ) as BlockConfig;
116
+ ) as BlockConfigContainer;
117
117
  const workflowContent = await fs.promises.readFile(
118
118
  description.components.workflow.main.file
119
119
  );
@@ -155,7 +155,7 @@ export class BlockPackPreparer {
155
155
 
156
156
  // config
157
157
  const configResponse = await request(`${urlPrefix}/config.json`, httpOptions);
158
- const config = (await configResponse.body.json()) as BlockConfig;
158
+ const config = (await configResponse.body.json()) as BlockConfigContainer;
159
159
 
160
160
  return {
161
161
  type: 'explicit',
@@ -177,7 +177,7 @@ export class BlockPackPreparer {
177
177
  const registry = this.v2RegistryProvider.getRegistry(spec.registryUrl);
178
178
  const components = await registry.getComponents(spec.id);
179
179
  const getModel = async () =>
180
- (await (await request(components.model.url, httpOptions)).body.json()) as BlockConfig;
180
+ (await (await request(components.model.url, httpOptions)).body.json()) as BlockConfigContainer;
181
181
  const getWorkflow = async () =>
182
182
  await (await request(components.workflow.main.url, httpOptions)).body.arrayBuffer();
183
183
 
@@ -1,3 +1,4 @@
1
+ import { test, expect } from '@jest/globals';
1
2
  import { field, poll, TestHelpers, toGlobalResourceId } from '@milaboratories/pl-client';
2
3
  import { createProject, ProjectMutator, withProject } from './project';
3
4
  import { outputRef } from '../model/args';
@@ -28,6 +29,7 @@ test('simple test #1', async () => {
28
29
  { id: 'block1', label: 'Block1', renderingMode: 'Heavy' },
29
30
  {
30
31
  args: JSON.stringify({ numbers: [1, 2, 3] }),
32
+ uiState: "{}",
31
33
  blockPack: await TestBPPreparer.prepare(BPSpecEnterV041NotPrepared)
32
34
  }
33
35
  );
@@ -41,6 +43,7 @@ test('simple test #1', async () => {
41
43
  { id: 'block2', label: 'Block2', renderingMode: 'Heavy' },
42
44
  {
43
45
  args: JSON.stringify({ numbers: [3, 4, 5] }),
46
+ uiState: "{}",
44
47
  blockPack: await TestBPPreparer.prepare(BPSpecEnterV041NotPrepared)
45
48
  }
46
49
  );
@@ -57,6 +60,7 @@ test('simple test #1', async () => {
57
60
  args: JSON.stringify({
58
61
  sources: [outputRef('block1', 'column'), outputRef('block2', 'column')]
59
62
  }),
63
+ uiState: "{}",
60
64
  blockPack: await TestBPPreparer.prepare(BPSpecSumV042NotPrepared)
61
65
  }
62
66
  );
@@ -191,6 +195,7 @@ test('simple test #2 with bp migration', async () => {
191
195
  { id: 'block1', label: 'Block1', renderingMode: 'Heavy' },
192
196
  {
193
197
  args: JSON.stringify({ numbers: [1, 2, 3] }),
198
+ uiState: "{}",
194
199
  blockPack: await TestBPPreparer.prepare(BPSpecEnterV041NotPrepared)
195
200
  }
196
201
  );
@@ -198,6 +203,7 @@ test('simple test #2 with bp migration', async () => {
198
203
  { id: 'block2', label: 'Block2', renderingMode: 'Heavy' },
199
204
  {
200
205
  args: JSON.stringify({ numbers: [3, 4, 5] }),
206
+ uiState: "{}",
201
207
  blockPack: await TestBPPreparer.prepare(BPSpecEnterV041NotPrepared)
202
208
  }
203
209
  );
@@ -207,6 +213,7 @@ test('simple test #2 with bp migration', async () => {
207
213
  args: JSON.stringify({
208
214
  sources: [outputRef('block1', 'column'), outputRef('block2', 'column')]
209
215
  }),
216
+ uiState: "{}",
210
217
  blockPack: await TestBPPreparer.prepare(BPSpecSumV042NotPrepared)
211
218
  }
212
219
  );
@@ -178,6 +178,7 @@ class BlockInfo {
178
178
  export interface NewBlockSpec {
179
179
  blockPack: BlockPackSpecPrepared;
180
180
  args: string;
181
+ uiState: string;
181
182
  }
182
183
 
183
184
  const NoNewBlocks = (blockId: string) => {
@@ -443,19 +444,19 @@ export class ProjectMutator {
443
444
  }
444
445
 
445
446
  /** Update block label */
446
- public setBlockLabel(blockId: string, label: string): void {
447
- const newStructure = this.structure;
448
- let ok = false;
449
- for (const block of allBlocks(newStructure))
450
- if (block.id === blockId) {
451
- block.label = label;
452
- ok = true;
453
- break;
454
- }
455
- if (!ok) throw new Error(`block ${blockId} not found`);
456
- this.updateStructure(newStructure);
457
- this.updateLastModified();
458
- }
447
+ // public setBlockLabel(blockId: string, label: string): void {
448
+ // const newStructure = this.structure;
449
+ // let ok = false;
450
+ // for (const block of allBlocks(newStructure))
451
+ // if (block.id === blockId) {
452
+ // block.label = label;
453
+ // ok = true;
454
+ // break;
455
+ // }
456
+ // if (!ok) throw new Error(`block ${blockId} not found`);
457
+ // this.updateStructure(newStructure);
458
+ // this.updateLastModified();
459
+ // }
459
460
 
460
461
  private createCtx(upstream: Set<string>, ctxField: 'stagingCtx' | 'prodCtx'): AnyRef {
461
462
  const upstreamContexts: AnyRef[] = [];
@@ -586,6 +587,12 @@ export class ProjectMutator {
586
587
  const argsRes = this.tx.createValue(Pl.JsonObject, binArgs);
587
588
  this.setBlockField(blockId, 'currentArgs', argsRes, 'Ready', binArgs);
588
589
 
590
+ // uiState
591
+ if (spec.uiState /* this check is for compatibility with old configs */) {
592
+ this.blockFrontendStates.set(blockId, spec.uiState);
593
+ this.changedBlockFrontendStates.add(blockId);
594
+ }
595
+
589
596
  // checking structure
590
597
  info.check();
591
598
  }
@@ -9,7 +9,8 @@ import {
9
9
  ResultCollection,
10
10
  ResultPoolEntry,
11
11
  ValueOrError,
12
- executePSpecPredicate
12
+ executePSpecPredicate,
13
+ mapValueInVOE
13
14
  } from '@platforma-sdk/model';
14
15
  import { notEmpty } from '@milaboratories/ts-helpers';
15
16
  import { outputRef } from '../model/args';
@@ -74,8 +75,49 @@ export class ResultPool {
74
75
  this.allSpecsAvailable = allSpecsAvailable;
75
76
  }
76
77
 
77
- public getBlockLabel(blockId: string): string {
78
- return notEmpty(this.blocks.get(blockId)?.info?.label, `block "${blockId}" not found`);
78
+ public getSpecByRef(blockId: string, exportName: string): PObjectSpec | undefined {
79
+ const block = this.blocks.get(blockId);
80
+ if (block === undefined) return undefined;
81
+ let result = block.prod?.results?.get(exportName)?.spec;
82
+ if (result !== undefined) return result;
83
+ result = block.staging?.results?.get(exportName)?.spec;
84
+ if (result !== undefined) return result;
85
+ if (block.staging === undefined) this.ctx.markUnstable(`staging_not_rendered:${blockId}`);
86
+ else if (!block.staging.locked) this.ctx.markUnstable(`staging_not_locked:${blockId}`);
87
+ else if (block.prod !== undefined && !block.prod.locked)
88
+ this.ctx.markUnstable(`prod_not_locked:${blockId}`);
89
+ // if prod is absent, returned undefined value is considered stable
90
+ return undefined;
91
+ }
92
+
93
+ public getDataOrErrorByRef(
94
+ blockId: string,
95
+ exportName: string
96
+ ): ValueOrError<PObject<PlTreeNodeAccessor>, string> | undefined {
97
+ const block = this.blocks.get(blockId);
98
+ if (block === undefined) return undefined;
99
+ let result = block.prod?.results?.get(exportName);
100
+ let data = result?.data?.();
101
+ if (result !== undefined && result.spec !== undefined && data !== undefined)
102
+ return mapValueInVOE(data, (value) => ({
103
+ id: derivePObjectId(result!.spec!, value),
104
+ spec: result!.spec!,
105
+ data: value
106
+ }));
107
+ if (result !== undefined) this.ctx.markUnstable(`no_data:${blockId}:${exportName}`);
108
+ if (block.prod !== undefined && !block.prod.locked)
109
+ this.ctx.markUnstable(`prod_not_locked:${blockId}`);
110
+ // if prod is absent, returned undefined value is considered stable
111
+ return undefined;
112
+ }
113
+
114
+ public getDataByRef(
115
+ blockId: string,
116
+ exportName: string
117
+ ): PObject<PlTreeNodeAccessor> | undefined {
118
+ const res = this.getDataOrErrorByRef(blockId, exportName);
119
+ if (res === undefined || !res.ok) return undefined;
120
+ return res.value;
79
121
  }
80
122
 
81
123
  public getData(): ExtendedResultCollection<PObject<PlTreeNodeAccessor>> {