@platforma-sdk/model 1.24.9 → 1.24.11
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/bconfig/container.d.ts.map +1 -1
- package/dist/bconfig/lambdas.d.ts +1 -1
- package/dist/bconfig/lambdas.d.ts.map +1 -1
- package/dist/bconfig/normalization.d.ts.map +1 -1
- package/dist/bconfig/types.d.ts.map +1 -1
- package/dist/bconfig/utils.d.ts.map +1 -1
- package/dist/bconfig/v3.d.ts.map +1 -1
- package/dist/block_api.d.ts.map +1 -1
- package/dist/block_state_patch.d.ts.map +1 -1
- package/dist/block_state_util.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/components/PFrameForGraphs.d.ts.map +1 -1
- package/dist/config/actions.d.ts.map +1 -1
- package/dist/config/actions_kinds.d.ts.map +1 -1
- package/dist/config/model.d.ts.map +1 -1
- package/dist/config/type_engine.d.ts.map +1 -1
- package/dist/config/type_util.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/pframe.d.ts.map +1 -1
- package/dist/platforma.d.ts.map +1 -1
- package/dist/raw_globals.d.ts.map +1 -1
- package/dist/ref_util.d.ts.map +1 -1
- package/dist/render/accessor.d.ts.map +1 -1
- package/dist/render/api.d.ts +2 -2
- package/dist/render/api.d.ts.map +1 -1
- package/dist/render/future.d.ts +2 -2
- package/dist/render/future.d.ts.map +1 -1
- package/dist/render/internal.d.ts +2 -2
- package/dist/render/internal.d.ts.map +1 -1
- package/dist/render/util/label.d.ts.map +1 -1
- package/dist/render/util/resource_map.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/bconfig/container.ts +3 -3
- package/src/bconfig/lambdas.ts +2 -2
- package/src/bconfig/normalization.ts +26 -25
- package/src/bconfig/types.ts +3 -3
- package/src/bconfig/utils.ts +1 -1
- package/src/bconfig/v3.ts +4 -4
- package/src/block_api.ts +3 -3
- package/src/block_state_patch.ts +3 -3
- package/src/block_state_util.ts +4 -4
- package/src/builder.ts +50 -44
- package/src/components/PFrameForGraphs.ts +171 -169
- package/src/config/actions.ts +71 -71
- package/src/config/actions_kinds.ts +9 -9
- package/src/config/model.ts +3 -1
- package/src/config/type_engine.ts +3 -2
- package/src/config/type_util.ts +1 -1
- package/src/internal.ts +4 -4
- package/src/pframe.ts +3 -3
- package/src/platforma.ts +7 -7
- package/src/raw_globals.ts +1 -1
- package/src/ref_util.ts +4 -3
- package/src/render/accessor.ts +30 -28
- package/src/render/api.ts +10 -6
- package/src/render/future.ts +3 -3
- package/src/render/internal.ts +8 -8
- package/src/render/util/label.ts +7 -7
- package/src/render/util/resource_map.ts +6 -7
- package/src/sdk_info.ts +1 -1
package/src/builder.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { BlockRenderingMode, BlockSection, ValueOrErrors } from '@milaboratories/pl-model-common';
|
|
2
|
-
import { Checked, ConfigResult,
|
|
1
|
+
import type { BlockRenderingMode, BlockSection, ValueOrErrors, AnyFunction } from '@milaboratories/pl-model-common';
|
|
2
|
+
import type { Checked, ConfigResult, TypedConfig } from './config';
|
|
3
|
+
import { getImmediate } from './config';
|
|
3
4
|
import { getPlatformaInstance, isInUI, tryRegisterCallback } from './internal';
|
|
4
|
-
import { Platforma } from './platforma';
|
|
5
|
-
import { InferRenderFunctionReturn,
|
|
5
|
+
import type { Platforma } from './platforma';
|
|
6
|
+
import type { InferRenderFunctionReturn, RenderFunction } from './render';
|
|
7
|
+
import { RenderCtx } from './render';
|
|
6
8
|
import { PlatformaSDKVersion } from './version';
|
|
7
|
-
import {
|
|
9
|
+
import type {
|
|
8
10
|
TypedConfigOrConfigLambda,
|
|
9
11
|
ConfigRenderLambda,
|
|
10
12
|
StdCtxArgsOnly,
|
|
@@ -12,8 +14,10 @@ import {
|
|
|
12
14
|
ResolveCfgType,
|
|
13
15
|
ExtractFunctionHandleReturn,
|
|
14
16
|
BlockConfigContainer,
|
|
17
|
+
ConfigRenderLambdaFlags,
|
|
18
|
+
} from './bconfig';
|
|
19
|
+
import {
|
|
15
20
|
downgradeCfgOrLambda,
|
|
16
|
-
ConfigRenderLambdaFlags
|
|
17
21
|
} from './bconfig';
|
|
18
22
|
|
|
19
23
|
type SectionsExpectedType = readonly BlockSection[];
|
|
@@ -23,10 +27,11 @@ type SectionsCfgChecked<Cfg extends TypedConfig, Args, UiState> = Checked<
|
|
|
23
27
|
ConfigResult<Cfg, StdCtxArgsOnly<Args, UiState>> extends SectionsExpectedType ? true : false
|
|
24
28
|
>;
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
// TODO (Unused type in code)
|
|
31
|
+
// type SectionsRFChecked<RF extends Function> = Checked<
|
|
32
|
+
// RF,
|
|
33
|
+
// InferRenderFunctionReturn<RF> extends SectionsExpectedType ? true : false
|
|
34
|
+
// >;
|
|
30
35
|
|
|
31
36
|
type InputsValidExpectedType = boolean;
|
|
32
37
|
|
|
@@ -35,10 +40,11 @@ type InputsValidCfgChecked<Cfg extends TypedConfig, Args, UiState> = Checked<
|
|
|
35
40
|
ConfigResult<Cfg, StdCtxArgsOnly<Args, UiState>> extends InputsValidExpectedType ? true : false
|
|
36
41
|
>;
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
// TODO (Unused type in code)
|
|
44
|
+
// type InputsValidRFChecked<RF extends Function> = Checked<
|
|
45
|
+
// RF,
|
|
46
|
+
// InferRenderFunctionReturn<RF> extends InputsValidExpectedType ? true : false
|
|
47
|
+
// >;
|
|
42
48
|
|
|
43
49
|
type NoOb = Record<string, never>;
|
|
44
50
|
|
|
@@ -49,7 +55,7 @@ export class BlockModel<
|
|
|
49
55
|
Args,
|
|
50
56
|
OutputsCfg extends Record<string, TypedConfigOrConfigLambda>,
|
|
51
57
|
UiState,
|
|
52
|
-
Href extends `/${string}` = '/'
|
|
58
|
+
Href extends `/${string}` = '/',
|
|
53
59
|
> {
|
|
54
60
|
private constructor(
|
|
55
61
|
private readonly _renderingMode: BlockRenderingMode,
|
|
@@ -58,7 +64,7 @@ export class BlockModel<
|
|
|
58
64
|
private readonly _outputs: OutputsCfg,
|
|
59
65
|
private readonly _inputsValid: TypedConfigOrConfigLambda,
|
|
60
66
|
private readonly _sections: TypedConfigOrConfigLambda,
|
|
61
|
-
private readonly _title: ConfigRenderLambda | undefined
|
|
67
|
+
private readonly _title: ConfigRenderLambda | undefined,
|
|
62
68
|
) {}
|
|
63
69
|
|
|
64
70
|
/** Initiates configuration builder */
|
|
@@ -83,7 +89,7 @@ export class BlockModel<
|
|
|
83
89
|
{},
|
|
84
90
|
getImmediate(true),
|
|
85
91
|
getImmediate([]),
|
|
86
|
-
undefined
|
|
92
|
+
undefined,
|
|
87
93
|
);
|
|
88
94
|
}
|
|
89
95
|
|
|
@@ -119,8 +125,8 @@ export class BlockModel<
|
|
|
119
125
|
>;
|
|
120
126
|
public output(
|
|
121
127
|
key: string,
|
|
122
|
-
cfgOrRf: TypedConfig |
|
|
123
|
-
flags: ConfigRenderLambdaFlags = {}
|
|
128
|
+
cfgOrRf: TypedConfig | AnyFunction,
|
|
129
|
+
flags: ConfigRenderLambdaFlags = {},
|
|
124
130
|
): BlockModel<Args, OutputsCfg, UiState, Href> {
|
|
125
131
|
if (typeof cfgOrRf === 'function') {
|
|
126
132
|
const handle = `output#${key}`;
|
|
@@ -134,12 +140,12 @@ export class BlockModel<
|
|
|
134
140
|
[key]: {
|
|
135
141
|
__renderLambda: true,
|
|
136
142
|
handle,
|
|
137
|
-
...flags
|
|
138
|
-
} satisfies ConfigRenderLambda
|
|
143
|
+
...flags,
|
|
144
|
+
} satisfies ConfigRenderLambda,
|
|
139
145
|
},
|
|
140
146
|
this._inputsValid,
|
|
141
147
|
this._sections,
|
|
142
|
-
this._title
|
|
148
|
+
this._title,
|
|
143
149
|
);
|
|
144
150
|
} else
|
|
145
151
|
return new BlockModel(
|
|
@@ -148,24 +154,24 @@ export class BlockModel<
|
|
|
148
154
|
this._initialUiState,
|
|
149
155
|
{
|
|
150
156
|
...this._outputs,
|
|
151
|
-
[key]: cfgOrRf
|
|
157
|
+
[key]: cfgOrRf,
|
|
152
158
|
},
|
|
153
159
|
this._inputsValid,
|
|
154
160
|
this._sections,
|
|
155
|
-
this._title
|
|
161
|
+
this._title,
|
|
156
162
|
);
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
/** Shortcut for {@link output} with retentive flag set to true. */
|
|
160
166
|
public retentiveOutput<const Key extends string, const RF extends RenderFunction<Args, UiState>>(
|
|
161
167
|
key: Key,
|
|
162
|
-
rf: RF
|
|
168
|
+
rf: RF,
|
|
163
169
|
): BlockModel<
|
|
164
|
-
|
|
170
|
+
Args,
|
|
165
171
|
OutputsCfg & { [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>> },
|
|
166
172
|
UiState,
|
|
167
173
|
Href
|
|
168
|
-
|
|
174
|
+
> {
|
|
169
175
|
return this.output(key, rf, { retentive: true });
|
|
170
176
|
}
|
|
171
177
|
|
|
@@ -179,7 +185,7 @@ export class BlockModel<
|
|
|
179
185
|
rf: RF
|
|
180
186
|
): BlockModel<Args, OutputsCfg, UiState, Href>;
|
|
181
187
|
public argsValid(
|
|
182
|
-
cfgOrRf: TypedConfig |
|
|
188
|
+
cfgOrRf: TypedConfig | AnyFunction,
|
|
183
189
|
): BlockModel<Args, OutputsCfg, UiState, `/${string}`> {
|
|
184
190
|
if (typeof cfgOrRf === 'function') {
|
|
185
191
|
tryRegisterCallback('inputsValid', () => cfgOrRf(new RenderCtx()));
|
|
@@ -190,10 +196,10 @@ export class BlockModel<
|
|
|
190
196
|
this._outputs,
|
|
191
197
|
{
|
|
192
198
|
__renderLambda: true,
|
|
193
|
-
handle: 'inputsValid'
|
|
199
|
+
handle: 'inputsValid',
|
|
194
200
|
} satisfies ConfigRenderLambda,
|
|
195
201
|
this._sections,
|
|
196
|
-
this._title
|
|
202
|
+
this._title,
|
|
197
203
|
);
|
|
198
204
|
} else
|
|
199
205
|
return new BlockModel<Args, OutputsCfg, UiState>(
|
|
@@ -203,7 +209,7 @@ export class BlockModel<
|
|
|
203
209
|
this._outputs,
|
|
204
210
|
cfgOrRf,
|
|
205
211
|
this._sections,
|
|
206
|
-
this._title
|
|
212
|
+
this._title,
|
|
207
213
|
);
|
|
208
214
|
}
|
|
209
215
|
|
|
@@ -215,7 +221,7 @@ export class BlockModel<
|
|
|
215
221
|
/** Sets the config to generate list of section in the left block overviews panel */
|
|
216
222
|
public sections<
|
|
217
223
|
const Ret extends SectionsExpectedType,
|
|
218
|
-
const RF extends RenderFunction<Args, UiState, Ret
|
|
224
|
+
const RF extends RenderFunction<Args, UiState, Ret>,
|
|
219
225
|
>(rf: RF): BlockModel<Args, OutputsCfg, UiState, DeriveHref<ReturnType<RF>>>;
|
|
220
226
|
public sections<const Cfg extends TypedConfig>(
|
|
221
227
|
cfg: Cfg & SectionsCfgChecked<Cfg, Args, UiState>
|
|
@@ -226,7 +232,7 @@ export class BlockModel<
|
|
|
226
232
|
DeriveHref<ConfigResult<Cfg, StdCtxArgsOnly<Args, UiState>>>
|
|
227
233
|
>;
|
|
228
234
|
public sections(
|
|
229
|
-
arrOrCfgOrRf: SectionsExpectedType | TypedConfig |
|
|
235
|
+
arrOrCfgOrRf: SectionsExpectedType | TypedConfig | AnyFunction,
|
|
230
236
|
): BlockModel<Args, OutputsCfg, UiState, `/${string}`> {
|
|
231
237
|
if (Array.isArray(arrOrCfgOrRf)) {
|
|
232
238
|
return this.sections(getImmediate(arrOrCfgOrRf));
|
|
@@ -239,7 +245,7 @@ export class BlockModel<
|
|
|
239
245
|
this._outputs,
|
|
240
246
|
this._inputsValid,
|
|
241
247
|
{ __renderLambda: true, handle: 'sections' } as ConfigRenderLambda,
|
|
242
|
-
this._title
|
|
248
|
+
this._title,
|
|
243
249
|
);
|
|
244
250
|
} else
|
|
245
251
|
return new BlockModel<Args, OutputsCfg, UiState>(
|
|
@@ -249,13 +255,13 @@ export class BlockModel<
|
|
|
249
255
|
this._outputs,
|
|
250
256
|
this._inputsValid,
|
|
251
257
|
arrOrCfgOrRf as TypedConfig,
|
|
252
|
-
this._title
|
|
258
|
+
this._title,
|
|
253
259
|
);
|
|
254
260
|
}
|
|
255
261
|
|
|
256
262
|
/** Sets a rendering function to derive block title, shown for the block in the left blocks-overview panel. */
|
|
257
263
|
public title(
|
|
258
|
-
rf: RenderFunction<Args, UiState, string
|
|
264
|
+
rf: RenderFunction<Args, UiState, string>,
|
|
259
265
|
): BlockModel<Args, OutputsCfg, UiState, Href> {
|
|
260
266
|
tryRegisterCallback('title', () => rf(new RenderCtx()));
|
|
261
267
|
return new BlockModel<Args, OutputsCfg, UiState, Href>(
|
|
@@ -265,7 +271,7 @@ export class BlockModel<
|
|
|
265
271
|
this._outputs,
|
|
266
272
|
this._inputsValid,
|
|
267
273
|
this._sections,
|
|
268
|
-
{ __renderLambda: true, handle: 'title' } as ConfigRenderLambda
|
|
274
|
+
{ __renderLambda: true, handle: 'title' } as ConfigRenderLambda,
|
|
269
275
|
);
|
|
270
276
|
}
|
|
271
277
|
|
|
@@ -281,7 +287,7 @@ export class BlockModel<
|
|
|
281
287
|
this._outputs,
|
|
282
288
|
this._inputsValid,
|
|
283
289
|
this._sections,
|
|
284
|
-
this._title
|
|
290
|
+
this._title,
|
|
285
291
|
);
|
|
286
292
|
}
|
|
287
293
|
|
|
@@ -294,7 +300,7 @@ export class BlockModel<
|
|
|
294
300
|
this._outputs,
|
|
295
301
|
this._inputsValid,
|
|
296
302
|
this._sections,
|
|
297
|
-
this._title
|
|
303
|
+
this._title,
|
|
298
304
|
);
|
|
299
305
|
}
|
|
300
306
|
|
|
@@ -307,7 +313,7 @@ export class BlockModel<
|
|
|
307
313
|
this._outputs,
|
|
308
314
|
this._inputsValid,
|
|
309
315
|
this._sections,
|
|
310
|
-
this._title
|
|
316
|
+
this._title,
|
|
311
317
|
);
|
|
312
318
|
}
|
|
313
319
|
|
|
@@ -331,7 +337,7 @@ export class BlockModel<
|
|
|
331
337
|
inputsValid: this._inputsValid,
|
|
332
338
|
sections: this._sections,
|
|
333
339
|
title: this._title,
|
|
334
|
-
outputs: this._outputs
|
|
340
|
+
outputs: this._outputs,
|
|
335
341
|
},
|
|
336
342
|
|
|
337
343
|
// fields below are added to allow previous desktop versions read generated configs
|
|
@@ -341,8 +347,8 @@ export class BlockModel<
|
|
|
341
347
|
inputsValid: downgradeCfgOrLambda(this._inputsValid),
|
|
342
348
|
sections: downgradeCfgOrLambda(this._sections),
|
|
343
349
|
outputs: Object.fromEntries(
|
|
344
|
-
Object.entries(this._outputs).map(([key, value]) => [key, downgradeCfgOrLambda(value)])
|
|
345
|
-
)
|
|
350
|
+
Object.entries(this._outputs).map(([key, value]) => [key, downgradeCfgOrLambda(value)]),
|
|
351
|
+
),
|
|
346
352
|
};
|
|
347
353
|
|
|
348
354
|
if (!isInUI())
|
|
@@ -362,7 +368,7 @@ export type InferOutputType<CfgOrFH, Args, UiState> = CfgOrFH extends TypedConfi
|
|
|
362
368
|
type InferOutputsFromConfigs<
|
|
363
369
|
Args,
|
|
364
370
|
OutputsCfg extends Record<string, TypedConfigOrConfigLambda>,
|
|
365
|
-
UiState
|
|
371
|
+
UiState,
|
|
366
372
|
> = {
|
|
367
373
|
[Key in keyof OutputsCfg]: ValueOrErrors<InferOutputType<OutputsCfg[Key], Args, UiState>>;
|
|
368
374
|
};
|
|
@@ -1,64 +1,66 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AxisId,
|
|
3
|
+
PColumn,
|
|
4
|
+
PColumnValues,
|
|
5
|
+
PFrameHandle,
|
|
6
|
+
PObjectId,
|
|
7
|
+
ValueType } from '@milaboratories/pl-model-common';
|
|
1
8
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
matchAxisId,
|
|
6
|
-
PColumn,
|
|
7
|
-
PColumnValues,
|
|
8
|
-
PFrameHandle,
|
|
9
|
-
PObjectId,
|
|
10
|
-
ValueType,
|
|
9
|
+
getAxisId,
|
|
10
|
+
isPColumn,
|
|
11
|
+
matchAxisId,
|
|
11
12
|
} from '@milaboratories/pl-model-common';
|
|
12
|
-
import {RenderCtx
|
|
13
|
+
import type { RenderCtx } from '../render';
|
|
14
|
+
import { TreeNodeAccessor } from '../render';
|
|
13
15
|
|
|
14
16
|
/** Create id for column copy with added keys in axes domains */
|
|
15
17
|
const colId = (id: PObjectId, domains: (Record<string, string> | undefined)[]) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
let wid = id.toString();
|
|
19
|
+
domains?.forEach((domain) => {
|
|
20
|
+
if (domain) {
|
|
21
|
+
for (const [k, v] of Object.entries(domain)) {
|
|
22
|
+
wid += k;
|
|
23
|
+
wid += v;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return wid;
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
/** All combinations with 1 key from each list */
|
|
29
31
|
function getKeysCombinations(idsLists: AxisId[][]) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
result = nextResult;
|
|
32
|
+
if (!idsLists.length) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
let result: AxisId[][] = [[]];
|
|
36
|
+
idsLists.forEach((list) => {
|
|
37
|
+
const nextResult: AxisId[][] = [];
|
|
38
|
+
list.forEach((key) => {
|
|
39
|
+
nextResult.push(...result.map((resultItem) => [...resultItem, key]));
|
|
40
40
|
});
|
|
41
|
-
|
|
41
|
+
result = nextResult;
|
|
42
|
+
});
|
|
43
|
+
return result;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
/** Check if axes of secondary column are exactly in axes of main column */
|
|
45
47
|
function checkFullCompatibility(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
mainColumn: PColumn<TreeNodeAccessor | PColumnValues>,
|
|
49
|
+
secondaryColumn: PColumn<TreeNodeAccessor | PColumnValues>,
|
|
48
50
|
): boolean {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
const mainAxesIds = mainColumn.spec.axesSpec.map(getAxisId);
|
|
52
|
+
const secondaryAxesIds = secondaryColumn.spec.axesSpec.map(getAxisId);
|
|
53
|
+
return secondaryAxesIds.every((id) => mainAxesIds.some((mainId) => matchAxisId(mainId, id) && matchAxisId(id, mainId)));
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/** Check if axes of secondary column are in axes of main column, but they can have compatible difference in domains */
|
|
55
57
|
function checkCompatibility(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
mainColumn: PColumn<TreeNodeAccessor | PColumnValues>,
|
|
59
|
+
secondaryColumn: PColumn<TreeNodeAccessor | PColumnValues>,
|
|
58
60
|
): boolean {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
const mainAxesIds = mainColumn.spec.axesSpec.map(getAxisId);
|
|
62
|
+
const secondaryAxesIds = secondaryColumn.spec.axesSpec.map(getAxisId);
|
|
63
|
+
return secondaryAxesIds.every((id) => mainAxesIds.some((mainId) => matchAxisId(mainId, id)));
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
export const IS_VIRTUAL_COLUMN = 'pl7.app/graph/isVirtual'; // annotation for column duplicates with extended domains
|
|
@@ -67,157 +69,157 @@ export const LABEL_ANNOTATION = 'pl7.app/label';
|
|
|
67
69
|
/** Main column can have additional domains, if secondary column (meta-column) has all axes match main column axes
|
|
68
70
|
we can add its copy with missed domain fields for compatibility */
|
|
69
71
|
function getAdditionalColumnsForPair(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
mainColumn: PColumn<TreeNodeAccessor | PColumnValues>,
|
|
73
|
+
secondaryColumn: PColumn<TreeNodeAccessor | PColumnValues>,
|
|
72
74
|
): PColumn<TreeNodeAccessor | PColumnValues>[] {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
75
|
+
const mainAxesIds = mainColumn.spec.axesSpec.map(getAxisId);
|
|
76
|
+
const secondaryAxesIds = secondaryColumn.spec.axesSpec.map(getAxisId);
|
|
77
|
+
|
|
78
|
+
const isFullCompatible = checkFullCompatibility(mainColumn, secondaryColumn);
|
|
79
|
+
if (isFullCompatible) { // in this case it isn't necessary to add more columns
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
const isCompatible = checkCompatibility(mainColumn, secondaryColumn);
|
|
83
|
+
if (!isCompatible) { // in this case it is impossible to add some compatible column
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
// options with different possible domains for every axis of secondary column
|
|
87
|
+
const secondaryIdsOptions = secondaryAxesIds.map((id) => {
|
|
88
|
+
return mainAxesIds.filter((mainId) => matchAxisId(mainId, id));
|
|
89
|
+
});
|
|
88
90
|
// all possible combinations of axes with added domains
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
return ({
|
|
107
|
-
...axisId,
|
|
108
|
-
annotations: secondaryColumn.spec.axesSpec[idx].annotations
|
|
109
|
-
})
|
|
110
|
-
});
|
|
111
|
-
return addedSet;
|
|
112
|
-
});
|
|
113
|
-
[...allAddedDomainValues].forEach(addedPart => {
|
|
114
|
-
if (addedByVariantsDomainValues.some(s => !s.has(addedPart))) {
|
|
115
|
-
addedNotToAllVariantsDomainValues.add(addedPart);
|
|
91
|
+
const secondaryIdsVariants = getKeysCombinations(secondaryIdsOptions);
|
|
92
|
+
|
|
93
|
+
// sets of added to column domain fields
|
|
94
|
+
const allAddedDomainValues = new Set<string>();
|
|
95
|
+
const addedNotToAllVariantsDomainValues = new Set<string>();
|
|
96
|
+
const addedByVariantsDomainValues = secondaryIdsVariants.map((idsList) => {
|
|
97
|
+
const addedSet = new Set<string>();
|
|
98
|
+
idsList.map((axisId, idx) => {
|
|
99
|
+
const d1 = secondaryColumn.spec.axesSpec[idx].domain;
|
|
100
|
+
const d2 = axisId.domain;
|
|
101
|
+
Object.entries(d2 ?? {}).forEach(([key, value]) => {
|
|
102
|
+
if (d1?.[key] === undefined) {
|
|
103
|
+
const item = JSON.stringify([key, value]);
|
|
104
|
+
addedSet.add(item);
|
|
105
|
+
allAddedDomainValues.add(item);
|
|
116
106
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const label = secondaryColumn.spec.annotations?.[LABEL_ANNOTATION] ?? '';
|
|
123
|
-
const labelDomainPart = ([...addedByVariantsDomainValues[idx]])
|
|
124
|
-
.filter(str => addedNotToAllVariantsDomainValues.has(str))
|
|
125
|
-
.sort()
|
|
126
|
-
.map((v) => JSON.parse(v)?.[1]) // use in labels only domain values, but sort them by key to save the same order in all column variants
|
|
127
|
-
.join(' / ');
|
|
128
|
-
|
|
129
|
-
const annotations:Record<string, string> = {
|
|
130
|
-
...secondaryColumn.spec.annotations,
|
|
131
|
-
[IS_VIRTUAL_COLUMN]: 'true'
|
|
132
|
-
}
|
|
133
|
-
if (label || labelDomainPart) {
|
|
134
|
-
annotations[LABEL_ANNOTATION] = label && labelDomainPart ? label + ' / ' + labelDomainPart : label + labelDomainPart;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
id: id as PObjectId,
|
|
139
|
-
spec: {
|
|
140
|
-
...secondaryColumn.spec,
|
|
141
|
-
axesSpec: idsList.map((axisId, idx) => ({
|
|
142
|
-
...axisId,
|
|
143
|
-
annotations: secondaryColumn.spec.axesSpec[idx].annotations
|
|
144
|
-
})),
|
|
145
|
-
annotations
|
|
146
|
-
},
|
|
147
|
-
data: secondaryColumn.data
|
|
148
|
-
};
|
|
107
|
+
});
|
|
108
|
+
return ({
|
|
109
|
+
...axisId,
|
|
110
|
+
annotations: secondaryColumn.spec.axesSpec[idx].annotations,
|
|
111
|
+
});
|
|
149
112
|
});
|
|
113
|
+
return addedSet;
|
|
114
|
+
});
|
|
115
|
+
[...allAddedDomainValues].forEach((addedPart) => {
|
|
116
|
+
if (addedByVariantsDomainValues.some((s) => !s.has(addedPart))) {
|
|
117
|
+
addedNotToAllVariantsDomainValues.add(addedPart);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return secondaryIdsVariants.map((idsList, idx) => {
|
|
122
|
+
const id = colId(secondaryColumn.id, idsList.map((id) => id.domain));
|
|
123
|
+
|
|
124
|
+
const label = secondaryColumn.spec.annotations?.[LABEL_ANNOTATION] ?? '';
|
|
125
|
+
const labelDomainPart = ([...addedByVariantsDomainValues[idx]])
|
|
126
|
+
.filter((str) => addedNotToAllVariantsDomainValues.has(str))
|
|
127
|
+
.sort()
|
|
128
|
+
.map((v) => JSON.parse(v)?.[1]) // use in labels only domain values, but sort them by key to save the same order in all column variants
|
|
129
|
+
.join(' / ');
|
|
130
|
+
|
|
131
|
+
const annotations: Record<string, string> = {
|
|
132
|
+
...secondaryColumn.spec.annotations,
|
|
133
|
+
[IS_VIRTUAL_COLUMN]: 'true',
|
|
134
|
+
};
|
|
135
|
+
if (label || labelDomainPart) {
|
|
136
|
+
annotations[LABEL_ANNOTATION] = label && labelDomainPart ? label + ' / ' + labelDomainPart : label + labelDomainPart;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
id: id as PObjectId,
|
|
141
|
+
spec: {
|
|
142
|
+
...secondaryColumn.spec,
|
|
143
|
+
axesSpec: idsList.map((axisId, idx) => ({
|
|
144
|
+
...axisId,
|
|
145
|
+
annotations: secondaryColumn.spec.axesSpec[idx].annotations,
|
|
146
|
+
})),
|
|
147
|
+
annotations,
|
|
148
|
+
},
|
|
149
|
+
data: secondaryColumn.data,
|
|
150
|
+
};
|
|
151
|
+
});
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
export function getAdditionalColumns(columns: PColumn<TreeNodeAccessor | PColumnValues>[]): PColumn<TreeNodeAccessor | PColumnValues>[] {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
155
|
+
const additionalColumns: PColumn<TreeNodeAccessor | PColumnValues>[] = [];
|
|
156
|
+
for (let i = 0; i < columns.length; i++) {
|
|
157
|
+
for (let j = i + 1; j < columns.length; j++) {
|
|
158
|
+
const column1 = columns[i];
|
|
159
|
+
const column2 = columns[j];
|
|
160
|
+
|
|
161
|
+
// check if column 1 is meta for column 2 or backward
|
|
162
|
+
additionalColumns.push(
|
|
163
|
+
...getAdditionalColumnsForPair(column1, column2),
|
|
164
|
+
...getAdditionalColumnsForPair(column2, column1),
|
|
165
|
+
);
|
|
165
166
|
}
|
|
166
|
-
|
|
167
|
+
}
|
|
168
|
+
return additionalColumns;
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
export function enrichColumnsWithCompatible(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
+
mainColumns: PColumn<TreeNodeAccessor | PColumnValues>[],
|
|
173
|
+
secondaryColumns: PColumn<TreeNodeAccessor | PColumnValues>[],
|
|
172
174
|
): PColumn<TreeNodeAccessor | PColumnValues>[] {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
175
|
+
const result = [...mainColumns];
|
|
176
|
+
for (const secondaryColumn of secondaryColumns) {
|
|
177
|
+
for (const mainColumn of mainColumns) {
|
|
178
|
+
if (mainColumn.id === secondaryColumn.id) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
if (checkCompatibility(mainColumn, secondaryColumn)) {
|
|
182
|
+
result.push(secondaryColumn);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
184
185
|
}
|
|
185
|
-
|
|
186
|
+
}
|
|
187
|
+
return result;
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
const VALUE_TYPES: ValueType[] = [
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
191
|
+
'Int',
|
|
192
|
+
'Long',
|
|
193
|
+
'Float',
|
|
194
|
+
'Double',
|
|
195
|
+
'String',
|
|
196
|
+
'Bytes',
|
|
195
197
|
];
|
|
196
198
|
|
|
197
199
|
export function createPFrameForGraphs<A, U>(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
ctx: RenderCtx<A, U>,
|
|
201
|
+
blockColumns?: PColumn<TreeNodeAccessor | PColumnValues>[],
|
|
200
202
|
): PFrameHandle | undefined {
|
|
201
|
-
|
|
203
|
+
if (blockColumns === undefined) return undefined;
|
|
202
204
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
const upstreamColumns = ctx.resultPool
|
|
206
|
+
.getData()
|
|
207
|
+
.entries.map((v) => v.obj)
|
|
208
|
+
.filter(isPColumn)
|
|
209
|
+
.filter((column) => VALUE_TYPES.includes(column.spec.valueType));
|
|
208
210
|
|
|
209
|
-
|
|
211
|
+
const columnsWithCompatibleFromUpstream = enrichColumnsWithCompatible(blockColumns, upstreamColumns);
|
|
210
212
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
// additional columns are duplicates with extra fields in domains for compatibility in all possible pairs of columns set
|
|
214
|
+
const extendedColumns = [...columnsWithCompatibleFromUpstream, ...getAdditionalColumns(columnsWithCompatibleFromUpstream)];
|
|
213
215
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
)
|
|
216
|
+
// if at least one column is not yet ready, we can't show the table
|
|
217
|
+
if (
|
|
218
|
+
extendedColumns.some(
|
|
219
|
+
(a) => a.data instanceof TreeNodeAccessor && !a.data.getIsReadyOrError(),
|
|
219
220
|
)
|
|
220
|
-
|
|
221
|
+
)
|
|
222
|
+
return undefined;
|
|
221
223
|
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
+
return ctx.createPFrame(extendedColumns);
|
|
225
|
+
}
|