@platforma-sdk/ui-vue 1.37.10 → 1.37.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.
@@ -1,6 +1,6 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.37.10 build /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.37.11 build /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > vite build
5
5
 
6
6
  vite v6.3.5 building for production...
@@ -10,7 +10,7 @@ rendering chunks...
10
10
 
11
11
  [vite:dts] Start generate declaration files...
12
12
  computing gzip size...
13
- [vite:dts] Declaration files built in 4905ms.
13
+ [vite:dts] Declaration files built in 5133ms.
14
14
 
15
15
  dist/_virtual/re.js  0.08 kB │ gzip: 0.10 kB │ map: 0.09 kB
16
16
  dist/_virtual/lodash2.js  0.09 kB │ gzip: 0.10 kB │ map: 0.09 kB
@@ -146,8 +146,8 @@ computing gzip size...
146
146
  dist/lib/ui/uikit/dist/components/PlChartHistogram/logspace.js  0.27 kB │ gzip: 0.20 kB │ map: 0.88 kB
147
147
  dist/lib/ui/uikit/dist/components/PlSvg/PlSvg.vue.js  0.27 kB │ gzip: 0.21 kB │ map: 0.10 kB
148
148
  dist/lib/ui/uikit/dist/assets/icons/icon-assets-min/24_windows-expand.svg.js  0.27 kB │ gzip: 0.22 kB │ map: 0.51 kB
149
- dist/node_modules/.pnpm/semver@7.7.2/node_modules/semver/functions/valid.js  0.27 kB │ gzip: 0.21 kB │ map: 0.59 kB
150
149
  dist/components/PlMultiSequenceAlignment/residue-counts.js  0.27 kB │ gzip: 0.20 kB │ map: 4.45 kB
150
+ dist/node_modules/.pnpm/semver@7.7.2/node_modules/semver/functions/valid.js  0.27 kB │ gzip: 0.21 kB │ map: 0.59 kB
151
151
  dist/lib/ui/uikit/dist/assets/icons/icon-assets-min/24_arrow-left.svg.js  0.27 kB │ gzip: 0.23 kB │ map: 0.47 kB
152
152
  dist/components/PlMultiSequenceAlignment/Legend.vue.js  0.27 kB │ gzip: 0.21 kB │ map: 0.10 kB
153
153
  dist/lib/ui/uikit/dist/assets/icons/icon-assets-min/24_arrow-right.svg.js  0.27 kB │ gzip: 0.24 kB │ map: 0.47 kB
@@ -803,7 +803,7 @@ computing gzip size...
803
803
  dist/lib/ui/uikit/dist/components/PlFileDialog/PlFileDialog.vue.js  3.51 kB │ gzip: 1.39 kB │ map: 4.61 kB
804
804
  dist/lib/ui/uikit/dist/components/PlBtnSecondary/PlBtnSecondary.vue.js  3.54 kB │ gzip: 1.34 kB │ map: 1.25 kB
805
805
  dist/lib/ui/uikit/dist/components/PlBtnPrimary/PlBtnPrimary.vue.js  3.56 kB │ gzip: 1.33 kB │ map: 1.24 kB
806
- dist/sdk/model/dist/index.js  3.56 kB │ gzip: 1.45 kB │ map: 51.35 kB
806
+ dist/sdk/model/dist/index.js  3.57 kB │ gzip: 1.45 kB │ map: 51.57 kB
807
807
  dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue.js  3.59 kB │ gzip: 1.43 kB │ map: 2.78 kB
808
808
  dist/node_modules/.pnpm/semver@7.7.2/node_modules/semver/index.js  3.67 kB │ gzip: 1.01 kB │ map: 5.45 kB
809
809
  dist/lib/ui/uikit/dist/composition/useSortable.js  3.68 kB │ gzip: 1.32 kB │ map: 10.93 kB
@@ -876,4 +876,4 @@ computing gzip size...
876
876
  dist/lib/ui/uikit/dist/index.js 497.54 kB │ gzip: 191.69 kB │ map: 0.18 kB
877
877
  dist/lib/ui/uikit/dist/components/PlSlideModal/PlSlideModal.vue.js 601.36 kB │ gzip: 204.40 kB │ map: 0.23 kB
878
878
  dist/lib/ui/uikit/dist/components/DataTable/TableComponent.vue.js 602.69 kB │ gzip: 204.99 kB │ map: 0.27 kB
879
- ✓ built in 9.16s
879
+ ✓ built in 9.82s
@@ -1,5 +1,5 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.37.10 type-check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.37.11 type-check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > vue-tsc --noEmit --project ./tsconfig.json
5
5
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @platforma-sdk/ui-vue
2
2
 
3
+ ## 1.37.11
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [10e5841]
8
+ - @platforma-sdk/model@1.37.11
9
+ - @milaboratories/uikit@2.2.94
10
+
3
11
  ## 1.37.10
4
12
 
5
13
  ### Patch Changes
@@ -14,7 +14,7 @@ const e = r.object({
14
14
  label: r.string()
15
15
  });
16
16
  r.array(e);
17
- const a = "1.37.2";
17
+ const a = "1.37.11";
18
18
  function l() {
19
19
  return o({ sdkVersion: a });
20
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../../../../../../model/src/internal.ts","../../../../../../../../../model/src/render/util/label.ts","../../../../../../../../../model/src/version.ts","../../../../../../../../../model/src/raw_globals.ts"],"sourcesContent":["import type { ValueOrErrors } from '@milaboratories/pl-model-common';\nimport {} from './global';\nimport type { Platforma } from './platforma';\nimport type { FutureHandle, GlobalCfgRenderCtx } from './render/internal';\n\n/** Utility code helping to identify whether the code is running in actual UI environment */\nexport function isInUI() {\n return (\n typeof globalThis.getPlatforma !== 'undefined' || typeof globalThis.platforma !== 'undefined'\n );\n}\n\n/** Utility code helping to retrieve a platforma instance form the environment */\nexport function getPlatformaInstance<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(config?: { sdkVersion: string }): Platforma<Args, Outputs, UiState, Href> {\n if (config && typeof globalThis.getPlatforma === 'function')\n return globalThis.getPlatforma(config);\n else if (typeof globalThis.platforma !== 'undefined') return globalThis.platforma;\n else throw new Error('Can\\'t get platforma instance.');\n}\n\nexport function tryGetCfgRenderCtx(): GlobalCfgRenderCtx | undefined {\n if (typeof globalThis.cfgRenderCtx !== 'undefined') return globalThis.cfgRenderCtx;\n else return undefined;\n}\n\nexport function getCfgRenderCtx(): GlobalCfgRenderCtx {\n if (typeof globalThis.cfgRenderCtx !== 'undefined') return globalThis.cfgRenderCtx;\n else throw new Error('Not in config rendering context');\n}\n\nexport function tryRegisterCallback(key: string, callback: (...args: any[]) => any): boolean {\n const ctx = tryGetCfgRenderCtx();\n if (ctx === undefined) return false;\n if (key in ctx.callbackRegistry) throw new Error(`Callback with key ${key} already registered.`);\n ctx.callbackRegistry[key] = callback;\n return true;\n}\n\nconst futureResolves = new Map<string, ((value: unknown) => void)[]>();\n\nexport function registerFutureAwait(handle: FutureHandle, onResolve: (value: unknown) => void) {\n if (!(handle in getCfgRenderCtx().callbackRegistry)) {\n getCfgRenderCtx().callbackRegistry[handle] = (value: unknown) => {\n for (const res of futureResolves.get(handle)!) {\n res(value);\n }\n };\n futureResolves.set(handle, []);\n }\n futureResolves.get(handle)!.push(onResolve);\n}\n","import type { PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport const PAnnotationLabel = 'pl7.app/label';\nexport const PAnnotationTrace = 'pl7.app/trace';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = spec.annotations?.[PAnnotationLabel];\n const traceStr = spec.annotations?.[PAnnotationTrace];\n const baseTrace = (traceStr ? Trace.safeParse(JSON.parse(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n // checking if labels uniquely separate our records\n if (candidateResult !== undefined && new Set(candidateResult.map((c) => c.label)).size === values.length) return candidateResult;\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n return calculate(new Set([...mainTypes, ...secondaryTypes]), true)!;\n}\n","export const PlatformaSDKVersion = '1.37.2';\n","import type { ValueOrErrors } from '@milaboratories/pl-model-common';\nimport {} from './global';\nimport { getPlatformaInstance } from './internal';\nimport type { Platforma } from './platforma';\nimport { PlatformaSDKVersion } from './version';\n\nexport function getRawPlatformaInstance<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(): Platforma<Args, Outputs, UiState, Href> {\n return getPlatformaInstance<Args, Outputs, UiState, Href>({ sdkVersion: PlatformaSDKVersion });\n}\n\n/** Returns a global platforma instance or a provided fallback if it's not available. */\nexport function getPlatformaOrDefault<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(platforma: Platforma<Args, Outputs, UiState, Href>): Platforma<Args, Outputs, UiState, Href> {\n try {\n return getRawPlatformaInstance<Args, Outputs, UiState, Href>();\n } catch {\n return platforma;\n }\n}\n"],"names":["getPlatformaInstance","config","TraceEntry","z","PlatformaSDKVersion","getRawPlatformaInstance"],"mappings":";;;AAaO,SAASA,EAKdC,GAA0E;AACtEA,MAAAA,KAAU,OAAO,WAAW,gBAAiB;AACxC,WAAA,WAAW,aAAaA,CAAM;AAAA,MAC9B,OAAO,WAAW,YAAc,YAAoB,WAAW;AAC7D,QAAA,IAAI,MAAM,+BAAgC;AACvD;ACDaC,MAAAA,IAAaC,EAAE,OAAO;AAAA,EACjC,MAAMA,EAAE,OAAO;AAAA,EACf,YAAYA,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,IAAIA,EAAE,OAAO,EAAE,SAAS;AAAA,EACxB,OAAOA,EAAE,OAAO;AAClB,CAAC;AAIoBA,EAAE,MAAMD,CAAU;AC/BhC,MAAME,IAAsB;ACM5B,SAASC,IAK6B;AACpCL,SAAAA,EAAmD,EAAE,YAAYI,GAAqB;AAC/F;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../../../../../../model/src/internal.ts","../../../../../../../../../model/src/render/util/label.ts","../../../../../../../../../model/src/version.ts","../../../../../../../../../model/src/raw_globals.ts"],"sourcesContent":["import type { ValueOrErrors } from '@milaboratories/pl-model-common';\nimport {} from './global';\nimport type { Platforma } from './platforma';\nimport type { FutureHandle, GlobalCfgRenderCtx } from './render/internal';\n\n/** Utility code helping to identify whether the code is running in actual UI environment */\nexport function isInUI() {\n return (\n typeof globalThis.getPlatforma !== 'undefined' || typeof globalThis.platforma !== 'undefined'\n );\n}\n\n/** Utility code helping to retrieve a platforma instance form the environment */\nexport function getPlatformaInstance<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(config?: { sdkVersion: string }): Platforma<Args, Outputs, UiState, Href> {\n if (config && typeof globalThis.getPlatforma === 'function')\n return globalThis.getPlatforma(config);\n else if (typeof globalThis.platforma !== 'undefined') return globalThis.platforma;\n else throw new Error('Can\\'t get platforma instance.');\n}\n\nexport function tryGetCfgRenderCtx(): GlobalCfgRenderCtx | undefined {\n if (typeof globalThis.cfgRenderCtx !== 'undefined') return globalThis.cfgRenderCtx;\n else return undefined;\n}\n\nexport function getCfgRenderCtx(): GlobalCfgRenderCtx {\n if (typeof globalThis.cfgRenderCtx !== 'undefined') return globalThis.cfgRenderCtx;\n else throw new Error('Not in config rendering context');\n}\n\nexport function tryRegisterCallback(key: string, callback: (...args: any[]) => any): boolean {\n const ctx = tryGetCfgRenderCtx();\n if (ctx === undefined) return false;\n if (key in ctx.callbackRegistry) throw new Error(`Callback with key ${key} already registered.`);\n ctx.callbackRegistry[key] = callback;\n return true;\n}\n\nconst futureResolves = new Map<string, ((value: unknown) => void)[]>();\n\nexport function registerFutureAwait(handle: FutureHandle, onResolve: (value: unknown) => void) {\n if (!(handle in getCfgRenderCtx().callbackRegistry)) {\n getCfgRenderCtx().callbackRegistry[handle] = (value: unknown) => {\n for (const res of futureResolves.get(handle)!) {\n res(value);\n }\n };\n futureResolves.set(handle, []);\n }\n futureResolves.get(handle)!.push(onResolve);\n}\n","import type { PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport const PAnnotationLabel = 'pl7.app/label';\nexport const PAnnotationTrace = 'pl7.app/trace';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = spec.annotations?.[PAnnotationLabel];\n const traceStr = spec.annotations?.[PAnnotationTrace];\n const baseTrace = (traceStr ? Trace.safeParse(JSON.parse(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n // checking if labels uniquely separate our records\n if (candidateResult !== undefined && new Set(candidateResult.map((c) => c.label)).size === values.length) return candidateResult;\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n return calculate(new Set([...mainTypes, ...secondaryTypes]), true)!;\n}\n","export const PlatformaSDKVersion = '1.37.11';\n","import type { ValueOrErrors } from '@milaboratories/pl-model-common';\nimport {} from './global';\nimport { getPlatformaInstance } from './internal';\nimport type { Platforma } from './platforma';\nimport { PlatformaSDKVersion } from './version';\n\nexport function getRawPlatformaInstance<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(): Platforma<Args, Outputs, UiState, Href> {\n return getPlatformaInstance<Args, Outputs, UiState, Href>({ sdkVersion: PlatformaSDKVersion });\n}\n\n/** Returns a global platforma instance or a provided fallback if it's not available. */\nexport function getPlatformaOrDefault<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(platforma: Platforma<Args, Outputs, UiState, Href>): Platforma<Args, Outputs, UiState, Href> {\n try {\n return getRawPlatformaInstance<Args, Outputs, UiState, Href>();\n } catch {\n return platforma;\n }\n}\n"],"names":["getPlatformaInstance","config","TraceEntry","z","PlatformaSDKVersion","getRawPlatformaInstance"],"mappings":";;;AAaO,SAASA,EAKdC,GAA0E;AACtEA,MAAAA,KAAU,OAAO,WAAW,gBAAiB;AACxC,WAAA,WAAW,aAAaA,CAAM;AAAA,MAC9B,OAAO,WAAW,YAAc,YAAoB,WAAW;AAC7D,QAAA,IAAI,MAAM,+BAAgC;AACvD;ACDaC,MAAAA,IAAaC,EAAE,OAAO;AAAA,EACjC,MAAMA,EAAE,OAAO;AAAA,EACf,YAAYA,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,IAAIA,EAAE,OAAO,EAAE,SAAS;AAAA,EACxB,OAAOA,EAAE,OAAO;AAClB,CAAC;AAIoBA,EAAE,MAAMD,CAAU;AC/BhC,MAAME,IAAsB;ACM5B,SAASC,IAK6B;AACpCL,SAAAA,EAAmD,EAAE,YAAYI,GAAqB;AAC/F;"}
@@ -16,7 +16,7 @@ const f = a.object({
16
16
  label: a.string()
17
17
  });
18
18
  a.array(f);
19
- const m = "1.37.2";
19
+ const m = "1.37.11";
20
20
  function b() {
21
21
  return {
22
22
  version: 2,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../../model/src/internal.ts","../../../../../model/src/render/util/label.ts","../../../../../model/src/version.ts","../../../../../model/src/components/PlDataTable.ts","../../../../../model/src/components/PFrameForGraphs.ts","../../../../../model/src/components/PlMultiSequenceAlignment.ts","../../../../../model/src/components/PlSelectionModel.ts","../../../../../model/src/raw_globals.ts","../../../../../model/src/env_value.ts"],"sourcesContent":["import type { ValueOrErrors } from '@milaboratories/pl-model-common';\nimport {} from './global';\nimport type { Platforma } from './platforma';\nimport type { FutureHandle, GlobalCfgRenderCtx } from './render/internal';\n\n/** Utility code helping to identify whether the code is running in actual UI environment */\nexport function isInUI() {\n return (\n typeof globalThis.getPlatforma !== 'undefined' || typeof globalThis.platforma !== 'undefined'\n );\n}\n\n/** Utility code helping to retrieve a platforma instance form the environment */\nexport function getPlatformaInstance<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(config?: { sdkVersion: string }): Platforma<Args, Outputs, UiState, Href> {\n if (config && typeof globalThis.getPlatforma === 'function')\n return globalThis.getPlatforma(config);\n else if (typeof globalThis.platforma !== 'undefined') return globalThis.platforma;\n else throw new Error('Can\\'t get platforma instance.');\n}\n\nexport function tryGetCfgRenderCtx(): GlobalCfgRenderCtx | undefined {\n if (typeof globalThis.cfgRenderCtx !== 'undefined') return globalThis.cfgRenderCtx;\n else return undefined;\n}\n\nexport function getCfgRenderCtx(): GlobalCfgRenderCtx {\n if (typeof globalThis.cfgRenderCtx !== 'undefined') return globalThis.cfgRenderCtx;\n else throw new Error('Not in config rendering context');\n}\n\nexport function tryRegisterCallback(key: string, callback: (...args: any[]) => any): boolean {\n const ctx = tryGetCfgRenderCtx();\n if (ctx === undefined) return false;\n if (key in ctx.callbackRegistry) throw new Error(`Callback with key ${key} already registered.`);\n ctx.callbackRegistry[key] = callback;\n return true;\n}\n\nconst futureResolves = new Map<string, ((value: unknown) => void)[]>();\n\nexport function registerFutureAwait(handle: FutureHandle, onResolve: (value: unknown) => void) {\n if (!(handle in getCfgRenderCtx().callbackRegistry)) {\n getCfgRenderCtx().callbackRegistry[handle] = (value: unknown) => {\n for (const res of futureResolves.get(handle)!) {\n res(value);\n }\n };\n futureResolves.set(handle, []);\n }\n futureResolves.get(handle)!.push(onResolve);\n}\n","import type { PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport const PAnnotationLabel = 'pl7.app/label';\nexport const PAnnotationTrace = 'pl7.app/trace';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = spec.annotations?.[PAnnotationLabel];\n const traceStr = spec.annotations?.[PAnnotationTrace];\n const baseTrace = (traceStr ? Trace.safeParse(JSON.parse(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n // checking if labels uniquely separate our records\n if (candidateResult !== undefined && new Set(candidateResult.map((c) => c.label)).size === values.length) return candidateResult;\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n return calculate(new Set([...mainTypes, ...secondaryTypes]), true)!;\n}\n","export const PlatformaSDKVersion = '1.37.2';\n","import type {\n AxisId,\n AxisSpec,\n CanonicalizedJson,\n DataInfo,\n ListOptionBase,\n PColumn,\n PColumnIdAndSpec,\n PColumnSpec,\n PColumnValues,\n PObjectId,\n PTableColumnId,\n PTableColumnIdColumn,\n PTableColumnSpec,\n PTableDef,\n PTableHandle,\n PTableRecordFilter,\n PTableRecordSingleValueFilterV2,\n PTableSorting,\n PTableValue,\n} from '@milaboratories/pl-model-common';\nimport {\n canonicalizeJson,\n getAxisId,\n getColumnIdAndSpec,\n matchAxisId,\n} from '@milaboratories/pl-model-common';\nimport type {\n AxisLabelProvider,\n ColumnProvider,\n PColumnDataUniversal,\n RenderCtx,\n} from '../render';\nimport {\n PColumnCollection,\n TreeNodeAccessor,\n} from '../render';\n\n/** Canonicalized PTableColumnSpec JSON string */\nexport type PTableColumnSpecJson = CanonicalizedJson<PTableColumnSpec>;\n\nexport type PlDataTableGridStateCore = {\n /** Includes column ordering */\n columnOrder?: {\n /** All colIds in order */\n orderedColIds: PTableColumnSpecJson[];\n };\n /** Includes current sort columns and direction */\n sort?: {\n /** Sorted columns and directions in order */\n sortModel: {\n /** Column Id to apply the sort to. */\n colId: PTableColumnSpecJson;\n /** Sort direction */\n sort: 'asc' | 'desc';\n }[];\n };\n /** Includes column visibility */\n columnVisibility?: {\n /** All colIds which were hidden */\n hiddenColIds: PTableColumnSpecJson[];\n };\n};\n\n/** TODO: refactor to use sheets in the grid state */\nexport type PlDataTableGridStateWithoutSheets = PlDataTableGridStateCore & {\n /** DataSource identifier for state management */\n sourceId?: string;\n};\n\n/** Data table state */\nexport type PlDataTableGridState = PlDataTableGridStateWithoutSheets & {\n /** current sheet selections */\n sheets?: Record<CanonicalizedJson<AxisId>, string | number>;\n};\n\nexport type PlDataTableSheet = {\n /** spec of the axis to use */\n axis: AxisSpec;\n /** options to show in the filter dropdown */\n options: ListOptionBase<string | number>[];\n /** default (selected) value */\n defaultValue?: string | number;\n};\n\nexport type PlDataTableSheetState = {\n /** id of the axis */\n axisId: AxisId;\n /** selected value */\n value: string | number;\n};\n\n/**\n * Params used to get p-table handle from the driver\n */\nexport type PTableParams = {\n sorting?: PTableSorting[];\n filters?: PTableRecordFilter[];\n};\n\n/**\n * PlDataTable persisted state\n */\nexport type PlDataTableState = {\n // internal ag-grid state\n gridState: PlDataTableGridState;\n // mapping of gridState onto the p-table data structures\n pTableParams?: PTableParams;\n};\n\n/**\n * PlDataTableV2 persisted state\n */\nexport type PlDataTableStateV2 =\n // Old versions of the state\n | PlDataTableState\n // Normalized state\n | PlDataTableStateV2Normalized;\n\nexport type PlDataTableStateV2CacheEntry = {\n /** DataSource identifier for state management */\n sourceId: string;\n /** Internal ag-grid state */\n gridState: PlDataTableGridStateCore;\n /** Sheets state */\n sheetsState: PlDataTableSheetState[];\n};\n\nexport type PTableParamsV2 = {\n sorting: PTableSorting[];\n filters: PTableRecordFilter[];\n hiddenColIds: PObjectId[] | null;\n};\n\nexport type PlDataTableStateV2Normalized = {\n // version for upgrades\n version: 2;\n // internal ag-grid states, LRU cache for 5 sourceId-s\n stateCache: PlDataTableStateV2CacheEntry[];\n // mapping of gridState for current sourceId onto the p-table data structures\n pTableParams: PTableParamsV2;\n};\n\n/** Create default PlDataTableStateV2 */\nexport function createPlDataTableStateV2(): PlDataTableStateV2Normalized {\n return {\n version: 2,\n stateCache: [],\n pTableParams: {\n sorting: [],\n filters: [],\n hiddenColIds: null,\n },\n };\n}\n\n/** Upgrade PlDataTableStateV2 to the latest version */\nexport function upgradePlDataTableStateV2(state: PlDataTableStateV2): PlDataTableStateV2Normalized {\n // v1 -> v2\n if (!('version' in state)) {\n // Non upgradeable as sourceId calculation algorithm has changed, resetting state to default\n return createPlDataTableStateV2();\n }\n return state;\n}\n\n/** PlTableFilters filter entry */\nexport type PlTableFilterIsNotNA = {\n /** Predicate type */\n type: 'isNotNA';\n};\n\n/** PlTableFilters filter entry */\nexport type PlTableFilterIsNA = {\n /** Predicate type */\n type: 'isNA';\n};\n\n/** PlTableFilters filter entries applicable to both string and number values */\nexport type PlTableFilterCommon = PlTableFilterIsNotNA | PlTableFilterIsNA;\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberEquals = {\n /** Predicate type */\n type: 'number_equals';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberNotEquals = {\n /** Predicate type */\n type: 'number_notEquals';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberGreaterThan = {\n /** Predicate type */\n type: 'number_greaterThan';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberGreaterThanOrEqualTo = {\n /** Predicate type */\n type: 'number_greaterThanOrEqualTo';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberLessThan = {\n /** Predicate type */\n type: 'number_lessThan';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberLessThanOrEqualTo = {\n /** Predicate type */\n type: 'number_lessThanOrEqualTo';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberBetween = {\n /** Predicate type */\n type: 'number_between';\n /** Referense value for the lower bound */\n lowerBound: number;\n /** Defines whether values equal to lower bound reference value should be matched */\n includeLowerBound: boolean;\n /** Referense value for the upper bound */\n upperBound: number;\n /** Defines whether values equal to upper bound reference value should be matched */\n includeUpperBound: boolean;\n};\n\n/** All PlTableFilters numeric filter entries */\nexport type PlTableFilterNumber =\n | PlTableFilterCommon\n | PlTableFilterNumberEquals\n | PlTableFilterNumberNotEquals\n | PlTableFilterNumberGreaterThan\n | PlTableFilterNumberGreaterThanOrEqualTo\n | PlTableFilterNumberLessThan\n | PlTableFilterNumberLessThanOrEqualTo\n | PlTableFilterNumberBetween;\n/** All types of PlTableFilters numeric filter entries */\nexport type PlTableFilterNumberType = PlTableFilterNumber['type'];\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringEquals = {\n /** Predicate type */\n type: 'string_equals';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringNotEquals = {\n /** Predicate type */\n type: 'string_notEquals';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringContains = {\n /** Predicate type */\n type: 'string_contains';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringDoesNotContain = {\n /** Predicate type */\n type: 'string_doesNotContain';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringMatches = {\n /** Predicate type */\n type: 'string_matches';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringDoesNotMatch = {\n /** Predicate type */\n type: 'string_doesNotMatch';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringContainsFuzzyMatch = {\n /** Predicate type */\n type: 'string_containsFuzzyMatch';\n /** Referense value */\n reference: string;\n /**\n * Maximum acceptable edit distance between reference value and matched substring\n * @see https://en.wikipedia.org/wiki/Edit_distance\n */\n maxEdits: number;\n /**\n * When {@link substitutionsOnly} is set to false\n * Levenshtein distance is used as edit distance (substitutions and indels)\n * @see https://en.wikipedia.org/wiki/Levenshtein_distance\n * When {@link substitutionsOnly} is set to true\n * Hamming distance is used as edit distance (substitutions only)\n * @see https://en.wikipedia.org/wiki/Hamming_distance\n */\n substitutionsOnly: boolean;\n /**\n * Single character in {@link reference} that will labelColumn any\n * single character in searched text.\n */\n wildcard?: string;\n};\n\n/** All PlTableFilters string filter entries */\nexport type PlTableFilterString =\n | PlTableFilterCommon\n | PlTableFilterStringEquals\n | PlTableFilterStringNotEquals\n | PlTableFilterStringContains\n | PlTableFilterStringDoesNotContain\n | PlTableFilterStringMatches\n | PlTableFilterStringDoesNotMatch\n | PlTableFilterStringContainsFuzzyMatch;\n/** All types of PlTableFilters string filter entries */\nexport type PlTableFilterStringType = PlTableFilterString['type'];\n\n/** All PlTableFilters filter entries */\nexport type PlTableFilter = PlTableFilterNumber | PlTableFilterString;\n/** All types of PlTableFilters filter entries */\nexport type PlTableFilterType = PlTableFilter['type'];\n\n/** Internal grid column identifier */\nexport type PlTableFilterColumnId = string;\n\n/** PlTableFiltersState entry */\nexport type PlTableFiltersStateEntry = {\n /** Column identifier */\n columnId: PlTableFilterColumnId;\n /** Active filter */\n filter: PlTableFilter;\n /** Flag to temporarily disable filter */\n disabled: boolean;\n};\n\n/** PlTableFiltersModel state */\nexport type PlTableFiltersState = PlTableFiltersStateEntry[];\n\n/** PlTableFilters model */\nexport type PlTableFiltersModel = {\n /** Internal PlTableFilters component state, do not change! */\n state?: PlTableFiltersState;\n /** Internal PlTableFilters component state, do not change!\n * Defaults filters applied to the table */\n defaultsApplied?: boolean;\n /** Resulting filters which should be used in Join */\n filters?: PTableRecordFilter[];\n};\n\nexport type CreatePlDataTableOps = {\n /** Filters for columns and non-partitioned axes */\n filters?: PTableRecordFilter[];\n\n /** Sorting to columns hidden from user */\n sorting?: PTableSorting[];\n\n /**\n * Selects columns for which will be inner-joined to the table.\n *\n * Default behaviour: all columns are considered to be core\n */\n coreColumnPredicate?: (spec: PColumnSpec) => boolean;\n\n /**\n * Determines how core columns should be joined together:\n * inner - so user will only see records present in all core columns\n * full - so user will only see records present in any of the core columns\n *\n * All non-core columns will be left joined to the table produced by the core\n * columns, in other words records form the pool of non-core columns will only\n * make their way into the final table if core table contins corresponding key.\n *\n * Default: 'full'\n */\n coreJoinType?: 'inner' | 'full';\n};\n\n/** Check if column is a label column */\nexport function isLabelColumn(column: PColumnSpec) {\n return column.axesSpec.length === 1 && column.name === 'pl7.app/label';\n}\n\n/** Get all label columns from the result pool */\nexport function getAllLabelColumns(\n resultPool: AxisLabelProvider & ColumnProvider,\n): PColumn<PColumnDataUniversal>[] | undefined {\n return new PColumnCollection()\n .addAxisLabelProvider(resultPool)\n .addColumnProvider(resultPool)\n .getColumns({\n name: 'pl7.app/label',\n axes: [{}], // exactly one axis\n }, { dontWaitAllData: true });\n}\n\n/** Get label columns matching the provided columns from the result pool */\nexport function getMatchingLabelColumns(\n columns: PColumnIdAndSpec[],\n allLabelColumns: PColumn<PColumnDataUniversal>[],\n): PColumn<PColumnDataUniversal>[] {\n // split input columns into label and value columns\n const inputLabelColumns: typeof columns = [];\n const inputValueColumns: typeof columns = [];\n for (const column of columns) {\n if (isLabelColumn(column.spec)) {\n inputLabelColumns.push(column);\n } else {\n inputValueColumns.push(column);\n }\n }\n\n // collect distinct axes of value columns\n const unlabeledAxes: AxisId[] = [];\n for (const column of inputValueColumns) {\n for (const axis of column.spec.axesSpec) {\n const axisId = getAxisId(axis);\n if (!unlabeledAxes.some((id) => matchAxisId(id, axisId))) {\n unlabeledAxes.push(axisId);\n }\n }\n }\n\n // remove axes matched by input label columns\n for (const labelColumn of inputLabelColumns) {\n const labelAxisId = getAxisId(labelColumn.spec.axesSpec[0]);\n const labelMatch = unlabeledAxes.findIndex((axisId) => matchAxisId(axisId, labelAxisId));\n if (labelMatch !== -1) {\n unlabeledAxes.splice(labelMatch, 1);\n }\n }\n\n // warning: changing this id will break backward compatibility\n const colId = (id: PObjectId, domain?: Record<string, string>): PObjectId => {\n let wid = id.toString();\n if (domain) {\n for (const k in domain) {\n wid += k;\n wid += domain[k];\n }\n }\n return wid as PObjectId;\n };\n\n // search label columns for unmatched axes\n const labelColumns: typeof allLabelColumns = [];\n for (const labelColumn of allLabelColumns) {\n const labelAxis = labelColumn.spec.axesSpec[0];\n const labelAxisId = getAxisId(labelAxis);\n const labelMatch = unlabeledAxes.findIndex((axisId) => matchAxisId(axisId, labelAxisId));\n if (labelMatch !== -1) {\n const axisId = unlabeledAxes[labelMatch];\n const dataDomainLen = Object.keys(axisId.domain ?? {}).length;\n const labelDomainLen = Object.keys(labelAxis.domain ?? {}).length;\n if (dataDomainLen > labelDomainLen) {\n labelColumns.push({\n id: colId(labelColumn.id, axisId.domain),\n spec: {\n ...labelColumn.spec,\n axesSpec: [{ ...axisId, annotations: labelAxis.annotations }],\n },\n data: labelColumn.data,\n });\n } else {\n labelColumns.push(labelColumn);\n }\n unlabeledAxes.splice(labelMatch, 1);\n }\n }\n return labelColumns;\n}\n\n/** Check if all columns are computed */\nexport function allColumnsComputed(\n columns: PColumn<PColumnValues | TreeNodeAccessor | DataInfo<TreeNodeAccessor>>[],\n): boolean {\n type Data = typeof columns[number]['data'];\n const isValues = (d: Data): d is PColumnValues => Array.isArray(d);\n const isAccessor = (d: Data): d is TreeNodeAccessor => d instanceof TreeNodeAccessor;\n const isDataInfo = (d: Data): d is DataInfo<TreeNodeAccessor> =>\n typeof d === 'object' && 'type' in d;\n\n return columns\n .map((c) => c.data)\n .every((d): boolean => {\n if (isValues(d)) {\n return true;\n } else if (isAccessor(d)) {\n return d.getIsReadyOrError();\n } else if (isDataInfo(d)) {\n const type = d.type;\n switch (type) {\n case 'Json':\n return true;\n case 'JsonPartitioned':\n return Object.values(d.parts).every((p) => p.getIsReadyOrError());\n case 'BinaryPartitioned':\n return Object.values(d.parts)\n .every((p) => p.index.getIsReadyOrError() && p.values.getIsReadyOrError());\n }\n } else {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw Error(`unsupported column data type: ${d satisfies never}`);\n }\n });\n}\n\nfunction createPTableDef(\n columns: PColumn<PColumnDataUniversal>[],\n labelColumns: PColumn<PColumnDataUniversal>[],\n coreJoinType: 'inner' | 'full',\n filters: PTableRecordSingleValueFilterV2[],\n sorting: PTableSorting[],\n coreColumnPredicate?: ((spec: PColumnSpec) => boolean),\n): PTableDef<PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>> {\n let coreColumns = columns;\n const secondaryColumns: typeof columns = [];\n\n if (coreColumnPredicate) {\n coreColumns = [];\n for (const c of columns)\n if (coreColumnPredicate(c.spec)) coreColumns.push(c);\n else secondaryColumns.push(c);\n }\n\n secondaryColumns.push(...labelColumns);\n\n return {\n src: {\n type: 'outer',\n primary: {\n type: coreJoinType,\n entries: coreColumns.map((c) => ({ type: 'column', column: c })),\n },\n secondary: secondaryColumns.map((c) => ({ type: 'column', column: c })),\n },\n filters,\n sorting,\n };\n}\n\n/**\n * Create p-table handle given ui table state\n *\n * @param ctx context\n * @param columns column list\n * @param tableState table ui state\n * @returns PlAgDataTable table source\n */\nexport function createPlDataTable<A, U>(\n ctx: RenderCtx<A, U>,\n columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableState | undefined\n): PTableHandle | undefined;\nexport function createPlDataTable<A, U>(\n ctx: RenderCtx<A, U>,\n columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableState | undefined,\n ops: CreatePlDataTableOps\n): PTableHandle | undefined;\n/** @deprecated use method with extended ops as the last argument */\nexport function createPlDataTable<A, U>(\n ctx: RenderCtx<A, U>,\n columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableState | undefined,\n filters: PTableRecordFilter[]\n): PTableHandle | undefined;\nexport function createPlDataTable<A, U>(\n ctx: RenderCtx<A, U>,\n columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableState | undefined,\n ops?: PTableRecordFilter[] | CreatePlDataTableOps,\n): PTableHandle | undefined {\n // ops migration for backward compatibility with previous deprecated API\n if (Array.isArray(ops)) {\n ops = { filters: ops };\n }\n\n const coreJoinType = ops?.coreJoinType ?? 'full';\n const filters: PTableRecordSingleValueFilterV2[]\n = uniqueBy(\n [...(ops?.filters ?? []), ...(tableState?.pTableParams?.filters ?? [])],\n (f) => canonicalizeJson<PTableColumnId>(f.column),\n );\n const sorting: PTableSorting[]\n = uniqueBy(\n [...(ops?.sorting ?? []), ...(tableState?.pTableParams?.sorting ?? [])],\n (s) => canonicalizeJson<PTableColumnId>(s.column),\n );\n\n const allLabelColumns = getAllLabelColumns(ctx.resultPool);\n if (!allLabelColumns) return undefined;\n\n const labelColumns = getMatchingLabelColumns(columns.map(getColumnIdAndSpec), allLabelColumns);\n\n // if at least one column is not yet computed, we can't show the table\n if (!allColumnsComputed([...columns, ...labelColumns])) return undefined;\n\n return ctx.createPTable(\n createPTableDef(columns, labelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate));\n}\n\n/** PlAgDataTable model */\nexport type PlDataTableModel = {\n /** p-table including all columns, used to show the full specification of the table */\n fullTableHandle: PTableHandle;\n /** p-table including only visible columns, used to get the data */\n visibleTableHandle: PTableHandle;\n};\n\n/**\n * @deprecated Used only in PlAgDataTable v1 that is no longer maintained.\n * Please migrate to v2.\n */\nexport type PTableRowKey = PTableValue[];\n\n/** Check if column should be omitted from the table */\nexport function isColumnHidden(spec: { annotations?: Record<string, string> }): boolean {\n return spec.annotations?.['pl7.app/table/visibility'] === 'hidden';\n}\n\n/** Check if column is hidden by default */\nexport function isColumnOptional(spec: { annotations?: Record<string, string> }): boolean {\n return spec.annotations?.['pl7.app/table/visibility'] === 'optional';\n}\n\n/**\n * Return unique entries of the array by the provided id\n * For each id, the last entry is kept\n */\nexport function uniqueBy<T>(array: T[], makeId: (entry: T) => string): T[] {\n return [...new Map(array.map((e) => [makeId(e), e])).values()];\n}\n\n/**\n * Create p-table spec and handle given ui table state\n *\n * @param ctx context\n * @param columns column list\n * @param tableState table ui state\n * @returns PlAgDataTableV2 table source\n */\nexport function createPlDataTableV2<A, U>(\n ctx: RenderCtx<A, U>,\n inputColumns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableStateV2 | undefined,\n ops?: CreatePlDataTableOps,\n): PlDataTableModel | undefined {\n const tableStateNormalized = upgradePlDataTableStateV2(tableState ?? createPlDataTableStateV2());\n\n const coreJoinType = ops?.coreJoinType ?? 'full';\n const filters: PTableRecordSingleValueFilterV2[]\n = uniqueBy(\n [...(ops?.filters ?? []), ...tableStateNormalized.pTableParams.filters],\n (f) => canonicalizeJson<PTableColumnId>(f.column),\n );\n const sorting: PTableSorting[]\n = uniqueBy(\n [...(ops?.sorting ?? []), ...tableStateNormalized.pTableParams.sorting],\n (s) => canonicalizeJson<PTableColumnId>(s.column),\n );\n const columns = inputColumns.filter((c) => !isColumnHidden(c.spec));\n\n const allLabelColumns = getAllLabelColumns(ctx.resultPool);\n if (!allLabelColumns) return undefined;\n\n const fullLabelColumns = getMatchingLabelColumns(columns.map(getColumnIdAndSpec), allLabelColumns);\n const fullDef = createPTableDef(columns, fullLabelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate);\n const fullHandle = ctx.createPTable(fullDef);\n\n const hiddenColumns = new Set<PObjectId>(((): PObjectId[] => {\n // Inner join works as a filter - all columns must be present\n if (coreJoinType === 'inner') return [];\n\n const hiddenColIds = tableStateNormalized.pTableParams.hiddenColIds;\n if (hiddenColIds) return hiddenColIds;\n\n return columns\n .filter((c) => isColumnOptional(c.spec))\n .map((c) => c.id);\n })());\n\n // Preserve core columns as they change the shape of join.\n if (ops?.coreColumnPredicate) {\n const coreColumns = columns.flatMap((c) => ops?.coreColumnPredicate?.(c.spec) ? [c.id] : []);\n coreColumns.forEach((c) => hiddenColumns.delete(c));\n }\n\n // Filters decrease the number of result rows, sorting changes the order of result rows\n [...filters.map((f) => f.column), ...sorting.map((s) => s.column)]\n .filter((c): c is PTableColumnIdColumn => c.type === 'column')\n .map((c) => hiddenColumns.delete(c.id));\n\n const visibleColumns = columns.filter((c) => !hiddenColumns.has(c.id));\n const visibleLabelColumns = getMatchingLabelColumns(visibleColumns.map(getColumnIdAndSpec), allLabelColumns);\n\n // if at least one column is not yet computed, we can't show the table\n if (!allColumnsComputed([...visibleColumns, ...visibleLabelColumns])) return undefined;\n\n const visibleDef = createPTableDef(visibleColumns, visibleLabelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate);\n const visibleHandle = ctx.createPTable(visibleDef);\n\n return {\n fullTableHandle: fullHandle,\n visibleTableHandle: visibleHandle,\n } satisfies PlDataTableModel;\n}\n\n/** Create sheet entries for PlDataTable */\nexport function createPlDataTableSheet<A, U>(\n ctx: RenderCtx<A, U>,\n axis: AxisSpec,\n values: (string | number)[],\n): PlDataTableSheet {\n const labels = ctx.resultPool.findLabels(axis);\n return {\n axis,\n options: values.map((v) => ({\n value: v,\n label: labels?.[v] ?? v.toString(),\n })),\n defaultValue: values[0],\n };\n}\n","import type {\n AxisId,\n CanonicalizedJson,\n PColumn,\n PColumnSpec,\n PFrameHandle,\n PObjectId,\n} from '@milaboratories/pl-model-common';\nimport {\n canonicalizeJson,\n getAxisId,\n matchAxisId, parseJson,\n} from '@milaboratories/pl-model-common';\nimport type { PColumnDataUniversal, RenderCtx } from '../render';\nimport { PColumnCollection, TreeNodeAccessor } from '../render';\nimport { isLabelColumn } from './PlDataTable';\n\n/** Create id for column copy with added keys in axes domains */\nconst colId = (id: PObjectId, domains: (Record<string, string> | undefined)[]) => {\n let wid = id.toString();\n domains?.forEach((domain) => {\n if (domain) {\n for (const [k, v] of Object.entries(domain)) {\n wid += k;\n wid += v;\n }\n }\n });\n return wid;\n};\n\n/** All combinations with 1 key from each list */\nfunction getKeysCombinations(idsLists: AxisId[][]) {\n if (!idsLists.length) {\n return [];\n }\n let result: AxisId[][] = [[]];\n idsLists.forEach((list) => {\n const nextResult: AxisId[][] = [];\n list.forEach((key) => {\n nextResult.push(...result.map((resultItem) => [...resultItem, key]));\n });\n result = nextResult;\n });\n return result;\n}\n\n/** Check if column is a linker column */\nexport function isLinkerColumn(column: PColumnSpec) {\n return column.axesSpec.length === 2 && column.annotations?.[LINKER_COLUMN_ANNOTATION] === 'true';\n}\n\nexport const IS_VIRTUAL_COLUMN = 'pl7.app/graph/isVirtual'; // annotation for column duplicates with extended domains\nexport const LABEL_ANNOTATION = 'pl7.app/label';\nexport const LINKER_COLUMN_ANNOTATION = 'pl7.app/isLinkerColumn';\n\nexport type LinkerColumnsMap = Map<CanonicalizedJson<AxisId>, Set<CanonicalizedJson<AxisId>>>;\nexport function getLinkerColumnsMap(linkerColumns: PColumn<PColumnDataUniversal>[]) {\n const resultMap: LinkerColumnsMap = new Map();\n for (const { spec } of linkerColumns) {\n const axisIds = spec.axesSpec.map(getAxisId).map(canonicalizeJson);\n axisIds.forEach((id) => {\n if (!resultMap.has(id)) {\n resultMap.set(id, new Set());\n }\n });\n for (let i = 0; i < axisIds.length - 1; i++) {\n for (let j = i + 1; j < axisIds.length; j++) {\n const id1 = axisIds[i];\n const id2 = axisIds[j];\n resultMap.get(id1)?.add(id2);\n resultMap.get(id2)?.add(id1);\n }\n }\n }\n return resultMap;\n}\n\nexport function getAvailableWithLinkersAxes(\n linkerColumns: PColumn<PColumnDataUniversal>[],\n blockAxes: Map<CanonicalizedJson<AxisId>, AxisId>,\n): Map<CanonicalizedJson<AxisId>, AxisId> {\n const linkerColumnsMap = getLinkerColumnsMap(linkerColumns);\n const linkerColumnsMapIds = [...linkerColumnsMap.keys()].map(parseJson);\n const startKeys: CanonicalizedJson<AxisId>[] = [];\n for (const startId of blockAxes.values()) {\n const matched = linkerColumnsMapIds.find((id) => matchAxisId(startId, id));\n if (matched) {\n startKeys.push(canonicalizeJson(matched)); // linker column can contain fewer domains than in block's columns, it's fixed on next step in enrichCompatible\n }\n }\n const visited: Set<CanonicalizedJson<AxisId>> = new Set(startKeys);\n const addedAvailableAxes: Map<CanonicalizedJson<AxisId>, AxisId> = new Map();\n let nextKeys = [...startKeys];\n\n while (nextKeys.length) {\n const next: CanonicalizedJson<AxisId>[] = [];\n for (const nextKey of nextKeys) {\n for (const availableKey of linkerColumnsMap.get(nextKey) ?? []) {\n if (!visited.has(availableKey)) {\n next.push(availableKey);\n visited.add(availableKey);\n addedAvailableAxes.set(availableKey, parseJson(availableKey));\n }\n }\n }\n nextKeys = next;\n }\n return addedAvailableAxes;\n}\n/** Add columns with fully compatible axes created from partial compatible ones */\nexport function enrichCompatible(blockAxes: Map<string, AxisId>, columns: PColumn<PColumnDataUniversal>[]) {\n const result: PColumn<PColumnDataUniversal>[] = [];\n columns.forEach((column) => {\n result.push(...getAdditionalColumnsForColumn(blockAxes, column));\n });\n return result;\n}\n\nfunction getAdditionalColumnsForColumn(\n blockAxes: Map<string, AxisId>,\n column: PColumn<PColumnDataUniversal>,\n): PColumn<PColumnDataUniversal>[] {\n const columnAxesIds = column.spec.axesSpec.map(getAxisId);\n\n if (columnAxesIds.every((id) => blockAxes.has(canonicalizeJson(id)))) {\n return [column]; // the column is compatible with its own domains without modifications\n }\n\n // options with different possible domains for every axis of secondary column\n const secondaryIdsOptions = columnAxesIds.map((id) => {\n const result = [];\n for (const [_, mainId] of blockAxes) {\n if (matchAxisId(mainId, id) && !matchAxisId(id, mainId)) {\n result.push(mainId);\n }\n }\n return result;\n });\n // all possible combinations of axes with added domains\n const secondaryIdsVariants = getKeysCombinations(secondaryIdsOptions);\n\n // sets of added to column domain fields\n const allAddedDomainValues = new Set<string>();\n const addedNotToAllVariantsDomainValues = new Set<string>();\n const addedByVariantsDomainValues = secondaryIdsVariants.map((idsList) => {\n const addedSet = new Set<string>();\n idsList.map((axisId, idx) => {\n const d1 = column.spec.axesSpec[idx].domain;\n const d2 = axisId.domain;\n Object.entries(d2 ?? {}).forEach(([key, value]) => {\n if (d1?.[key] === undefined) {\n const item = JSON.stringify([key, value]);\n addedSet.add(item);\n allAddedDomainValues.add(item);\n }\n });\n return ({\n ...axisId,\n annotations: column.spec.axesSpec[idx].annotations,\n });\n });\n return addedSet;\n });\n [...allAddedDomainValues].forEach((addedPart) => {\n if (addedByVariantsDomainValues.some((s) => !s.has(addedPart))) {\n addedNotToAllVariantsDomainValues.add(addedPart);\n }\n });\n\n const additionalColumns = secondaryIdsVariants.map((idsList, idx) => {\n const id = colId(column.id, idsList.map((id) => id.domain));\n\n const label = column.spec.annotations?.[LABEL_ANNOTATION] ?? '';\n const labelDomainPart = ([...addedByVariantsDomainValues[idx]])\n .filter((str) => addedNotToAllVariantsDomainValues.has(str))\n .sort()\n .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\n .join(' / ');\n\n const annotations: Record<string, string> = {\n ...column.spec.annotations,\n [IS_VIRTUAL_COLUMN]: 'true',\n };\n if (label || labelDomainPart) {\n annotations[LABEL_ANNOTATION] = label && labelDomainPart ? label + ' / ' + labelDomainPart : label + labelDomainPart;\n }\n\n return {\n id: id as PObjectId,\n spec: {\n ...column.spec,\n axesSpec: idsList.map((axisId, idx) => ({\n ...axisId,\n annotations: column.spec.axesSpec[idx].annotations,\n })),\n annotations,\n },\n data: column.data,\n };\n });\n\n return [column, ...additionalColumns];\n}\n\n/**\n The aim of createPFrameForGraphs: to create pframe with block’s columns and all compatible columns from result pool\n (including linker columns and all label columns).\n Block’s columns are added to pframe as is.\n Other columns are added basing on set of axes of block’s columns, considering available with linker columns.\n Compatible columns must have at least one axis from block’s axes set. This axis of the compatible column from\n result pool must satisfy matchAxisId (it can have less domain keys than in block’s axis, but without conflicting values\n among existing ones).\n In requests to pframe (calculateTableData) columns must have strictly the same axes. For compatibility in case\n of partially matched axis we add to pframe a copy of this column with modified axis (with filled missed domains)\n and modified label (with added domain values in case if more than one copy with different domains exist).\n */\nexport function createPFrameForGraphs<A, U>(\n ctx: RenderCtx<A, U>,\n blockColumns: PColumn<PColumnDataUniversal>[] | undefined,\n): PFrameHandle | undefined {\n if (!blockColumns) return undefined;\n\n const columns = new PColumnCollection();\n columns.addColumnProvider(ctx.resultPool);\n columns.addColumns(blockColumns);\n\n // all possible axes from block columns\n const blockAxes = new Map<CanonicalizedJson<AxisId>, AxisId>();\n // axes from block columns and compatible result pool columns\n const allAxes = new Map<CanonicalizedJson<AxisId>, AxisId>();\n for (const c of blockColumns) {\n for (const id of c.spec.axesSpec) {\n const aid = getAxisId(id);\n blockAxes.set(canonicalizeJson(aid), aid);\n allAxes.set(canonicalizeJson(aid), aid);\n }\n }\n\n // all linker columns always go to pFrame - even it's impossible to use some of them they all are hidden\n const linkerColumns = columns.getColumns((spec) => isLinkerColumn(spec)) ?? [];\n const availableWithLinkersAxes = getAvailableWithLinkersAxes(linkerColumns, blockAxes);\n\n // all possible axes from connected linkers\n for (const item of availableWithLinkersAxes) {\n blockAxes.set(...item);\n allAxes.set(...item);\n }\n\n // all compatible with block columns but without label columns\n const compatibleWithoutLabels = (columns.getColumns((spec) => spec.axesSpec.some(axisSpec => {\n const axisId = getAxisId(axisSpec);\n for (const selectorAxisId of blockAxes.values()) {\n if (matchAxisId(selectorAxisId, axisId)) {\n return true;\n }\n }\n return false;\n }), {dontWaitAllData: true, overrideLabelAnnotation: false}) ?? []).filter((column) => !isLabelColumn(column.spec));\n\n // extend axes set for label columns request\n for (const c of compatibleWithoutLabels) {\n for (const id of c.spec.axesSpec) {\n const aid = getAxisId(id);\n allAxes.set(canonicalizeJson(aid), aid);\n }\n }\n\n // label columns must be compatible with full set of axes - block axes and axes from compatible columns from result pool\n const compatibleLabels = (columns.getColumns((spec) => spec.axesSpec.some(axisSpec => {\n const axisId = getAxisId(axisSpec);\n for (const selectorAxisId of allAxes.values()) {\n if (matchAxisId(selectorAxisId, axisId)) {\n return true;\n }\n }\n return false;\n }), {dontWaitAllData: true, overrideLabelAnnotation: false}) ?? []).filter((column) => isLabelColumn(column.spec));\n\n const compatible = [...compatibleWithoutLabels, ...compatibleLabels];\n\n // additional columns are duplicates with extra fields in domains for compatibility if there are ones with partial match\n const extendedColumns = enrichCompatible(blockAxes, compatible);\n\n // if at least one column is not yet ready, we can't show the table\n if (\n extendedColumns.some(\n (a) => a.data instanceof TreeNodeAccessor && !a.data.getIsReadyOrError(),\n )\n )\n return undefined;\n\n return ctx.createPFrame(extendedColumns);\n}\n","import {\n isPTableAbsent,\n type PColumn,\n type PColumnIdAndSpec,\n type PColumnKey,\n type PColumnValues,\n type PObjectId,\n type PTableColumnId,\n uniquePlId,\n} from '@milaboratories/pl-model-common';\nimport { type PlSelectionModel } from './PlSelectionModel';\n\nexport type PColumnPredicate = (column: PColumnIdAndSpec) => boolean;\n\nexport type PlMultiSequenceAlignmentModel = {\n version?: number;\n sequenceColumnIds?: PObjectId[];\n labelColumnIds?: PTableColumnId[];\n};\n\nexport function createRowSelectionColumn({\n selection,\n columnId = uniquePlId() as string as PObjectId,\n label = 'Selection marker',\n domain,\n}: {\n selection: PlSelectionModel | undefined;\n columnId?: PObjectId;\n label?: string;\n domain?: Record<string, string>;\n}): PColumn<PColumnValues> | undefined {\n if (!selection?.axesSpec.length) {\n return;\n }\n const data: PColumnValues = selection.selectedKeys\n .filter((r): r is PColumnKey => r.every((v) => !isPTableAbsent(v)))\n .map((r) => ({ key: r, val: 1 }));\n if (!data.length) {\n return;\n }\n return {\n id: columnId,\n spec: {\n kind: 'PColumn',\n valueType: 'Int',\n name: 'pl7.app/table/row-selection',\n axesSpec: selection.axesSpec,\n ...(domain && Object.keys(domain).length && { domain }),\n annotations: {\n 'pl7.app/label': label,\n 'pl7.app/discreteValues': '[1]',\n },\n },\n data,\n };\n}\n","import type { AxesSpec, PTableAbsent, PTableValue } from '@milaboratories/pl-model-common';\nimport { PTableNA } from '@milaboratories/pl-model-common';\n\n/** Key is a set of all axes values, which means it is unique across rows */\nexport type PTableKey = AxisValue[];\n\n/** Readable axis value */\nexport type AxisValue = string | number | PTableAbsent;\n\n/**\n * Information on selected rows.\n * for selectedKeys = [[axis1Value, axis2Value, axis3Value], ...]\n * axesSpec would be [axis1Spec, axis2Spec, axis3Spec]\n */\nexport type PlSelectionModel = {\n /** Specs for {@link AxisValue}'s in {@link PTableKey} */\n axesSpec: AxesSpec;\n /** Row keys (arrays of axes values) of selected rows */\n selectedKeys: PTableKey[];\n};\n\nexport function mapPTableValueToAxisKey(value: PTableValue): AxisValue {\n if (value === PTableNA) {\n console.error('Axis value can never be N/A');\n return ''; // @TODO: add proper handling\n }\n return value;\n}\n","import type { ValueOrErrors } from '@milaboratories/pl-model-common';\nimport {} from './global';\nimport { getPlatformaInstance } from './internal';\nimport type { Platforma } from './platforma';\nimport { PlatformaSDKVersion } from './version';\n\nexport function getRawPlatformaInstance<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(): Platforma<Args, Outputs, UiState, Href> {\n return getPlatformaInstance<Args, Outputs, UiState, Href>({ sdkVersion: PlatformaSDKVersion });\n}\n\n/** Returns a global platforma instance or a provided fallback if it's not available. */\nexport function getPlatformaOrDefault<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(platforma: Platforma<Args, Outputs, UiState, Href>): Platforma<Args, Outputs, UiState, Href> {\n try {\n return getRawPlatformaInstance<Args, Outputs, UiState, Href>();\n } catch {\n return platforma;\n }\n}\n","import {} from './global';\n\nexport function getEnvironmentValue(name: string): string | undefined {\n if (typeof globalThis.getEnvironmentValue !== 'function') return undefined;\n else return globalThis.getEnvironmentValue(name);\n}\n"],"names":["getPlatformaInstance","config","TraceEntry","z","PlatformaSDKVersion","createPlDataTableStateV2","upgradePlDataTableStateV2","state","isLabelColumn","column","isColumnOptional","spec","_a","isLinkerColumn","LINKER_COLUMN_ANNOTATION","createRowSelectionColumn","selection","columnId","uniquePlId","label","domain","data","r","v","isPTableAbsent","mapPTableValueToAxisKey","value","PTableNA","getRawPlatformaInstance","getPlatformaOrDefault","platforma","getEnvironmentValue","name"],"mappings":";;;;;AAaO,SAASA,EAKdC,GAA0E;AACtEA,MAAAA,KAAU,OAAO,WAAW,gBAAiB;AACxC,WAAA,WAAW,aAAaA,CAAM;AAAA,MAC9B,OAAO,WAAW,YAAc,IAAA,QAAoB,WAAW;AAC7D,QAAA,IAAI,MAAM,+BAAgC;AACvD;MCDaC,IAAaC,EAAE,OAAO;AAAA,EACjC,MAAMA,EAAE,OAAO;AAAA,EACf,YAAYA,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,IAAIA,EAAE,OAAO,EAAE,SAAS;AAAA,EACxB,OAAOA,EAAE,OAAO;AAClB,CAAC;AAIoBA,EAAE,MAAMD,CAAU;AC/BhC,MAAME,IAAsB;ACgJ5B,SAASC,IAAyD;AAChE,SAAA;AAAA,IACL,SAAS;AAAA,IACT,YAAY,CAAC;AAAA,IACb,cAAc;AAAA,MACZ,SAAS,CAAC;AAAA,MACV,SAAS,CAAC;AAAA,MACV,cAAc;AAAA,IAAA;AAAA,EAElB;AACF;AAGO,SAASC,EAA0BC,GAAyD;AAE3F,SAAA,aAAaA,IAIZA,IAFEF,EAAyB;AAGpC;AAiPO,SAASG,EAAcC,GAAqB;AACjD,SAAOA,EAAO,SAAS,WAAW,KAAKA,EAAO,SAAS;AACzD;AAiPO,SAASC,EAAiBC,GAAyD;;AACjF,WAAAC,IAAAD,EAAK,gBAAL,OAAA,SAAAC,EAAmB,0BAAgC,OAAA;AAC5D;AC1lBO,SAASC,EAAeJ,GAAqB;;AAC3CA,SAAAA,EAAO,SAAS,WAAW,OAAKG,IAAAH,EAAO,gBAAP,OAAAG,SAAAA,EAAqBE,CAA8B,OAAA;AAC5F;AAEO,MAEMA,IAA2B;AClCjC,SAASC,EAAyB;AAAA,EACvC,WAAAC;AAAAA,EACA,UAAAC,IAAWC,EAAW;AAAA,EACtB,OAAAC,IAAQ;AAAA,EACR,QAAAC;AACF,GAKuC;AACjC,MAAA,EAACJ,KAAA,QAAAA,EAAW,SAAS;AACvB;AAEIK,QAAAA,IAAsBL,EAAU,aACnC,OAAO,CAACM,MAAuBA,EAAE,MAAM,CAACC,MAAM,CAACC,EAAeD,CAAC,CAAC,CAAC,EACjE,IAAI,CAACD,OAAO,EAAE,KAAKA,GAAG,KAAK,EAAA,EAAI;AAC9B,MAACD,EAAK;AAGH,WAAA;AAAA,MACL,IAAIJ;AAAAA,MACJ,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,WAAW;AAAA,QACX,MAAM;AAAA,QACN,UAAUD,EAAU;AAAA,QACpB,GAAII,KAAU,OAAO,KAAKA,CAAM,EAAE,UAAU,EAAE,QAAAA,EAAO;AAAA,QACrD,aAAa;AAAA,UACX,iBAAiBD;AAAAA,UACjB,0BAA0B;AAAA,QAAA;AAAA,MAE9B;AAAA,MACA,MAAAE;AAAAA,IACF;AACF;AClCO,SAASI,EAAwBC,GAA+B;AACrE,SAAIA,MAAUC,KACZ,QAAQ,MAAM,6BAA6B,GACpC,MAEFD;AACT;ACrBO,SAASE,IAK6B;AACpC5B,SAAAA,EAAmD,EAAE,YAAYI,GAAqB;AAC/F;AAGO,SAASyB,EAKdC,GAA6F;AACzF,MAAA;AACF,WAAOF,EAAsD;AAAA,EAAA,QACvD;AACCE,WAAAA;AAAAA,EAAA;AAEX;ACzBO,SAASC,EAAoBC,GAAkC;AAChE,MAAA,OAAO,WAAW,uBAAwB;AAClC,WAAA,WAAW,oBAAoBA,CAAI;AACjD;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../../model/src/internal.ts","../../../../../model/src/render/util/label.ts","../../../../../model/src/version.ts","../../../../../model/src/components/PlDataTable.ts","../../../../../model/src/components/PFrameForGraphs.ts","../../../../../model/src/components/PlMultiSequenceAlignment.ts","../../../../../model/src/components/PlSelectionModel.ts","../../../../../model/src/raw_globals.ts","../../../../../model/src/env_value.ts"],"sourcesContent":["import type { ValueOrErrors } from '@milaboratories/pl-model-common';\nimport {} from './global';\nimport type { Platforma } from './platforma';\nimport type { FutureHandle, GlobalCfgRenderCtx } from './render/internal';\n\n/** Utility code helping to identify whether the code is running in actual UI environment */\nexport function isInUI() {\n return (\n typeof globalThis.getPlatforma !== 'undefined' || typeof globalThis.platforma !== 'undefined'\n );\n}\n\n/** Utility code helping to retrieve a platforma instance form the environment */\nexport function getPlatformaInstance<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(config?: { sdkVersion: string }): Platforma<Args, Outputs, UiState, Href> {\n if (config && typeof globalThis.getPlatforma === 'function')\n return globalThis.getPlatforma(config);\n else if (typeof globalThis.platforma !== 'undefined') return globalThis.platforma;\n else throw new Error('Can\\'t get platforma instance.');\n}\n\nexport function tryGetCfgRenderCtx(): GlobalCfgRenderCtx | undefined {\n if (typeof globalThis.cfgRenderCtx !== 'undefined') return globalThis.cfgRenderCtx;\n else return undefined;\n}\n\nexport function getCfgRenderCtx(): GlobalCfgRenderCtx {\n if (typeof globalThis.cfgRenderCtx !== 'undefined') return globalThis.cfgRenderCtx;\n else throw new Error('Not in config rendering context');\n}\n\nexport function tryRegisterCallback(key: string, callback: (...args: any[]) => any): boolean {\n const ctx = tryGetCfgRenderCtx();\n if (ctx === undefined) return false;\n if (key in ctx.callbackRegistry) throw new Error(`Callback with key ${key} already registered.`);\n ctx.callbackRegistry[key] = callback;\n return true;\n}\n\nconst futureResolves = new Map<string, ((value: unknown) => void)[]>();\n\nexport function registerFutureAwait(handle: FutureHandle, onResolve: (value: unknown) => void) {\n if (!(handle in getCfgRenderCtx().callbackRegistry)) {\n getCfgRenderCtx().callbackRegistry[handle] = (value: unknown) => {\n for (const res of futureResolves.get(handle)!) {\n res(value);\n }\n };\n futureResolves.set(handle, []);\n }\n futureResolves.get(handle)!.push(onResolve);\n}\n","import type { PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport const PAnnotationLabel = 'pl7.app/label';\nexport const PAnnotationTrace = 'pl7.app/trace';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = spec.annotations?.[PAnnotationLabel];\n const traceStr = spec.annotations?.[PAnnotationTrace];\n const baseTrace = (traceStr ? Trace.safeParse(JSON.parse(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n // checking if labels uniquely separate our records\n if (candidateResult !== undefined && new Set(candidateResult.map((c) => c.label)).size === values.length) return candidateResult;\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n return calculate(new Set([...mainTypes, ...secondaryTypes]), true)!;\n}\n","export const PlatformaSDKVersion = '1.37.11';\n","import type {\n AxisId,\n AxisSpec,\n CanonicalizedJson,\n DataInfo,\n ListOptionBase,\n PColumn,\n PColumnIdAndSpec,\n PColumnSpec,\n PColumnValues,\n PObjectId,\n PTableColumnId,\n PTableColumnIdColumn,\n PTableColumnSpec,\n PTableDef,\n PTableHandle,\n PTableRecordFilter,\n PTableRecordSingleValueFilterV2,\n PTableSorting,\n PTableValue,\n} from '@milaboratories/pl-model-common';\nimport {\n canonicalizeJson,\n getAxisId,\n getColumnIdAndSpec,\n matchAxisId,\n} from '@milaboratories/pl-model-common';\nimport type {\n AxisLabelProvider,\n ColumnProvider,\n PColumnDataUniversal,\n RenderCtx,\n} from '../render';\nimport {\n PColumnCollection,\n TreeNodeAccessor,\n} from '../render';\n\n/** Canonicalized PTableColumnSpec JSON string */\nexport type PTableColumnSpecJson = CanonicalizedJson<PTableColumnSpec>;\n\nexport type PlDataTableGridStateCore = {\n /** Includes column ordering */\n columnOrder?: {\n /** All colIds in order */\n orderedColIds: PTableColumnSpecJson[];\n };\n /** Includes current sort columns and direction */\n sort?: {\n /** Sorted columns and directions in order */\n sortModel: {\n /** Column Id to apply the sort to. */\n colId: PTableColumnSpecJson;\n /** Sort direction */\n sort: 'asc' | 'desc';\n }[];\n };\n /** Includes column visibility */\n columnVisibility?: {\n /** All colIds which were hidden */\n hiddenColIds: PTableColumnSpecJson[];\n };\n};\n\n/** TODO: refactor to use sheets in the grid state */\nexport type PlDataTableGridStateWithoutSheets = PlDataTableGridStateCore & {\n /** DataSource identifier for state management */\n sourceId?: string;\n};\n\n/** Data table state */\nexport type PlDataTableGridState = PlDataTableGridStateWithoutSheets & {\n /** current sheet selections */\n sheets?: Record<CanonicalizedJson<AxisId>, string | number>;\n};\n\nexport type PlDataTableSheet = {\n /** spec of the axis to use */\n axis: AxisSpec;\n /** options to show in the filter dropdown */\n options: ListOptionBase<string | number>[];\n /** default (selected) value */\n defaultValue?: string | number;\n};\n\nexport type PlDataTableSheetState = {\n /** id of the axis */\n axisId: AxisId;\n /** selected value */\n value: string | number;\n};\n\n/**\n * Params used to get p-table handle from the driver\n */\nexport type PTableParams = {\n sorting?: PTableSorting[];\n filters?: PTableRecordFilter[];\n};\n\n/**\n * PlDataTable persisted state\n */\nexport type PlDataTableState = {\n // internal ag-grid state\n gridState: PlDataTableGridState;\n // mapping of gridState onto the p-table data structures\n pTableParams?: PTableParams;\n};\n\n/**\n * PlDataTableV2 persisted state\n */\nexport type PlDataTableStateV2 =\n // Old versions of the state\n | PlDataTableState\n // Normalized state\n | PlDataTableStateV2Normalized;\n\nexport type PlDataTableStateV2CacheEntry = {\n /** DataSource identifier for state management */\n sourceId: string;\n /** Internal ag-grid state */\n gridState: PlDataTableGridStateCore;\n /** Sheets state */\n sheetsState: PlDataTableSheetState[];\n};\n\nexport type PTableParamsV2 = {\n sorting: PTableSorting[];\n filters: PTableRecordFilter[];\n hiddenColIds: PObjectId[] | null;\n};\n\nexport type PlDataTableStateV2Normalized = {\n // version for upgrades\n version: 2;\n // internal ag-grid states, LRU cache for 5 sourceId-s\n stateCache: PlDataTableStateV2CacheEntry[];\n // mapping of gridState for current sourceId onto the p-table data structures\n pTableParams: PTableParamsV2;\n};\n\n/** Create default PlDataTableStateV2 */\nexport function createPlDataTableStateV2(): PlDataTableStateV2Normalized {\n return {\n version: 2,\n stateCache: [],\n pTableParams: {\n sorting: [],\n filters: [],\n hiddenColIds: null,\n },\n };\n}\n\n/** Upgrade PlDataTableStateV2 to the latest version */\nexport function upgradePlDataTableStateV2(state: PlDataTableStateV2): PlDataTableStateV2Normalized {\n // v1 -> v2\n if (!('version' in state)) {\n // Non upgradeable as sourceId calculation algorithm has changed, resetting state to default\n return createPlDataTableStateV2();\n }\n return state;\n}\n\n/** PlTableFilters filter entry */\nexport type PlTableFilterIsNotNA = {\n /** Predicate type */\n type: 'isNotNA';\n};\n\n/** PlTableFilters filter entry */\nexport type PlTableFilterIsNA = {\n /** Predicate type */\n type: 'isNA';\n};\n\n/** PlTableFilters filter entries applicable to both string and number values */\nexport type PlTableFilterCommon = PlTableFilterIsNotNA | PlTableFilterIsNA;\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberEquals = {\n /** Predicate type */\n type: 'number_equals';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberNotEquals = {\n /** Predicate type */\n type: 'number_notEquals';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberGreaterThan = {\n /** Predicate type */\n type: 'number_greaterThan';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberGreaterThanOrEqualTo = {\n /** Predicate type */\n type: 'number_greaterThanOrEqualTo';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberLessThan = {\n /** Predicate type */\n type: 'number_lessThan';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberLessThanOrEqualTo = {\n /** Predicate type */\n type: 'number_lessThanOrEqualTo';\n /** Referense value */\n reference: number;\n};\n\n/** PlTableFilters numeric filter entry */\nexport type PlTableFilterNumberBetween = {\n /** Predicate type */\n type: 'number_between';\n /** Referense value for the lower bound */\n lowerBound: number;\n /** Defines whether values equal to lower bound reference value should be matched */\n includeLowerBound: boolean;\n /** Referense value for the upper bound */\n upperBound: number;\n /** Defines whether values equal to upper bound reference value should be matched */\n includeUpperBound: boolean;\n};\n\n/** All PlTableFilters numeric filter entries */\nexport type PlTableFilterNumber =\n | PlTableFilterCommon\n | PlTableFilterNumberEquals\n | PlTableFilterNumberNotEquals\n | PlTableFilterNumberGreaterThan\n | PlTableFilterNumberGreaterThanOrEqualTo\n | PlTableFilterNumberLessThan\n | PlTableFilterNumberLessThanOrEqualTo\n | PlTableFilterNumberBetween;\n/** All types of PlTableFilters numeric filter entries */\nexport type PlTableFilterNumberType = PlTableFilterNumber['type'];\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringEquals = {\n /** Predicate type */\n type: 'string_equals';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringNotEquals = {\n /** Predicate type */\n type: 'string_notEquals';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringContains = {\n /** Predicate type */\n type: 'string_contains';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringDoesNotContain = {\n /** Predicate type */\n type: 'string_doesNotContain';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringMatches = {\n /** Predicate type */\n type: 'string_matches';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringDoesNotMatch = {\n /** Predicate type */\n type: 'string_doesNotMatch';\n /** Referense value */\n reference: string;\n};\n\n/** PlTableFilters string filter entry */\nexport type PlTableFilterStringContainsFuzzyMatch = {\n /** Predicate type */\n type: 'string_containsFuzzyMatch';\n /** Referense value */\n reference: string;\n /**\n * Maximum acceptable edit distance between reference value and matched substring\n * @see https://en.wikipedia.org/wiki/Edit_distance\n */\n maxEdits: number;\n /**\n * When {@link substitutionsOnly} is set to false\n * Levenshtein distance is used as edit distance (substitutions and indels)\n * @see https://en.wikipedia.org/wiki/Levenshtein_distance\n * When {@link substitutionsOnly} is set to true\n * Hamming distance is used as edit distance (substitutions only)\n * @see https://en.wikipedia.org/wiki/Hamming_distance\n */\n substitutionsOnly: boolean;\n /**\n * Single character in {@link reference} that will labelColumn any\n * single character in searched text.\n */\n wildcard?: string;\n};\n\n/** All PlTableFilters string filter entries */\nexport type PlTableFilterString =\n | PlTableFilterCommon\n | PlTableFilterStringEquals\n | PlTableFilterStringNotEquals\n | PlTableFilterStringContains\n | PlTableFilterStringDoesNotContain\n | PlTableFilterStringMatches\n | PlTableFilterStringDoesNotMatch\n | PlTableFilterStringContainsFuzzyMatch;\n/** All types of PlTableFilters string filter entries */\nexport type PlTableFilterStringType = PlTableFilterString['type'];\n\n/** All PlTableFilters filter entries */\nexport type PlTableFilter = PlTableFilterNumber | PlTableFilterString;\n/** All types of PlTableFilters filter entries */\nexport type PlTableFilterType = PlTableFilter['type'];\n\n/** Internal grid column identifier */\nexport type PlTableFilterColumnId = string;\n\n/** PlTableFiltersState entry */\nexport type PlTableFiltersStateEntry = {\n /** Column identifier */\n columnId: PlTableFilterColumnId;\n /** Active filter */\n filter: PlTableFilter;\n /** Flag to temporarily disable filter */\n disabled: boolean;\n};\n\n/** PlTableFiltersModel state */\nexport type PlTableFiltersState = PlTableFiltersStateEntry[];\n\n/** PlTableFilters model */\nexport type PlTableFiltersModel = {\n /** Internal PlTableFilters component state, do not change! */\n state?: PlTableFiltersState;\n /** Internal PlTableFilters component state, do not change!\n * Defaults filters applied to the table */\n defaultsApplied?: boolean;\n /** Resulting filters which should be used in Join */\n filters?: PTableRecordFilter[];\n};\n\nexport type CreatePlDataTableOps = {\n /** Filters for columns and non-partitioned axes */\n filters?: PTableRecordFilter[];\n\n /** Sorting to columns hidden from user */\n sorting?: PTableSorting[];\n\n /**\n * Selects columns for which will be inner-joined to the table.\n *\n * Default behaviour: all columns are considered to be core\n */\n coreColumnPredicate?: (spec: PColumnSpec) => boolean;\n\n /**\n * Determines how core columns should be joined together:\n * inner - so user will only see records present in all core columns\n * full - so user will only see records present in any of the core columns\n *\n * All non-core columns will be left joined to the table produced by the core\n * columns, in other words records form the pool of non-core columns will only\n * make their way into the final table if core table contins corresponding key.\n *\n * Default: 'full'\n */\n coreJoinType?: 'inner' | 'full';\n};\n\n/** Check if column is a label column */\nexport function isLabelColumn(column: PColumnSpec) {\n return column.axesSpec.length === 1 && column.name === 'pl7.app/label';\n}\n\n/** Get all label columns from the result pool */\nexport function getAllLabelColumns(\n resultPool: AxisLabelProvider & ColumnProvider,\n): PColumn<PColumnDataUniversal>[] | undefined {\n return new PColumnCollection()\n .addAxisLabelProvider(resultPool)\n .addColumnProvider(resultPool)\n .getColumns({\n name: 'pl7.app/label',\n axes: [{}], // exactly one axis\n }, { dontWaitAllData: true });\n}\n\n/** Get label columns matching the provided columns from the result pool */\nexport function getMatchingLabelColumns(\n columns: PColumnIdAndSpec[],\n allLabelColumns: PColumn<PColumnDataUniversal>[],\n): PColumn<PColumnDataUniversal>[] {\n // split input columns into label and value columns\n const inputLabelColumns: typeof columns = [];\n const inputValueColumns: typeof columns = [];\n for (const column of columns) {\n if (isLabelColumn(column.spec)) {\n inputLabelColumns.push(column);\n } else {\n inputValueColumns.push(column);\n }\n }\n\n // collect distinct axes of value columns\n const unlabeledAxes: AxisId[] = [];\n for (const column of inputValueColumns) {\n for (const axis of column.spec.axesSpec) {\n const axisId = getAxisId(axis);\n if (!unlabeledAxes.some((id) => matchAxisId(id, axisId))) {\n unlabeledAxes.push(axisId);\n }\n }\n }\n\n // remove axes matched by input label columns\n for (const labelColumn of inputLabelColumns) {\n const labelAxisId = getAxisId(labelColumn.spec.axesSpec[0]);\n const labelMatch = unlabeledAxes.findIndex((axisId) => matchAxisId(axisId, labelAxisId));\n if (labelMatch !== -1) {\n unlabeledAxes.splice(labelMatch, 1);\n }\n }\n\n // warning: changing this id will break backward compatibility\n const colId = (id: PObjectId, domain?: Record<string, string>): PObjectId => {\n let wid = id.toString();\n if (domain) {\n for (const k in domain) {\n wid += k;\n wid += domain[k];\n }\n }\n return wid as PObjectId;\n };\n\n // search label columns for unmatched axes\n const labelColumns: typeof allLabelColumns = [];\n for (const labelColumn of allLabelColumns) {\n const labelAxis = labelColumn.spec.axesSpec[0];\n const labelAxisId = getAxisId(labelAxis);\n const labelMatch = unlabeledAxes.findIndex((axisId) => matchAxisId(axisId, labelAxisId));\n if (labelMatch !== -1) {\n const axisId = unlabeledAxes[labelMatch];\n const dataDomainLen = Object.keys(axisId.domain ?? {}).length;\n const labelDomainLen = Object.keys(labelAxis.domain ?? {}).length;\n if (dataDomainLen > labelDomainLen) {\n labelColumns.push({\n id: colId(labelColumn.id, axisId.domain),\n spec: {\n ...labelColumn.spec,\n axesSpec: [{ ...axisId, annotations: labelAxis.annotations }],\n },\n data: labelColumn.data,\n });\n } else {\n labelColumns.push(labelColumn);\n }\n unlabeledAxes.splice(labelMatch, 1);\n }\n }\n return labelColumns;\n}\n\n/** Check if all columns are computed */\nexport function allColumnsComputed(\n columns: PColumn<PColumnValues | TreeNodeAccessor | DataInfo<TreeNodeAccessor>>[],\n): boolean {\n type Data = typeof columns[number]['data'];\n const isValues = (d: Data): d is PColumnValues => Array.isArray(d);\n const isAccessor = (d: Data): d is TreeNodeAccessor => d instanceof TreeNodeAccessor;\n const isDataInfo = (d: Data): d is DataInfo<TreeNodeAccessor> =>\n typeof d === 'object' && 'type' in d;\n\n return columns\n .map((c) => c.data)\n .every((d): boolean => {\n if (isValues(d)) {\n return true;\n } else if (isAccessor(d)) {\n return d.getIsReadyOrError();\n } else if (isDataInfo(d)) {\n const type = d.type;\n switch (type) {\n case 'Json':\n return true;\n case 'JsonPartitioned':\n return Object.values(d.parts).every((p) => p.getIsReadyOrError());\n case 'BinaryPartitioned':\n return Object.values(d.parts)\n .every((p) => p.index.getIsReadyOrError() && p.values.getIsReadyOrError());\n }\n } else {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw Error(`unsupported column data type: ${d satisfies never}`);\n }\n });\n}\n\nfunction createPTableDef(\n columns: PColumn<PColumnDataUniversal>[],\n labelColumns: PColumn<PColumnDataUniversal>[],\n coreJoinType: 'inner' | 'full',\n filters: PTableRecordSingleValueFilterV2[],\n sorting: PTableSorting[],\n coreColumnPredicate?: ((spec: PColumnSpec) => boolean),\n): PTableDef<PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>> {\n let coreColumns = columns;\n const secondaryColumns: typeof columns = [];\n\n if (coreColumnPredicate) {\n coreColumns = [];\n for (const c of columns)\n if (coreColumnPredicate(c.spec)) coreColumns.push(c);\n else secondaryColumns.push(c);\n }\n\n secondaryColumns.push(...labelColumns);\n\n return {\n src: {\n type: 'outer',\n primary: {\n type: coreJoinType,\n entries: coreColumns.map((c) => ({ type: 'column', column: c })),\n },\n secondary: secondaryColumns.map((c) => ({ type: 'column', column: c })),\n },\n filters,\n sorting,\n };\n}\n\n/**\n * Create p-table handle given ui table state\n *\n * @param ctx context\n * @param columns column list\n * @param tableState table ui state\n * @returns PlAgDataTable table source\n */\nexport function createPlDataTable<A, U>(\n ctx: RenderCtx<A, U>,\n columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableState | undefined\n): PTableHandle | undefined;\nexport function createPlDataTable<A, U>(\n ctx: RenderCtx<A, U>,\n columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableState | undefined,\n ops: CreatePlDataTableOps\n): PTableHandle | undefined;\n/** @deprecated use method with extended ops as the last argument */\nexport function createPlDataTable<A, U>(\n ctx: RenderCtx<A, U>,\n columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableState | undefined,\n filters: PTableRecordFilter[]\n): PTableHandle | undefined;\nexport function createPlDataTable<A, U>(\n ctx: RenderCtx<A, U>,\n columns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableState | undefined,\n ops?: PTableRecordFilter[] | CreatePlDataTableOps,\n): PTableHandle | undefined {\n // ops migration for backward compatibility with previous deprecated API\n if (Array.isArray(ops)) {\n ops = { filters: ops };\n }\n\n const coreJoinType = ops?.coreJoinType ?? 'full';\n const filters: PTableRecordSingleValueFilterV2[]\n = uniqueBy(\n [...(ops?.filters ?? []), ...(tableState?.pTableParams?.filters ?? [])],\n (f) => canonicalizeJson<PTableColumnId>(f.column),\n );\n const sorting: PTableSorting[]\n = uniqueBy(\n [...(ops?.sorting ?? []), ...(tableState?.pTableParams?.sorting ?? [])],\n (s) => canonicalizeJson<PTableColumnId>(s.column),\n );\n\n const allLabelColumns = getAllLabelColumns(ctx.resultPool);\n if (!allLabelColumns) return undefined;\n\n const labelColumns = getMatchingLabelColumns(columns.map(getColumnIdAndSpec), allLabelColumns);\n\n // if at least one column is not yet computed, we can't show the table\n if (!allColumnsComputed([...columns, ...labelColumns])) return undefined;\n\n return ctx.createPTable(\n createPTableDef(columns, labelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate));\n}\n\n/** PlAgDataTable model */\nexport type PlDataTableModel = {\n /** p-table including all columns, used to show the full specification of the table */\n fullTableHandle: PTableHandle;\n /** p-table including only visible columns, used to get the data */\n visibleTableHandle: PTableHandle;\n};\n\n/**\n * @deprecated Used only in PlAgDataTable v1 that is no longer maintained.\n * Please migrate to v2.\n */\nexport type PTableRowKey = PTableValue[];\n\n/** Check if column should be omitted from the table */\nexport function isColumnHidden(spec: { annotations?: Record<string, string> }): boolean {\n return spec.annotations?.['pl7.app/table/visibility'] === 'hidden';\n}\n\n/** Check if column is hidden by default */\nexport function isColumnOptional(spec: { annotations?: Record<string, string> }): boolean {\n return spec.annotations?.['pl7.app/table/visibility'] === 'optional';\n}\n\n/**\n * Return unique entries of the array by the provided id\n * For each id, the last entry is kept\n */\nexport function uniqueBy<T>(array: T[], makeId: (entry: T) => string): T[] {\n return [...new Map(array.map((e) => [makeId(e), e])).values()];\n}\n\n/**\n * Create p-table spec and handle given ui table state\n *\n * @param ctx context\n * @param columns column list\n * @param tableState table ui state\n * @returns PlAgDataTableV2 table source\n */\nexport function createPlDataTableV2<A, U>(\n ctx: RenderCtx<A, U>,\n inputColumns: PColumn<TreeNodeAccessor | PColumnValues | DataInfo<TreeNodeAccessor>>[],\n tableState: PlDataTableStateV2,\n ops?: CreatePlDataTableOps,\n): PlDataTableModel | undefined {\n if (inputColumns.length === 0) return undefined;\n const tableStateNormalized = upgradePlDataTableStateV2(tableState ?? createPlDataTableStateV2());\n\n const coreJoinType = ops?.coreJoinType ?? 'full';\n const filters: PTableRecordSingleValueFilterV2[]\n = uniqueBy(\n [...(ops?.filters ?? []), ...tableStateNormalized.pTableParams.filters],\n (f) => canonicalizeJson<PTableColumnId>(f.column),\n );\n const sorting: PTableSorting[]\n = uniqueBy(\n [...(ops?.sorting ?? []), ...tableStateNormalized.pTableParams.sorting],\n (s) => canonicalizeJson<PTableColumnId>(s.column),\n );\n const columns = inputColumns.filter((c) => !isColumnHidden(c.spec));\n\n const allLabelColumns = getAllLabelColumns(ctx.resultPool);\n if (!allLabelColumns) return undefined;\n\n const fullLabelColumns = getMatchingLabelColumns(columns.map(getColumnIdAndSpec), allLabelColumns);\n const fullDef = createPTableDef(columns, fullLabelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate);\n const fullHandle = ctx.createPTable(fullDef);\n\n const hiddenColumns = new Set<PObjectId>(((): PObjectId[] => {\n // Inner join works as a filter - all columns must be present\n if (coreJoinType === 'inner') return [];\n\n const hiddenColIds = tableStateNormalized.pTableParams.hiddenColIds;\n if (hiddenColIds) return hiddenColIds;\n\n return columns\n .filter((c) => isColumnOptional(c.spec))\n .map((c) => c.id);\n })());\n\n // Preserve linker columns\n columns\n .filter((c) => c.spec.annotations?.['pl7.app/isLinkerColumn'] === 'true')\n .forEach((c) => hiddenColumns.delete(c.id));\n\n // Preserve core columns as they change the shape of join.\n if (ops?.coreColumnPredicate) {\n const coreColumns = columns.flatMap((c) => ops?.coreColumnPredicate?.(c.spec) ? [c.id] : []);\n coreColumns.forEach((c) => hiddenColumns.delete(c));\n }\n\n // Filters decrease the number of result rows, sorting changes the order of result rows\n [...filters.map((f) => f.column), ...sorting.map((s) => s.column)]\n .filter((c): c is PTableColumnIdColumn => c.type === 'column')\n .forEach((c) => hiddenColumns.delete(c.id));\n\n const visibleColumns = columns.filter((c) => !hiddenColumns.has(c.id));\n const visibleLabelColumns = getMatchingLabelColumns(visibleColumns.map(getColumnIdAndSpec), allLabelColumns);\n\n // if at least one column is not yet computed, we can't show the table\n if (!allColumnsComputed([...visibleColumns, ...visibleLabelColumns])) return undefined;\n\n const visibleDef = createPTableDef(visibleColumns, visibleLabelColumns, coreJoinType, filters, sorting, ops?.coreColumnPredicate);\n const visibleHandle = ctx.createPTable(visibleDef);\n\n return {\n fullTableHandle: fullHandle,\n visibleTableHandle: visibleHandle,\n } satisfies PlDataTableModel;\n}\n\n/** Create sheet entries for PlDataTable */\nexport function createPlDataTableSheet<A, U>(\n ctx: RenderCtx<A, U>,\n axis: AxisSpec,\n values: (string | number)[],\n): PlDataTableSheet {\n const labels = ctx.resultPool.findLabels(axis);\n return {\n axis,\n options: values.map((v) => ({\n value: v,\n label: labels?.[v] ?? v.toString(),\n })),\n defaultValue: values[0],\n };\n}\n","import type {\n AxisId,\n CanonicalizedJson,\n PColumn,\n PColumnSpec,\n PFrameHandle,\n PObjectId,\n} from '@milaboratories/pl-model-common';\nimport {\n canonicalizeJson,\n getAxisId,\n matchAxisId, parseJson,\n} from '@milaboratories/pl-model-common';\nimport type { PColumnDataUniversal, RenderCtx } from '../render';\nimport { PColumnCollection, TreeNodeAccessor } from '../render';\nimport { isLabelColumn } from './PlDataTable';\n\n/** Create id for column copy with added keys in axes domains */\nconst colId = (id: PObjectId, domains: (Record<string, string> | undefined)[]) => {\n let wid = id.toString();\n domains?.forEach((domain) => {\n if (domain) {\n for (const [k, v] of Object.entries(domain)) {\n wid += k;\n wid += v;\n }\n }\n });\n return wid;\n};\n\n/** All combinations with 1 key from each list */\nfunction getKeysCombinations(idsLists: AxisId[][]) {\n if (!idsLists.length) {\n return [];\n }\n let result: AxisId[][] = [[]];\n idsLists.forEach((list) => {\n const nextResult: AxisId[][] = [];\n list.forEach((key) => {\n nextResult.push(...result.map((resultItem) => [...resultItem, key]));\n });\n result = nextResult;\n });\n return result;\n}\n\n/** Check if column is a linker column */\nexport function isLinkerColumn(column: PColumnSpec) {\n return column.axesSpec.length === 2 && column.annotations?.[LINKER_COLUMN_ANNOTATION] === 'true';\n}\n\nexport const IS_VIRTUAL_COLUMN = 'pl7.app/graph/isVirtual'; // annotation for column duplicates with extended domains\nexport const LABEL_ANNOTATION = 'pl7.app/label';\nexport const LINKER_COLUMN_ANNOTATION = 'pl7.app/isLinkerColumn';\n\nexport type LinkerColumnsMap = Map<CanonicalizedJson<AxisId>, Set<CanonicalizedJson<AxisId>>>;\nexport function getLinkerColumnsMap(linkerColumns: PColumn<PColumnDataUniversal>[]) {\n const resultMap: LinkerColumnsMap = new Map();\n for (const { spec } of linkerColumns) {\n const axisIds = spec.axesSpec.map(getAxisId).map(canonicalizeJson);\n axisIds.forEach((id) => {\n if (!resultMap.has(id)) {\n resultMap.set(id, new Set());\n }\n });\n for (let i = 0; i < axisIds.length - 1; i++) {\n for (let j = i + 1; j < axisIds.length; j++) {\n const id1 = axisIds[i];\n const id2 = axisIds[j];\n resultMap.get(id1)?.add(id2);\n resultMap.get(id2)?.add(id1);\n }\n }\n }\n return resultMap;\n}\n\nexport function getAvailableWithLinkersAxes(\n linkerColumns: PColumn<PColumnDataUniversal>[],\n blockAxes: Map<CanonicalizedJson<AxisId>, AxisId>,\n): Map<CanonicalizedJson<AxisId>, AxisId> {\n const linkerColumnsMap = getLinkerColumnsMap(linkerColumns);\n const linkerColumnsMapIds = [...linkerColumnsMap.keys()].map(parseJson);\n const startKeys: CanonicalizedJson<AxisId>[] = [];\n for (const startId of blockAxes.values()) {\n const matched = linkerColumnsMapIds.find((id) => matchAxisId(startId, id));\n if (matched) {\n startKeys.push(canonicalizeJson(matched)); // linker column can contain fewer domains than in block's columns, it's fixed on next step in enrichCompatible\n }\n }\n const visited: Set<CanonicalizedJson<AxisId>> = new Set(startKeys);\n const addedAvailableAxes: Map<CanonicalizedJson<AxisId>, AxisId> = new Map();\n let nextKeys = [...startKeys];\n\n while (nextKeys.length) {\n const next: CanonicalizedJson<AxisId>[] = [];\n for (const nextKey of nextKeys) {\n for (const availableKey of linkerColumnsMap.get(nextKey) ?? []) {\n if (!visited.has(availableKey)) {\n next.push(availableKey);\n visited.add(availableKey);\n addedAvailableAxes.set(availableKey, parseJson(availableKey));\n }\n }\n }\n nextKeys = next;\n }\n return addedAvailableAxes;\n}\n/** Add columns with fully compatible axes created from partial compatible ones */\nexport function enrichCompatible(blockAxes: Map<string, AxisId>, columns: PColumn<PColumnDataUniversal>[]) {\n const result: PColumn<PColumnDataUniversal>[] = [];\n columns.forEach((column) => {\n result.push(...getAdditionalColumnsForColumn(blockAxes, column));\n });\n return result;\n}\n\nfunction getAdditionalColumnsForColumn(\n blockAxes: Map<string, AxisId>,\n column: PColumn<PColumnDataUniversal>,\n): PColumn<PColumnDataUniversal>[] {\n const columnAxesIds = column.spec.axesSpec.map(getAxisId);\n\n if (columnAxesIds.every((id) => blockAxes.has(canonicalizeJson(id)))) {\n return [column]; // the column is compatible with its own domains without modifications\n }\n\n // options with different possible domains for every axis of secondary column\n const secondaryIdsOptions = columnAxesIds.map((id) => {\n const result = [];\n for (const [_, mainId] of blockAxes) {\n if (matchAxisId(mainId, id) && !matchAxisId(id, mainId)) {\n result.push(mainId);\n }\n }\n return result;\n });\n // all possible combinations of axes with added domains\n const secondaryIdsVariants = getKeysCombinations(secondaryIdsOptions);\n\n // sets of added to column domain fields\n const allAddedDomainValues = new Set<string>();\n const addedNotToAllVariantsDomainValues = new Set<string>();\n const addedByVariantsDomainValues = secondaryIdsVariants.map((idsList) => {\n const addedSet = new Set<string>();\n idsList.map((axisId, idx) => {\n const d1 = column.spec.axesSpec[idx].domain;\n const d2 = axisId.domain;\n Object.entries(d2 ?? {}).forEach(([key, value]) => {\n if (d1?.[key] === undefined) {\n const item = JSON.stringify([key, value]);\n addedSet.add(item);\n allAddedDomainValues.add(item);\n }\n });\n return ({\n ...axisId,\n annotations: column.spec.axesSpec[idx].annotations,\n });\n });\n return addedSet;\n });\n [...allAddedDomainValues].forEach((addedPart) => {\n if (addedByVariantsDomainValues.some((s) => !s.has(addedPart))) {\n addedNotToAllVariantsDomainValues.add(addedPart);\n }\n });\n\n const additionalColumns = secondaryIdsVariants.map((idsList, idx) => {\n const id = colId(column.id, idsList.map((id) => id.domain));\n\n const label = column.spec.annotations?.[LABEL_ANNOTATION] ?? '';\n const labelDomainPart = ([...addedByVariantsDomainValues[idx]])\n .filter((str) => addedNotToAllVariantsDomainValues.has(str))\n .sort()\n .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\n .join(' / ');\n\n const annotations: Record<string, string> = {\n ...column.spec.annotations,\n [IS_VIRTUAL_COLUMN]: 'true',\n };\n if (label || labelDomainPart) {\n annotations[LABEL_ANNOTATION] = label && labelDomainPart ? label + ' / ' + labelDomainPart : label + labelDomainPart;\n }\n\n return {\n id: id as PObjectId,\n spec: {\n ...column.spec,\n axesSpec: idsList.map((axisId, idx) => ({\n ...axisId,\n annotations: column.spec.axesSpec[idx].annotations,\n })),\n annotations,\n },\n data: column.data,\n };\n });\n\n return [column, ...additionalColumns];\n}\n\n/**\n The aim of createPFrameForGraphs: to create pframe with block’s columns and all compatible columns from result pool\n (including linker columns and all label columns).\n Block’s columns are added to pframe as is.\n Other columns are added basing on set of axes of block’s columns, considering available with linker columns.\n Compatible columns must have at least one axis from block’s axes set. This axis of the compatible column from\n result pool must satisfy matchAxisId (it can have less domain keys than in block’s axis, but without conflicting values\n among existing ones).\n In requests to pframe (calculateTableData) columns must have strictly the same axes. For compatibility in case\n of partially matched axis we add to pframe a copy of this column with modified axis (with filled missed domains)\n and modified label (with added domain values in case if more than one copy with different domains exist).\n */\nexport function createPFrameForGraphs<A, U>(\n ctx: RenderCtx<A, U>,\n blockColumns: PColumn<PColumnDataUniversal>[] | undefined,\n): PFrameHandle | undefined {\n if (!blockColumns) return undefined;\n\n const columns = new PColumnCollection();\n columns.addColumnProvider(ctx.resultPool);\n columns.addColumns(blockColumns);\n\n // all possible axes from block columns\n const blockAxes = new Map<CanonicalizedJson<AxisId>, AxisId>();\n // axes from block columns and compatible result pool columns\n const allAxes = new Map<CanonicalizedJson<AxisId>, AxisId>();\n for (const c of blockColumns) {\n for (const id of c.spec.axesSpec) {\n const aid = getAxisId(id);\n blockAxes.set(canonicalizeJson(aid), aid);\n allAxes.set(canonicalizeJson(aid), aid);\n }\n }\n\n // all linker columns always go to pFrame - even it's impossible to use some of them they all are hidden\n const linkerColumns = columns.getColumns((spec) => isLinkerColumn(spec)) ?? [];\n const availableWithLinkersAxes = getAvailableWithLinkersAxes(linkerColumns, blockAxes);\n\n // all possible axes from connected linkers\n for (const item of availableWithLinkersAxes) {\n blockAxes.set(...item);\n allAxes.set(...item);\n }\n\n // all compatible with block columns but without label columns\n const compatibleWithoutLabels = (columns.getColumns((spec) => spec.axesSpec.some(axisSpec => {\n const axisId = getAxisId(axisSpec);\n for (const selectorAxisId of blockAxes.values()) {\n if (matchAxisId(selectorAxisId, axisId)) {\n return true;\n }\n }\n return false;\n }), {dontWaitAllData: true, overrideLabelAnnotation: false}) ?? []).filter((column) => !isLabelColumn(column.spec));\n\n // extend axes set for label columns request\n for (const c of compatibleWithoutLabels) {\n for (const id of c.spec.axesSpec) {\n const aid = getAxisId(id);\n allAxes.set(canonicalizeJson(aid), aid);\n }\n }\n\n // label columns must be compatible with full set of axes - block axes and axes from compatible columns from result pool\n const compatibleLabels = (columns.getColumns((spec) => spec.axesSpec.some(axisSpec => {\n const axisId = getAxisId(axisSpec);\n for (const selectorAxisId of allAxes.values()) {\n if (matchAxisId(selectorAxisId, axisId)) {\n return true;\n }\n }\n return false;\n }), {dontWaitAllData: true, overrideLabelAnnotation: false}) ?? []).filter((column) => isLabelColumn(column.spec));\n\n const compatible = [...compatibleWithoutLabels, ...compatibleLabels];\n\n // additional columns are duplicates with extra fields in domains for compatibility if there are ones with partial match\n const extendedColumns = enrichCompatible(blockAxes, compatible);\n\n // if at least one column is not yet ready, we can't show the table\n if (\n extendedColumns.some(\n (a) => a.data instanceof TreeNodeAccessor && !a.data.getIsReadyOrError(),\n )\n )\n return undefined;\n\n return ctx.createPFrame(extendedColumns);\n}\n","import {\n isPTableAbsent,\n type PColumn,\n type PColumnIdAndSpec,\n type PColumnKey,\n type PColumnValues,\n type PObjectId,\n type PTableColumnId,\n uniquePlId,\n} from '@milaboratories/pl-model-common';\nimport { type PlSelectionModel } from './PlSelectionModel';\n\nexport type PColumnPredicate = (column: PColumnIdAndSpec) => boolean;\n\nexport type PlMultiSequenceAlignmentModel = {\n version?: number;\n sequenceColumnIds?: PObjectId[];\n labelColumnIds?: PTableColumnId[];\n};\n\nexport function createRowSelectionColumn({\n selection,\n columnId = uniquePlId() as string as PObjectId,\n label = 'Selection marker',\n domain,\n}: {\n selection: PlSelectionModel | undefined;\n columnId?: PObjectId;\n label?: string;\n domain?: Record<string, string>;\n}): PColumn<PColumnValues> | undefined {\n if (!selection?.axesSpec.length) {\n return;\n }\n const data: PColumnValues = selection.selectedKeys\n .filter((r): r is PColumnKey => r.every((v) => !isPTableAbsent(v)))\n .map((r) => ({ key: r, val: 1 }));\n if (!data.length) {\n return;\n }\n return {\n id: columnId,\n spec: {\n kind: 'PColumn',\n valueType: 'Int',\n name: 'pl7.app/table/row-selection',\n axesSpec: selection.axesSpec,\n ...(domain && Object.keys(domain).length && { domain }),\n annotations: {\n 'pl7.app/label': label,\n 'pl7.app/discreteValues': '[1]',\n },\n },\n data,\n };\n}\n","import type { AxesSpec, PTableAbsent, PTableValue } from '@milaboratories/pl-model-common';\nimport { PTableNA } from '@milaboratories/pl-model-common';\n\n/** Key is a set of all axes values, which means it is unique across rows */\nexport type PTableKey = AxisValue[];\n\n/** Readable axis value */\nexport type AxisValue = string | number | PTableAbsent;\n\n/**\n * Information on selected rows.\n * for selectedKeys = [[axis1Value, axis2Value, axis3Value], ...]\n * axesSpec would be [axis1Spec, axis2Spec, axis3Spec]\n */\nexport type PlSelectionModel = {\n /** Specs for {@link AxisValue}'s in {@link PTableKey} */\n axesSpec: AxesSpec;\n /** Row keys (arrays of axes values) of selected rows */\n selectedKeys: PTableKey[];\n};\n\nexport function mapPTableValueToAxisKey(value: PTableValue): AxisValue {\n if (value === PTableNA) {\n console.error('Axis value can never be N/A');\n return ''; // @TODO: add proper handling\n }\n return value;\n}\n","import type { ValueOrErrors } from '@milaboratories/pl-model-common';\nimport {} from './global';\nimport { getPlatformaInstance } from './internal';\nimport type { Platforma } from './platforma';\nimport { PlatformaSDKVersion } from './version';\n\nexport function getRawPlatformaInstance<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(): Platforma<Args, Outputs, UiState, Href> {\n return getPlatformaInstance<Args, Outputs, UiState, Href>({ sdkVersion: PlatformaSDKVersion });\n}\n\n/** Returns a global platforma instance or a provided fallback if it's not available. */\nexport function getPlatformaOrDefault<\n Args = unknown,\n Outputs extends Record<string, ValueOrErrors<unknown>> = Record<string, ValueOrErrors<unknown>>,\n UiState = unknown,\n Href extends `/${string}` = `/${string}`,\n>(platforma: Platforma<Args, Outputs, UiState, Href>): Platforma<Args, Outputs, UiState, Href> {\n try {\n return getRawPlatformaInstance<Args, Outputs, UiState, Href>();\n } catch {\n return platforma;\n }\n}\n","import {} from './global';\n\nexport function getEnvironmentValue(name: string): string | undefined {\n if (typeof globalThis.getEnvironmentValue !== 'function') return undefined;\n else return globalThis.getEnvironmentValue(name);\n}\n"],"names":["getPlatformaInstance","config","TraceEntry","z","PlatformaSDKVersion","createPlDataTableStateV2","upgradePlDataTableStateV2","state","isLabelColumn","column","isColumnOptional","spec","_a","isLinkerColumn","LINKER_COLUMN_ANNOTATION","createRowSelectionColumn","selection","columnId","uniquePlId","label","domain","data","r","v","isPTableAbsent","mapPTableValueToAxisKey","value","PTableNA","getRawPlatformaInstance","getPlatformaOrDefault","platforma","getEnvironmentValue","name"],"mappings":";;;;;AAaO,SAASA,EAKdC,GAA0E;AACtEA,MAAAA,KAAU,OAAO,WAAW,gBAAiB;AACxC,WAAA,WAAW,aAAaA,CAAM;AAAA,MAC9B,OAAO,WAAW,YAAc,IAAA,QAAoB,WAAW;AAC7D,QAAA,IAAI,MAAM,+BAAgC;AACvD;MCDaC,IAAaC,EAAE,OAAO;AAAA,EACjC,MAAMA,EAAE,OAAO;AAAA,EACf,YAAYA,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,IAAIA,EAAE,OAAO,EAAE,SAAS;AAAA,EACxB,OAAOA,EAAE,OAAO;AAClB,CAAC;AAIoBA,EAAE,MAAMD,CAAU;AC/BhC,MAAME,IAAsB;ACgJ5B,SAASC,IAAyD;AAChE,SAAA;AAAA,IACL,SAAS;AAAA,IACT,YAAY,CAAC;AAAA,IACb,cAAc;AAAA,MACZ,SAAS,CAAC;AAAA,MACV,SAAS,CAAC;AAAA,MACV,cAAc;AAAA,IAAA;AAAA,EAElB;AACF;AAGO,SAASC,EAA0BC,GAAyD;AAE3F,SAAA,aAAaA,IAIZA,IAFEF,EAAyB;AAGpC;AAiPO,SAASG,EAAcC,GAAqB;AACjD,SAAOA,EAAO,SAAS,WAAW,KAAKA,EAAO,SAAS;AACzD;AAiPO,SAASC,EAAiBC,GAAyD;;AACjF,WAAAC,IAAAD,EAAK,gBAAL,OAAA,SAAAC,EAAmB,0BAAgC,OAAA;AAC5D;AC1lBO,SAASC,EAAeJ,GAAqB;;AAC3CA,SAAAA,EAAO,SAAS,WAAW,OAAKG,IAAAH,EAAO,gBAAP,OAAAG,SAAAA,EAAqBE,CAA8B,OAAA;AAC5F;AAEO,MAEMA,IAA2B;AClCjC,SAASC,EAAyB;AAAA,EACvC,WAAAC;AAAAA,EACA,UAAAC,IAAWC,EAAW;AAAA,EACtB,OAAAC,IAAQ;AAAA,EACR,QAAAC;AACF,GAKuC;AACjC,MAAA,EAACJ,KAAA,QAAAA,EAAW,SAAS;AACvB;AAEIK,QAAAA,IAAsBL,EAAU,aACnC,OAAO,CAACM,MAAuBA,EAAE,MAAM,CAACC,MAAM,CAACC,EAAeD,CAAC,CAAC,CAAC,EACjE,IAAI,CAACD,OAAO,EAAE,KAAKA,GAAG,KAAK,EAAA,EAAI;AAC9B,MAACD,EAAK;AAGH,WAAA;AAAA,MACL,IAAIJ;AAAAA,MACJ,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,WAAW;AAAA,QACX,MAAM;AAAA,QACN,UAAUD,EAAU;AAAA,QACpB,GAAII,KAAU,OAAO,KAAKA,CAAM,EAAE,UAAU,EAAE,QAAAA,EAAO;AAAA,QACrD,aAAa;AAAA,UACX,iBAAiBD;AAAAA,UACjB,0BAA0B;AAAA,QAAA;AAAA,MAE9B;AAAA,MACA,MAAAE;AAAAA,IACF;AACF;AClCO,SAASI,EAAwBC,GAA+B;AACrE,SAAIA,MAAUC,KACZ,QAAQ,MAAM,6BAA6B,GACpC,MAEFD;AACT;ACrBO,SAASE,IAK6B;AACpC5B,SAAAA,EAAmD,EAAE,YAAYI,GAAqB;AAC/F;AAGO,SAASyB,EAKdC,GAA6F;AACzF,MAAA;AACF,WAAOF,EAAsD;AAAA,EAAA,QACvD;AACCE,WAAAA;AAAAA,EAAA;AAEX;ACzBO,SAASC,EAAoBC,GAAkC;AAChE,MAAA,OAAO,WAAW,uBAAwB;AAClC,WAAA,WAAW,oBAAoBA,CAAI;AACjD;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/ui-vue",
3
- "version": "1.37.10",
3
+ "version": "1.37.11",
4
4
  "type": "module",
5
5
  "main": "dist/lib.js",
6
6
  "styles": "dist/lib.js",
@@ -29,9 +29,9 @@
29
29
  "d3-format": "^3.1.0",
30
30
  "lodash": "^4.17.17",
31
31
  "zod": "~3.23.8",
32
- "@milaboratories/uikit": "^2.2.93",
33
32
  "@milaboratories/biowasm-tools": "^1.1.0",
34
- "@platforma-sdk/model": "^1.37.2"
33
+ "@platforma-sdk/model": "^1.37.11",
34
+ "@milaboratories/uikit": "^2.2.94"
35
35
  },
36
36
  "devDependencies": {
37
37
  "happy-dom": "^15.11.7",
@@ -44,9 +44,9 @@
44
44
  "vitest": "^2.1.9",
45
45
  "vue-tsc": "^2.1.10",
46
46
  "yarpm": "^1.2.0",
47
+ "@milaboratories/build-configs": "1.0.4",
47
48
  "@milaboratories/ts-configs": "1.0.4",
48
49
  "@milaboratories/helpers": "^1.6.15",
49
- "@milaboratories/build-configs": "1.0.4",
50
50
  "@milaboratories/eslint-config": "^1.0.4"
51
51
  },
52
52
  "scripts": {