@platforma-sdk/ui-vue 1.72.0 → 1.73.2

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.72.0 build /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.73.2 build /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder build --target browser-lib
5
5
 
6
6
  Building browser-lib project...
@@ -16,7 +16,7 @@ Building browser-lib project...
16
16
  rendering chunks...
17
17
 
18
18
  [vite:dts] Start generate declaration files...
19
- [vite:dts] Declaration files built in 5393ms.
19
+ [vite:dts] Declaration files built in 4944ms.
20
20
 
21
21
  computing gzip size...
22
22
  dist/components/PlAnnotations/components/PlAnnotations.vue?vue&type=style&index=0&lang.css 0.04 kB │ gzip: 0.06 kB
@@ -24,7 +24,7 @@ dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue_vue_type_style_index_0_l
24
24
  dist/components/BlockLayout.vue?vue&type=style&index=0&lang.css 0.05 kB │ gzip: 0.07 kB
25
25
  dist/components/PlAgDataTable/PlAgDataTableSheets.vue?vue&type=style&index=0&lang.css 0.06 kB │ gzip: 0.08 kB
26
26
  dist/components/PlAnnotations/components/PlAnnotationsModal.vue?vue&type=style&index=0&lang.css 0.07 kB │ gzip: 0.08 kB
27
- dist/components/PlDatasetSelector/PlDatasetSelector.vue_vue_type_style_index_0_scoped_95f2adf4_lang.css 0.08 kB │ gzip: 0.09 kB
27
+ dist/components/PlDatasetSelector/PlDatasetSelector.vue_vue_type_style_index_0_scoped_cb8d3a14_lang.css 0.08 kB │ gzip: 0.09 kB
28
28
  dist/components/PlAgDataTable/PlAgDataTableV2.vue?vue&type=style&index=0&lang.css 0.09 kB │ gzip: 0.10 kB
29
29
  dist/components/PlAnnotations/components/FilterSidebar.vue?vue&type=style&index=0&lang.css 0.11 kB │ gzip: 0.09 kB
30
30
  dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue_vue_type_style_index_0_lang.css 0.16 kB │ gzip: 0.13 kB
@@ -203,11 +203,11 @@ dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue_vue_
203
203
  dist/components/PlAgDataTable/PlAgDataTableSheets.vue_vue_type_script_setup_true_lang.js 2.45 kB │ gzip: 1.17 kB │ map: 5.01 kB
204
204
  dist/components/PlAnnotations/components/PlAnnotations.vue_vue_type_script_setup_true_lang.js 2.69 kB │ gzip: 1.12 kB │ map: 4.16 kB
205
205
  dist/lib.js 2.73 kB │ gzip: 0.57 kB │ map: 3.98 kB
206
+ dist/components/PlDatasetSelector/PlDatasetSelector.vue_vue_type_script_setup_true_lang.js 2.90 kB │ gzip: 1.14 kB │ map: 6.46 kB
206
207
  dist/components/PlAgDataTable/compositions/useGrid.js 2.91 kB │ gzip: 1.29 kB │ map: 6.51 kB
207
208
  dist/components/PlAgColumnHeader/PlAgColumnHeader.vue_vue_type_script_setup_true_lang.js 2.93 kB │ gzip: 1.26 kB │ map: 7.97 kB
208
209
  dist/components/PlAgDataTable/sources/row-number.js 2.99 kB │ gzip: 1.31 kB │ map: 7.42 kB
209
210
  dist/defineApp.js 3.01 kB │ gzip: 1.05 kB │ map: 14.38 kB
210
- dist/components/PlDatasetSelector/PlDatasetSelector.vue_vue_type_script_setup_true_lang.js 3.18 kB │ gzip: 1.24 kB │ map: 7.33 kB
211
211
  dist/plugins/Monetization/LimitCard.vue_vue_type_script_setup_true_lang.js 3.31 kB │ gzip: 1.15 kB │ map: 9.08 kB
212
212
  dist/composition/fileContent.js 3.78 kB │ gzip: 1.45 kB │ map: 12.95 kB
213
213
  dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue_vue_type_script_setup_true_lang.js 3.83 kB │ gzip: 1.64 kB │ map: 6.89 kB
@@ -222,18 +222,18 @@ dist/components/PlBtnExportArchive/PlBtnExportArchive.vue_vue_type_script_setup_
222
222
  dist/internal/createAppV2.js 5.26 kB │ gzip: 1.98 kB │ map: 17.78 kB
223
223
  dist/components/PlAgDataTable/sources/table-state-v2.js 5.73 kB │ gzip: 1.85 kB │ map: 19.41 kB
224
224
  dist/internal/createAppV3.js 5.77 kB │ gzip: 2.21 kB │ map: 20.16 kB
225
- dist/components/PlAgDataTable/sources/table-source-v2.js 6.97 kB │ gzip: 2.70 kB │ map: 24.29 kB
225
+ dist/components/PlAgDataTable/sources/table-source-v2.js 6.89 kB │ gzip: 2.69 kB │ map: 24.21 kB
226
226
  dist/components/PlAdvancedFilter/PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js 8.54 kB │ gzip: 2.59 kB │ map: 18.44 kB
227
227
  dist/components/PlAdvancedFilter/FilterEditor.vue_vue_type_script_setup_true_lang.js 10.24 kB │ gzip: 3.04 kB │ map: 23.20 kB
228
228
  dist/components/PlAgDataTable/PlAgDataTableV2.vue_vue_type_script_setup_true_lang.js 12.31 kB │ gzip: 3.90 kB │ map: 29.22 kB
229
229
 
230
230
  [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugins. Here is a breakdown:
231
- - sourcemaps (46%)
232
- - vite:dts (21%)
233
- - vite:vue (9%)
234
- - vite:css-post (7%)
235
- - vite:css (6%)
231
+ - sourcemaps (31%)
232
+ - vite:dts (25%)
233
+ - vite:vue (13%)
234
+ - vite:css-post (12%)
235
+ - vite:css (8%)
236
236
  See https://rolldown.rs/options/checks#plugintimings for more details.
237
237
  
238
- ✓ built in 6.25s
238
+ ✓ built in 5.83s
239
239
  Build completed successfully
@@ -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.72.0 formatter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.73.2 formatter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder formatter --check
5
5
 
6
6
  Checking formatting...
@@ -8,5 +8,5 @@ Checking formatting...
8
8
  Checking formatting...
9
9
 
10
10
  All matched files use the correct format.
11
- Finished in 2617ms on 137 files using 8 threads.
11
+ Finished in 1383ms on 137 files using 8 threads.
12
12
  Format check completed successfully
@@ -1,10 +1,10 @@
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.72.0 linter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.73.2 linter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder linter --check
5
5
 
6
6
  Linting project...
7
7
  ↳ oxlint --config /home/runner/_work/platforma/platforma/sdk/ui-vue/.oxlintrc.json --deny-warnings
8
8
  Found 0 warnings and 0 errors.
9
- Finished in 56ms on 120 files with 98 rules using 8 threads.
9
+ Finished in 29ms on 120 files with 98 rules using 8 threads.
10
10
  Linting completed successfully
@@ -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.72.0 types:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.73.2 types:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder type-check --target browser-lib
5
5
 
6
6
  ↳ vue-tsc.js --noEmit --project ./tsconfig.json --customConditions ,
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @platforma-sdk/ui-vue
2
2
 
3
+ ## 1.73.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 62ab678: Disable linker tooltips
8
+
9
+ ## 1.73.0
10
+
11
+ ### Patch Changes
12
+
13
+ - 2df0aff: `buildDatasetOptions`: scope filter discovery to the result pool only (block outputs and prerun no longer pollute the filter dropdown), add a `filter` predicate to restrict eligible filter columns, and skip filter matches without a PlRef instead of throwing. Removes the need for callers to wrap `buildDatasetOptions` in try/catch.
14
+
15
+ `tableBuilder.addPrimary`: drop a `PrimaryRef.filter` whose `resolveColumn` produced no spec, so a stale or malformed filter ref no longer causes `pframes.build-table` to panic with `field "spec" not found and inputs locked`.
16
+
17
+ `PlDatasetSelector`: always render the filter dropdown, regardless of whether the selected dataset has compatible filters; the dropdown is clearable and uses an empty selection (instead of a synthetic "No filter" entry) to mean "no filter applied". Removed the `noFilterLabel` prop.
18
+
19
+ - Updated dependencies [2df0aff]
20
+ - @platforma-sdk/model@1.73.0
21
+ - @milaboratories/uikit@2.13.4
22
+
3
23
  ## 1.72.0
4
24
 
5
25
  ### Patch Changes
@@ -112,8 +112,7 @@ function T(t, n, o, d, f) {
112
112
  default: throw Error(`unsupported data type: ${m}`);
113
113
  }
114
114
  })(),
115
- tooltip: y(n.spec, c.Description)?.trim() ?? y(o.spec, c.Description)?.trim(),
116
- info: y(n.spec, c.Table.Info)?.trim() ?? y(o.spec, c.Table.Info)?.trim()
115
+ tooltip: y(n.spec, c.Description)?.trim() ?? y(o.spec, c.Description)?.trim()
117
116
  },
118
117
  cellDataType: (() => {
119
118
  switch (m) {
@@ -1 +1 @@
1
- {"version":3,"file":"table-source-v2.js","names":[],"sources":["../../../../src/components/PlAgDataTable/sources/table-source-v2.ts"],"sourcesContent":["import type {\n AxesSpec,\n PTableColumnId,\n PTableColumnSpecAxis,\n PTableColumnSpecColumn,\n PTableHandle,\n PTableValue,\n} from \"@platforma-sdk/model\";\nimport {\n canonicalizeJson,\n getAxisId,\n pTableValue,\n type PFrameDriver,\n type PlDataTableSheet,\n type PTableVector,\n type AxisId,\n type PTableColumnSpec,\n type PTableKey,\n type PlTableColumnId,\n type PlTableColumnIdJson,\n isLabelColumn as isLabelColumnSpec,\n isLinkerColumn as isLinkerColumnSpec,\n isColumnHidden,\n isColumnOptional,\n matchAxisId,\n readAnnotation,\n readAnnotationJson,\n Annotation,\n ValueType,\n getPTableColumnId,\n} from \"@platforma-sdk/model\";\nimport type {\n CellStyle,\n ColDef,\n GridApi,\n ICellRendererParams,\n IServerSideDatasource,\n IServerSideGetRowsParams,\n ManagedGridOptions,\n} from \"ag-grid-enterprise\";\nimport type { PlAgHeaderComponentParams, PlAgHeaderComponentType } from \"../../PlAgColumnHeader\";\nimport { PlAgColumnHeader } from \"../../PlAgColumnHeader\";\nimport { PlAgTextAndButtonCell } from \"../../PlAgTextAndButtonCell\";\nimport type { PlAgDataTableV2Row, PlTableRowId } from \"../types\";\nimport { PTableHidden } from \"./common\";\nimport { defaultMainMenuItems } from \"./menu-items\";\nimport { makeRowNumberColDef, PlAgDataTableRowNumberColId } from \"./row-number\";\nimport { getColumnRenderingSpec } from \"./value-rendering\";\nimport type { Ref } from \"vue\";\nimport { isJsonEqual } from \"@milaboratories/helpers\";\nimport type { DeferredCircular } from \"./focus-row\";\nimport { isNil, uniq } from \"es-toolkit\";\n\nexport function isLabelColumn(column: PTableColumnSpec): column is PTableColumnSpecColumn {\n return column.type === \"column\" && isLabelColumnSpec(column.spec);\n}\n\n/** Convert columnar data from the driver to rows, used by ag-grid */\nfunction columns2rows(\n fields: number[],\n columns: PTableVector[],\n fieldResultMapping: number[],\n axesResultIndices: number[],\n): PlAgDataTableV2Row[] {\n const rowData: PlAgDataTableV2Row[] = [];\n for (let rowIdx = 0; rowIdx < columns[0].data.length; ++rowIdx) {\n const axesKey: PTableKey = axesResultIndices.map((ri) => pTableValue(columns[ri], rowIdx));\n const id = canonicalizeJson<PlTableRowId>(axesKey);\n const row = fields.reduce<PlAgDataTableV2Row>(\n (acc, field, colIdx) => {\n acc[field.toString() as `${number}`] =\n fieldResultMapping[colIdx] === -1\n ? PTableHidden\n : pTableValue(columns[fieldResultMapping[colIdx]], rowIdx);\n return acc;\n },\n { id, axesKey },\n );\n\n rowData.push(row);\n }\n return rowData;\n}\n\n/** Calculate GridOptions for selected p-table data source */\nexport async function calculateGridOptions({\n generation,\n pfDriver,\n sheets,\n fullTableHandle,\n visibleTableHandle,\n dataRenderedTracker,\n hiddenColIds,\n cellButtonAxisParams,\n}: {\n sheets: PlDataTableSheet[];\n pfDriver: PFrameDriver;\n generation: Ref<number>;\n fullTableHandle: PTableHandle;\n visibleTableHandle: PTableHandle;\n dataRenderedTracker: DeferredCircular<GridApi<PlAgDataTableV2Row>>;\n hiddenColIds?: PlTableColumnIdJson[];\n cellButtonAxisParams?: PlAgCellButtonAxisParams;\n}): Promise<\n Pick<ManagedGridOptions<PlAgDataTableV2Row>, \"columnDefs\" | \"serverSideDatasource\"> & {\n axesSpec: AxesSpec;\n }\n> {\n const stateGeneration = generation.value;\n\n // get specs of the full table\n const [tableSpecs, visibleTableSpecs] = await Promise.all([\n pfDriver.getSpec(fullTableHandle),\n pfDriver.getSpec(visibleTableHandle),\n ]);\n\n if (stateGeneration !== generation.value) throw new Error(\"table state generation changed\");\n\n // index mapping from full specs to visible subset (hidden columns → -1)\n const specsToVisibleSpecsMapping = buildSpecsToVisibleSpecsMapping(tableSpecs, visibleTableSpecs);\n\n const isPartitionedAxis = createPartitionedAxisPredicate(sheets);\n\n // label columns indexed by labeled axis (for axis→label replacement later)\n const getLabelColumnIndex = collectLabelColumnsByAxis(tableSpecs, isPartitionedAxis);\n\n // displayable column indices ordered: axes first, then columns by OrderPriority\n const fields = sortIndicesByTypeAndPriority(\n selectDisplayableIndices(tableSpecs, isPartitionedAxis, getLabelColumnIndex),\n tableSpecs,\n );\n\n // same as fields, but each axis replaced by its label column index when available\n const indices = replaceAxesWithLabelColumns(fields, tableSpecs, getLabelColumnIndex);\n\n // default hidden columns derived from Optional annotation when no saved state\n const resolvedHiddenColIds =\n hiddenColIds ?? computeDefaultHiddenColIds(fields, indices, tableSpecs);\n\n const columnDefs: ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden>[] = [\n makeRowNumberColDef(),\n ...fields.map((field, index) =>\n makeColDef(\n field,\n tableSpecs[field],\n tableSpecs[indices[index]],\n resolvedHiddenColIds,\n cellButtonAxisParams,\n ),\n ),\n ];\n\n // axes — taken directly from visible table (always present as part of join)\n const visibleAxes = collectVisibleAxes(visibleTableSpecs);\n\n // request indices: non-hidden display fields + visible axes for row selection keys.\n // Axes replaced by label columns request label data (display); original axis values\n // are fetched via visibleAxes (row keys).\n const { requestIndices, axesResultIndices, fieldResultMapping } = buildRequestIndices(\n indices,\n visibleAxes.map(([idx]) => idx),\n specsToVisibleSpecsMapping,\n );\n\n let rowCount = -1;\n let lastParams: IServerSideGetRowsParams | undefined = undefined;\n const serverSideDatasource: IServerSideDatasource<PlAgDataTableV2Row> = {\n getRows: async (params: IServerSideGetRowsParams) => {\n if (stateGeneration !== generation.value) return params.fail();\n try {\n if (rowCount === -1) {\n const ptShape = await pfDriver.getShape(visibleTableHandle);\n if (stateGeneration !== generation.value || params.api.isDestroyed())\n return params.fail();\n rowCount = ptShape.rows;\n }\n\n if (rowCount == 0) {\n params.success({ rowData: [], rowCount });\n // Warning: AgGrid cannot show two overlays at once,\n // so first hide loading overlay, then show no rows overlay\n params.api.setGridOption(\"loading\", false);\n params.api.showNoRowsOverlay();\n return;\n }\n\n // If sort has changed - show skeletons instead of data\n if (lastParams && !isJsonEqual(lastParams.request.sortModel, params.request.sortModel)) {\n return params.success({ rowData: [], rowCount });\n }\n lastParams = params;\n\n let length = 0;\n let rowData: PlAgDataTableV2Row[] = [];\n if (\n rowCount > 0 &&\n params.request.startRow !== undefined &&\n params.request.endRow !== undefined\n ) {\n length = Math.min(rowCount, params.request.endRow) - params.request.startRow;\n if (length > 0) {\n const data = await pfDriver.getData(visibleTableHandle, requestIndices, {\n offset: params.request.startRow,\n length,\n });\n if (stateGeneration !== generation.value || params.api.isDestroyed())\n return params.fail();\n rowData = columns2rows(fields, data, fieldResultMapping, axesResultIndices);\n }\n }\n\n params.success({ rowData, rowCount });\n params.api.autoSizeColumns(\n params.api\n .getAllDisplayedColumns()\n .filter((column) => column.getColId() !== PlAgDataTableRowNumberColId),\n );\n params.api.setGridOption(\"loading\", false);\n dataRenderedTracker.resolve(params.api);\n } catch (error: unknown) {\n if (stateGeneration !== generation.value || params.api.isDestroyed()) return params.fail();\n params.api.setGridOption(\"loading\", true);\n params.fail();\n console.trace(error);\n }\n },\n };\n\n return {\n axesSpec: visibleAxes.map(([, { spec }]) => spec),\n columnDefs,\n serverSideDatasource,\n };\n}\n\nexport type PlAgCellButtonAxisParams = {\n showCellButtonForAxisId?: AxisId;\n cellButtonInvokeRowsOnDoubleClick?: boolean;\n trigger: (key?: PTableKey) => void;\n};\n\n/**\n * Calculates column definition for a given p-table column\n */\nexport function makeColDef(\n iCol: number,\n spec: PTableColumnSpec,\n labeledSpec: PTableColumnSpec,\n hiddenColIds: PlTableColumnIdJson[] | undefined,\n cellButtonAxisParams?: PlAgCellButtonAxisParams,\n): ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden> {\n const colId = canonicalizeJson<PlTableColumnId>({\n source: spec,\n labeled: labeledSpec,\n });\n const valueType = spec.type === \"axis\" ? spec.spec.type : spec.spec.valueType;\n const columnRenderingSpec = getColumnRenderingSpec(spec);\n const cellStyle: CellStyle = {};\n if (columnRenderingSpec.fontFamily) {\n if (columnRenderingSpec.fontFamily === \"monospace\") {\n cellStyle.fontFamily = \"Spline Sans Mono\";\n cellStyle.fontWeight = 300;\n } else {\n cellStyle.fontFamily = columnRenderingSpec.fontFamily;\n }\n }\n const headerName =\n readAnnotation(labeledSpec.spec, Annotation.Label)?.trim() ??\n readAnnotation(spec.spec, Annotation.Label)?.trim() ??\n `Unlabeled ${spec.type} ${iCol}`;\n\n return {\n colId,\n mainMenuItems: defaultMainMenuItems,\n context: spec,\n field: `${iCol}`,\n headerName,\n lockPosition: spec.type === \"axis\",\n hide: hiddenColIds !== undefined && hiddenColIds.includes(colId),\n valueFormatter: columnRenderingSpec.valueFormatter,\n headerComponent: PlAgColumnHeader,\n cellRendererSelector: cellButtonAxisParams?.showCellButtonForAxisId\n ? (params: ICellRendererParams) => {\n if (spec.type !== \"axis\") return;\n\n const axisId = (params.colDef?.context as PTableColumnSpec)?.id as AxisId;\n if (isJsonEqual(axisId, cellButtonAxisParams.showCellButtonForAxisId)) {\n return {\n component: PlAgTextAndButtonCell,\n params: {\n invokeRowsOnDoubleClick: cellButtonAxisParams.cellButtonInvokeRowsOnDoubleClick,\n onClick: (params: ICellRendererParams<PlAgDataTableV2Row>) => {\n cellButtonAxisParams.trigger(params.data?.axesKey);\n },\n },\n };\n }\n }\n : undefined,\n cellStyle,\n headerComponentParams: {\n type: ((): PlAgHeaderComponentType => {\n switch (valueType) {\n case ValueType.Int:\n case ValueType.Long:\n case ValueType.Float:\n case ValueType.Double:\n return \"Number\";\n case ValueType.String:\n case ValueType.Bytes:\n return \"Text\";\n default:\n throw Error(`unsupported data type: ${valueType}`);\n }\n })(),\n tooltip:\n readAnnotation(spec.spec, Annotation.Description)?.trim() ??\n readAnnotation(labeledSpec.spec, Annotation.Description)?.trim(),\n info:\n readAnnotation(spec.spec, Annotation.Table.Info)?.trim() ??\n readAnnotation(labeledSpec.spec, Annotation.Table.Info)?.trim(),\n } satisfies PlAgHeaderComponentParams,\n cellDataType: (() => {\n switch (valueType) {\n case ValueType.Int:\n case ValueType.Long:\n case ValueType.Float:\n case ValueType.Double:\n return \"number\";\n case ValueType.String:\n case ValueType.Bytes:\n return \"text\";\n default:\n throw Error(`unsupported data type: ${valueType}`);\n }\n })(),\n };\n}\n\n/** Build index mapping from full tableSpecs to their position in visibleTableSpecs (missing → -1). */\nfunction buildSpecsToVisibleSpecsMapping(\n tableSpecs: PTableColumnSpec[],\n visibleTableSpecs: PTableColumnSpec[],\n): Map<number, number> {\n const specId = (spec: PTableColumnSpec) =>\n canonicalizeJson<PTableColumnId>(getPTableColumnId(spec));\n const visibleSpecsMap = new Map(\n visibleTableSpecs.entries().map(([i, spec]) => [specId(spec), i] as const),\n );\n return new Map(\n tableSpecs.entries().map(([i, spec]) => {\n const visibleSpecIdx = visibleSpecsMap.get(specId(spec));\n return [i, isNil(visibleSpecIdx) ? -1 : visibleSpecIdx];\n }),\n );\n}\n\n/** Predicate that returns true when an axis is one of the sheet partition axes. */\nfunction createPartitionedAxisPredicate(sheets: PlDataTableSheet[]): (axisId: AxisId) => boolean {\n const sheetAxesIds = sheets.map((sheet) => getAxisId(sheet.axis));\n return (axisId) => sheetAxesIds.some((id) => matchAxisId(id, axisId));\n}\n\n/**\n * Collect label columns (skipping partitioned axes and duplicates) and return a\n * lookup function that resolves labeled axisId → label column index (or -1).\n */\nfunction collectLabelColumnsByAxis(\n tableSpecs: PTableColumnSpec[],\n isPartitionedAxis: (axisId: AxisId) => boolean,\n): (axisId: AxisId) => number {\n const labelColumns: { axisId: AxisId; labelColumnIdx: number }[] = [];\n for (const [i, spec] of tableSpecs.entries()) {\n if (spec.type !== \"column\" || !isLabelColumnSpec(spec.spec)) continue;\n const labeledAxisId = getAxisId(spec.spec.axesSpec[0]);\n if (isPartitionedAxis(labeledAxisId)) continue;\n if (labelColumns.some((info) => matchAxisId(info.axisId, labeledAxisId))) {\n console.warn(`multiple label columns match axisId: ${JSON.stringify(labeledAxisId)}`);\n continue;\n }\n labelColumns.push({ axisId: labeledAxisId, labelColumnIdx: i });\n }\n return (axisId) =>\n labelColumns.find((info) => matchAxisId(info.axisId, axisId))?.labelColumnIdx ?? -1;\n}\n\n/** Indices of columns to display: drop partitioned axes, label/linker columns, hidden columns. */\nfunction selectDisplayableIndices(\n tableSpecs: PTableColumnSpec[],\n isPartitionedAxis: (axisId: AxisId) => boolean,\n getLabelColumnIndex: (axisId: AxisId) => number,\n): number[] {\n return tableSpecs\n .entries()\n .filter(([, spec]) => {\n switch (spec.type) {\n case \"axis\":\n return (\n // show axis if not hidden or if it has a label column\n (!isColumnHidden(spec.spec) ? true : getLabelColumnIndex(spec.id) > -1) &&\n !isPartitionedAxis(spec.id)\n );\n case \"column\":\n return (\n !isColumnHidden(spec.spec) &&\n // hide label columns (their labeled axes are shown instead)\n !isLabelColumnSpec(spec.spec) &&\n !isLinkerColumnSpec(spec.spec)\n );\n }\n })\n .map(([i]) => i)\n .toArray();\n}\n\n/** Sort: axes first, then columns by OrderPriority annotation (higher priority = further left). */\nfunction sortIndicesByTypeAndPriority(indices: number[], tableSpecs: PTableColumnSpec[]): number[] {\n const priorityOf = (i: number): number => {\n const spec = tableSpecs[i];\n return spec.type === \"column\"\n ? (readAnnotationJson(spec.spec, Annotation.Table.OrderPriority) ?? 0)\n : 0;\n };\n return [...indices].sort((a, b) => {\n if (tableSpecs[a].type !== tableSpecs[b].type) {\n return tableSpecs[a].type === \"axis\" ? -1 : 1;\n }\n return priorityOf(b) - priorityOf(a);\n });\n}\n\n/** For each axis entry substitute the index of its matching label column when one exists. */\nfunction replaceAxesWithLabelColumns(\n fields: number[],\n tableSpecs: PTableColumnSpec[],\n getLabelColumnIndex: (axisId: AxisId) => number,\n): number[] {\n return fields.map((i) => {\n const spec = tableSpecs[i];\n const labelIdx = spec.type === \"axis\" ? getLabelColumnIndex(spec.id) : -1;\n return labelIdx === -1 ? i : labelIdx;\n });\n}\n\n/** Default hidden col ids built from columns marked with the Optional annotation. */\nfunction computeDefaultHiddenColIds(\n fields: number[],\n indices: number[],\n tableSpecs: PTableColumnSpec[],\n): PlTableColumnIdJson[] {\n return fields.reduce<PlTableColumnIdJson[]>((acc, field, i) => {\n const spec = tableSpecs[field];\n if (spec.type !== \"column\" || !isColumnOptional(spec.spec)) return acc;\n const labeledSpec = tableSpecs[indices[i]];\n return [...acc, canonicalizeJson<PlTableColumnId>({ source: spec, labeled: labeledSpec })];\n }, []);\n}\n\n/** Extract axis indices and specs from the visible table (always present as part of join). */\nfunction collectVisibleAxes(\n visibleTableSpecs: PTableColumnSpec[],\n): [number, PTableColumnSpecAxis][] {\n return visibleTableSpecs\n .entries()\n .filter((entry): entry is [number, PTableColumnSpecAxis] => entry[1].type === \"axis\")\n .toArray();\n}\n\n/**\n * Compose request indices for the visible table:\n * non-hidden display fields first, then visible axes (deduplicated).\n * Returns fieldResultMapping (display field → position in requestIndices, -1 if not requested)\n * and axesResultIndices (visible axis → position in requestIndices).\n */\nfunction buildRequestIndices(\n indices: number[],\n visibleAxesIndices: number[],\n specsToVisibleSpecsMapping: Map<number, number>,\n): {\n requestIndices: number[];\n axesResultIndices: number[];\n fieldResultMapping: number[];\n} {\n const resolved = indices.map((displayField) => {\n const idx = specsToVisibleSpecsMapping.get(displayField);\n return isNil(idx) || idx === -1 ? null : idx;\n });\n const requestIndices = uniq([\n ...resolved.filter((v): v is number => v !== null),\n ...visibleAxesIndices,\n ]);\n const fieldResultMapping = resolved.map((v) => (v === null ? -1 : requestIndices.indexOf(v)));\n const axesResultIndices = visibleAxesIndices.map((vi) => requestIndices.indexOf(vi));\n\n return { requestIndices, axesResultIndices, fieldResultMapping };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"table-source-v2.js","names":[],"sources":["../../../../src/components/PlAgDataTable/sources/table-source-v2.ts"],"sourcesContent":["import type {\n AxesSpec,\n PTableColumnId,\n PTableColumnSpecAxis,\n PTableColumnSpecColumn,\n PTableHandle,\n PTableValue,\n} from \"@platforma-sdk/model\";\nimport {\n canonicalizeJson,\n getAxisId,\n pTableValue,\n type PFrameDriver,\n type PlDataTableSheet,\n type PTableVector,\n type AxisId,\n type PTableColumnSpec,\n type PTableKey,\n type PlTableColumnId,\n type PlTableColumnIdJson,\n isLabelColumn as isLabelColumnSpec,\n isLinkerColumn as isLinkerColumnSpec,\n isColumnHidden,\n isColumnOptional,\n matchAxisId,\n readAnnotation,\n readAnnotationJson,\n Annotation,\n ValueType,\n getPTableColumnId,\n} from \"@platforma-sdk/model\";\nimport type {\n CellStyle,\n ColDef,\n GridApi,\n ICellRendererParams,\n IServerSideDatasource,\n IServerSideGetRowsParams,\n ManagedGridOptions,\n} from \"ag-grid-enterprise\";\nimport type { PlAgHeaderComponentParams, PlAgHeaderComponentType } from \"../../PlAgColumnHeader\";\nimport { PlAgColumnHeader } from \"../../PlAgColumnHeader\";\nimport { PlAgTextAndButtonCell } from \"../../PlAgTextAndButtonCell\";\nimport type { PlAgDataTableV2Row, PlTableRowId } from \"../types\";\nimport { PTableHidden } from \"./common\";\nimport { defaultMainMenuItems } from \"./menu-items\";\nimport { makeRowNumberColDef, PlAgDataTableRowNumberColId } from \"./row-number\";\nimport { getColumnRenderingSpec } from \"./value-rendering\";\nimport type { Ref } from \"vue\";\nimport { isJsonEqual } from \"@milaboratories/helpers\";\nimport type { DeferredCircular } from \"./focus-row\";\nimport { isNil, uniq } from \"es-toolkit\";\n\nexport function isLabelColumn(column: PTableColumnSpec): column is PTableColumnSpecColumn {\n return column.type === \"column\" && isLabelColumnSpec(column.spec);\n}\n\n/** Convert columnar data from the driver to rows, used by ag-grid */\nfunction columns2rows(\n fields: number[],\n columns: PTableVector[],\n fieldResultMapping: number[],\n axesResultIndices: number[],\n): PlAgDataTableV2Row[] {\n const rowData: PlAgDataTableV2Row[] = [];\n for (let rowIdx = 0; rowIdx < columns[0].data.length; ++rowIdx) {\n const axesKey: PTableKey = axesResultIndices.map((ri) => pTableValue(columns[ri], rowIdx));\n const id = canonicalizeJson<PlTableRowId>(axesKey);\n const row = fields.reduce<PlAgDataTableV2Row>(\n (acc, field, colIdx) => {\n acc[field.toString() as `${number}`] =\n fieldResultMapping[colIdx] === -1\n ? PTableHidden\n : pTableValue(columns[fieldResultMapping[colIdx]], rowIdx);\n return acc;\n },\n { id, axesKey },\n );\n\n rowData.push(row);\n }\n return rowData;\n}\n\n/** Calculate GridOptions for selected p-table data source */\nexport async function calculateGridOptions({\n generation,\n pfDriver,\n sheets,\n fullTableHandle,\n visibleTableHandle,\n dataRenderedTracker,\n hiddenColIds,\n cellButtonAxisParams,\n}: {\n sheets: PlDataTableSheet[];\n pfDriver: PFrameDriver;\n generation: Ref<number>;\n fullTableHandle: PTableHandle;\n visibleTableHandle: PTableHandle;\n dataRenderedTracker: DeferredCircular<GridApi<PlAgDataTableV2Row>>;\n hiddenColIds?: PlTableColumnIdJson[];\n cellButtonAxisParams?: PlAgCellButtonAxisParams;\n}): Promise<\n Pick<ManagedGridOptions<PlAgDataTableV2Row>, \"columnDefs\" | \"serverSideDatasource\"> & {\n axesSpec: AxesSpec;\n }\n> {\n const stateGeneration = generation.value;\n\n // get specs of the full table\n const [tableSpecs, visibleTableSpecs] = await Promise.all([\n pfDriver.getSpec(fullTableHandle),\n pfDriver.getSpec(visibleTableHandle),\n ]);\n\n if (stateGeneration !== generation.value) throw new Error(\"table state generation changed\");\n\n // index mapping from full specs to visible subset (hidden columns → -1)\n const specsToVisibleSpecsMapping = buildSpecsToVisibleSpecsMapping(tableSpecs, visibleTableSpecs);\n\n const isPartitionedAxis = createPartitionedAxisPredicate(sheets);\n\n // label columns indexed by labeled axis (for axis→label replacement later)\n const getLabelColumnIndex = collectLabelColumnsByAxis(tableSpecs, isPartitionedAxis);\n\n // displayable column indices ordered: axes first, then columns by OrderPriority\n const fields = sortIndicesByTypeAndPriority(\n selectDisplayableIndices(tableSpecs, isPartitionedAxis, getLabelColumnIndex),\n tableSpecs,\n );\n\n // same as fields, but each axis replaced by its label column index when available\n const indices = replaceAxesWithLabelColumns(fields, tableSpecs, getLabelColumnIndex);\n\n // default hidden columns derived from Optional annotation when no saved state\n const resolvedHiddenColIds =\n hiddenColIds ?? computeDefaultHiddenColIds(fields, indices, tableSpecs);\n\n const columnDefs: ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden>[] = [\n makeRowNumberColDef(),\n ...fields.map((field, index) =>\n makeColDef(\n field,\n tableSpecs[field],\n tableSpecs[indices[index]],\n resolvedHiddenColIds,\n cellButtonAxisParams,\n ),\n ),\n ];\n\n // axes — taken directly from visible table (always present as part of join)\n const visibleAxes = collectVisibleAxes(visibleTableSpecs);\n\n // request indices: non-hidden display fields + visible axes for row selection keys.\n // Axes replaced by label columns request label data (display); original axis values\n // are fetched via visibleAxes (row keys).\n const { requestIndices, axesResultIndices, fieldResultMapping } = buildRequestIndices(\n indices,\n visibleAxes.map(([idx]) => idx),\n specsToVisibleSpecsMapping,\n );\n\n let rowCount = -1;\n let lastParams: IServerSideGetRowsParams | undefined = undefined;\n const serverSideDatasource: IServerSideDatasource<PlAgDataTableV2Row> = {\n getRows: async (params: IServerSideGetRowsParams) => {\n if (stateGeneration !== generation.value) return params.fail();\n try {\n if (rowCount === -1) {\n const ptShape = await pfDriver.getShape(visibleTableHandle);\n if (stateGeneration !== generation.value || params.api.isDestroyed())\n return params.fail();\n rowCount = ptShape.rows;\n }\n\n if (rowCount == 0) {\n params.success({ rowData: [], rowCount });\n // Warning: AgGrid cannot show two overlays at once,\n // so first hide loading overlay, then show no rows overlay\n params.api.setGridOption(\"loading\", false);\n params.api.showNoRowsOverlay();\n return;\n }\n\n // If sort has changed - show skeletons instead of data\n if (lastParams && !isJsonEqual(lastParams.request.sortModel, params.request.sortModel)) {\n return params.success({ rowData: [], rowCount });\n }\n lastParams = params;\n\n let length = 0;\n let rowData: PlAgDataTableV2Row[] = [];\n if (\n rowCount > 0 &&\n params.request.startRow !== undefined &&\n params.request.endRow !== undefined\n ) {\n length = Math.min(rowCount, params.request.endRow) - params.request.startRow;\n if (length > 0) {\n const data = await pfDriver.getData(visibleTableHandle, requestIndices, {\n offset: params.request.startRow,\n length,\n });\n if (stateGeneration !== generation.value || params.api.isDestroyed())\n return params.fail();\n rowData = columns2rows(fields, data, fieldResultMapping, axesResultIndices);\n }\n }\n\n params.success({ rowData, rowCount });\n params.api.autoSizeColumns(\n params.api\n .getAllDisplayedColumns()\n .filter((column) => column.getColId() !== PlAgDataTableRowNumberColId),\n );\n params.api.setGridOption(\"loading\", false);\n dataRenderedTracker.resolve(params.api);\n } catch (error: unknown) {\n if (stateGeneration !== generation.value || params.api.isDestroyed()) return params.fail();\n params.api.setGridOption(\"loading\", true);\n params.fail();\n console.trace(error);\n }\n },\n };\n\n return {\n axesSpec: visibleAxes.map(([, { spec }]) => spec),\n columnDefs,\n serverSideDatasource,\n };\n}\n\nexport type PlAgCellButtonAxisParams = {\n showCellButtonForAxisId?: AxisId;\n cellButtonInvokeRowsOnDoubleClick?: boolean;\n trigger: (key?: PTableKey) => void;\n};\n\n/**\n * Calculates column definition for a given p-table column\n */\nexport function makeColDef(\n iCol: number,\n spec: PTableColumnSpec,\n labeledSpec: PTableColumnSpec,\n hiddenColIds: PlTableColumnIdJson[] | undefined,\n cellButtonAxisParams?: PlAgCellButtonAxisParams,\n): ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden> {\n const colId = canonicalizeJson<PlTableColumnId>({\n source: spec,\n labeled: labeledSpec,\n });\n const valueType = spec.type === \"axis\" ? spec.spec.type : spec.spec.valueType;\n const columnRenderingSpec = getColumnRenderingSpec(spec);\n const cellStyle: CellStyle = {};\n if (columnRenderingSpec.fontFamily) {\n if (columnRenderingSpec.fontFamily === \"monospace\") {\n cellStyle.fontFamily = \"Spline Sans Mono\";\n cellStyle.fontWeight = 300;\n } else {\n cellStyle.fontFamily = columnRenderingSpec.fontFamily;\n }\n }\n const headerName =\n readAnnotation(labeledSpec.spec, Annotation.Label)?.trim() ??\n readAnnotation(spec.spec, Annotation.Label)?.trim() ??\n `Unlabeled ${spec.type} ${iCol}`;\n\n return {\n colId,\n mainMenuItems: defaultMainMenuItems,\n context: spec,\n field: `${iCol}`,\n headerName,\n lockPosition: spec.type === \"axis\",\n hide: hiddenColIds !== undefined && hiddenColIds.includes(colId),\n valueFormatter: columnRenderingSpec.valueFormatter,\n headerComponent: PlAgColumnHeader,\n cellRendererSelector: cellButtonAxisParams?.showCellButtonForAxisId\n ? (params: ICellRendererParams) => {\n if (spec.type !== \"axis\") return;\n\n const axisId = (params.colDef?.context as PTableColumnSpec)?.id as AxisId;\n if (isJsonEqual(axisId, cellButtonAxisParams.showCellButtonForAxisId)) {\n return {\n component: PlAgTextAndButtonCell,\n params: {\n invokeRowsOnDoubleClick: cellButtonAxisParams.cellButtonInvokeRowsOnDoubleClick,\n onClick: (params: ICellRendererParams<PlAgDataTableV2Row>) => {\n cellButtonAxisParams.trigger(params.data?.axesKey);\n },\n },\n };\n }\n }\n : undefined,\n cellStyle,\n headerComponentParams: {\n type: ((): PlAgHeaderComponentType => {\n switch (valueType) {\n case ValueType.Int:\n case ValueType.Long:\n case ValueType.Float:\n case ValueType.Double:\n return \"Number\";\n case ValueType.String:\n case ValueType.Bytes:\n return \"Text\";\n default:\n throw Error(`unsupported data type: ${valueType}`);\n }\n })(),\n tooltip:\n readAnnotation(spec.spec, Annotation.Description)?.trim() ??\n readAnnotation(labeledSpec.spec, Annotation.Description)?.trim(),\n // info:\n // readAnnotation(spec.spec, Annotation.Table.Info)?.trim() ??\n // readAnnotation(labeledSpec.spec, Annotation.Table.Info)?.trim(),\n } satisfies PlAgHeaderComponentParams,\n cellDataType: (() => {\n switch (valueType) {\n case ValueType.Int:\n case ValueType.Long:\n case ValueType.Float:\n case ValueType.Double:\n return \"number\";\n case ValueType.String:\n case ValueType.Bytes:\n return \"text\";\n default:\n throw Error(`unsupported data type: ${valueType}`);\n }\n })(),\n };\n}\n\n/** Build index mapping from full tableSpecs to their position in visibleTableSpecs (missing → -1). */\nfunction buildSpecsToVisibleSpecsMapping(\n tableSpecs: PTableColumnSpec[],\n visibleTableSpecs: PTableColumnSpec[],\n): Map<number, number> {\n const specId = (spec: PTableColumnSpec) =>\n canonicalizeJson<PTableColumnId>(getPTableColumnId(spec));\n const visibleSpecsMap = new Map(\n visibleTableSpecs.entries().map(([i, spec]) => [specId(spec), i] as const),\n );\n return new Map(\n tableSpecs.entries().map(([i, spec]) => {\n const visibleSpecIdx = visibleSpecsMap.get(specId(spec));\n return [i, isNil(visibleSpecIdx) ? -1 : visibleSpecIdx];\n }),\n );\n}\n\n/** Predicate that returns true when an axis is one of the sheet partition axes. */\nfunction createPartitionedAxisPredicate(sheets: PlDataTableSheet[]): (axisId: AxisId) => boolean {\n const sheetAxesIds = sheets.map((sheet) => getAxisId(sheet.axis));\n return (axisId) => sheetAxesIds.some((id) => matchAxisId(id, axisId));\n}\n\n/**\n * Collect label columns (skipping partitioned axes and duplicates) and return a\n * lookup function that resolves labeled axisId → label column index (or -1).\n */\nfunction collectLabelColumnsByAxis(\n tableSpecs: PTableColumnSpec[],\n isPartitionedAxis: (axisId: AxisId) => boolean,\n): (axisId: AxisId) => number {\n const labelColumns: { axisId: AxisId; labelColumnIdx: number }[] = [];\n for (const [i, spec] of tableSpecs.entries()) {\n if (spec.type !== \"column\" || !isLabelColumnSpec(spec.spec)) continue;\n const labeledAxisId = getAxisId(spec.spec.axesSpec[0]);\n if (isPartitionedAxis(labeledAxisId)) continue;\n if (labelColumns.some((info) => matchAxisId(info.axisId, labeledAxisId))) {\n console.warn(`multiple label columns match axisId: ${JSON.stringify(labeledAxisId)}`);\n continue;\n }\n labelColumns.push({ axisId: labeledAxisId, labelColumnIdx: i });\n }\n return (axisId) =>\n labelColumns.find((info) => matchAxisId(info.axisId, axisId))?.labelColumnIdx ?? -1;\n}\n\n/** Indices of columns to display: drop partitioned axes, label/linker columns, hidden columns. */\nfunction selectDisplayableIndices(\n tableSpecs: PTableColumnSpec[],\n isPartitionedAxis: (axisId: AxisId) => boolean,\n getLabelColumnIndex: (axisId: AxisId) => number,\n): number[] {\n return tableSpecs\n .entries()\n .filter(([, spec]) => {\n switch (spec.type) {\n case \"axis\":\n return (\n // show axis if not hidden or if it has a label column\n (!isColumnHidden(spec.spec) ? true : getLabelColumnIndex(spec.id) > -1) &&\n !isPartitionedAxis(spec.id)\n );\n case \"column\":\n return (\n !isColumnHidden(spec.spec) &&\n // hide label columns (their labeled axes are shown instead)\n !isLabelColumnSpec(spec.spec) &&\n !isLinkerColumnSpec(spec.spec)\n );\n }\n })\n .map(([i]) => i)\n .toArray();\n}\n\n/** Sort: axes first, then columns by OrderPriority annotation (higher priority = further left). */\nfunction sortIndicesByTypeAndPriority(indices: number[], tableSpecs: PTableColumnSpec[]): number[] {\n const priorityOf = (i: number): number => {\n const spec = tableSpecs[i];\n return spec.type === \"column\"\n ? (readAnnotationJson(spec.spec, Annotation.Table.OrderPriority) ?? 0)\n : 0;\n };\n return [...indices].sort((a, b) => {\n if (tableSpecs[a].type !== tableSpecs[b].type) {\n return tableSpecs[a].type === \"axis\" ? -1 : 1;\n }\n return priorityOf(b) - priorityOf(a);\n });\n}\n\n/** For each axis entry substitute the index of its matching label column when one exists. */\nfunction replaceAxesWithLabelColumns(\n fields: number[],\n tableSpecs: PTableColumnSpec[],\n getLabelColumnIndex: (axisId: AxisId) => number,\n): number[] {\n return fields.map((i) => {\n const spec = tableSpecs[i];\n const labelIdx = spec.type === \"axis\" ? getLabelColumnIndex(spec.id) : -1;\n return labelIdx === -1 ? i : labelIdx;\n });\n}\n\n/** Default hidden col ids built from columns marked with the Optional annotation. */\nfunction computeDefaultHiddenColIds(\n fields: number[],\n indices: number[],\n tableSpecs: PTableColumnSpec[],\n): PlTableColumnIdJson[] {\n return fields.reduce<PlTableColumnIdJson[]>((acc, field, i) => {\n const spec = tableSpecs[field];\n if (spec.type !== \"column\" || !isColumnOptional(spec.spec)) return acc;\n const labeledSpec = tableSpecs[indices[i]];\n return [...acc, canonicalizeJson<PlTableColumnId>({ source: spec, labeled: labeledSpec })];\n }, []);\n}\n\n/** Extract axis indices and specs from the visible table (always present as part of join). */\nfunction collectVisibleAxes(\n visibleTableSpecs: PTableColumnSpec[],\n): [number, PTableColumnSpecAxis][] {\n return visibleTableSpecs\n .entries()\n .filter((entry): entry is [number, PTableColumnSpecAxis] => entry[1].type === \"axis\")\n .toArray();\n}\n\n/**\n * Compose request indices for the visible table:\n * non-hidden display fields first, then visible axes (deduplicated).\n * Returns fieldResultMapping (display field → position in requestIndices, -1 if not requested)\n * and axesResultIndices (visible axis → position in requestIndices).\n */\nfunction buildRequestIndices(\n indices: number[],\n visibleAxesIndices: number[],\n specsToVisibleSpecsMapping: Map<number, number>,\n): {\n requestIndices: number[];\n axesResultIndices: number[];\n fieldResultMapping: number[];\n} {\n const resolved = indices.map((displayField) => {\n const idx = specsToVisibleSpecsMapping.get(displayField);\n return isNil(idx) || idx === -1 ? null : idx;\n });\n const requestIndices = uniq([\n ...resolved.filter((v): v is number => v !== null),\n ...visibleAxesIndices,\n ]);\n const fieldResultMapping = resolved.map((v) => (v === null ? -1 : requestIndices.indexOf(v)));\n const axesResultIndices = visibleAxesIndices.map((vi) => requestIndices.indexOf(vi));\n\n return { requestIndices, axesResultIndices, fieldResultMapping };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,QAUb,CARM,EAAA,SAAA,GAAA,EADR,EASE,GAAA;;IAPC,MAAM,EAAA;IACN,kBAAgB;IAChB,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,SAAS,EAAM;IACf,uBAAqB,EAAM;IAC3B,oBAAoB,EAAM;IAC1B,6BAA6B,EAAM"}
1
+ {"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,QAiBZ,CAfK,EAAA,SAAA,GAAA,EADR,EASE,GAAA;;IAPC,MAAM,EAAA;IACN,kBAAgB;IAChB,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,SAAS,EAAM;IACf,uBAAqB,EAAM;IAC3B,oBAAoB,EAAM;IAC1B,6BAA6B,EAAM"}
@@ -2,7 +2,7 @@ import e from "../../_virtual/_plugin-vue_export-helper.js";
2
2
  import t from "./PlDatasetSelector.vue2.js";
3
3
  import './PlDatasetSelector.style.css';/* empty css */
4
4
  //#region src/components/PlDatasetSelector/PlDatasetSelector.vue
5
- var n = /* @__PURE__ */ e(t, [["__scopeId", "data-v-95f2adf4"]]);
5
+ var n = /* @__PURE__ */ e(t, [["__scopeId", "data-v-cb8d3a14"]]);
6
6
  //#endregion
7
7
  export { n as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"PlDatasetSelector.js","names":[],"sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Select a dataset and (optionally) a filter column, emitting a {@link DatasetSelection}.\n *\n * Behaves like {@link PlDropdownRef} when none of the offered datasets carry\n * filter options. When the selected dataset has compatible filters, a second\n * dropdown appears with the filters plus a \"No filter\" entry.\n *\n * The emitted value bundles the user's pick (`primary`) with the auto-attached\n * `enrichments` payload from the matching `DatasetOption`. Enrichments are\n * opaque to the UI — block authors unbundle them inside their args resolver.\n */\nexport default {\n name: \"PlDatasetSelector\",\n};\n</script>\n\n<script lang=\"ts\" setup>\nimport type { DatasetOption, DatasetSelection, PlRef } from \"@platforma-sdk/model\";\nimport { createDatasetSelection, createPrimaryRef, plRefsEqual } from \"@platforma-sdk/model\";\nimport type { ListOption } from \"@milaboratories/uikit\";\nimport { PlDropdown, PlDropdownRef } from \"@milaboratories/uikit\";\nimport { computed } from \"vue\";\n\nconst slots = defineSlots<{\n tooltip?: () => unknown;\n}>();\n\nconst model = defineModel<DatasetSelection | undefined>();\n\nconst props = withDefaults(\n defineProps<{\n /** Available datasets, each optionally carrying compatible filter choices. */\n options?: Readonly<DatasetOption[]>;\n /** Label above the dataset dropdown. */\n label?: string;\n /** Helper text below the dataset dropdown (shown when there is no error). */\n helper?: string;\n /** Helper text shown while `options` is undefined (loading). */\n loadingOptionsHelper?: string;\n /** Error message displayed below the dataset dropdown. */\n error?: unknown;\n /** Placeholder when no dataset is selected. */\n placeholder?: string;\n /** Label above the filter dropdown. */\n filterLabel?: string;\n /** Placeholder for the filter dropdown. */\n filterPlaceholder?: string;\n /** Label of the \"no filter\" entry prepended to the filter options. */\n noFilterLabel?: string;\n /** Show a clear button on the dataset dropdown. */\n clearable?: boolean;\n /** Mark the dataset dropdown as required. */\n required?: boolean;\n /** Disable all interaction. */\n disabled?: boolean;\n }>(),\n {\n options: undefined,\n label: undefined,\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n filterLabel: \"\",\n filterPlaceholder: \"...\",\n noFilterLabel: \"No filter\",\n clearable: false,\n required: false,\n disabled: false,\n },\n);\n\nconst selectedDataset = computed<PlRef | undefined>(() => model.value?.primary.column);\n\nconst selectedFilter = computed<PlRef | undefined>(() => model.value?.primary.filter);\n\nconst currentDatasetOption = computed<DatasetOption | undefined>(() => {\n const dataset = selectedDataset.value;\n if (!dataset) return undefined;\n return props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));\n});\n\n// PlDropdownRef expects `Option[]`; project the primary out of each entry.\nconst primaryOptions = computed<readonly { ref: PlRef; label: string }[] | undefined>(() =>\n props.options?.map((o) => o.primary),\n);\n\nconst hasFilters = computed(() => (currentDatasetOption.value?.filters?.length ?? 0) > 0);\n\n/**\n * Filter dropdown options. The first entry (`null`) is the \"No filter\" choice —\n * null distinguishes it from `undefined` (dropdown clear button, disabled here).\n */\nconst filterOptions = computed<ListOption<PlRef | null>[]>(() => {\n const filters = currentDatasetOption.value?.filters;\n if (!filters) return [];\n return [\n { label: props.noFilterLabel, value: null } as ListOption<PlRef | null>,\n ...filters.map((f) => ({ label: f.label, value: f.ref }) as ListOption<PlRef | null>),\n ];\n});\n\nconst filterValue = computed<PlRef | null>(() => selectedFilter.value ?? null);\n\nfunction emitValue(dataset: PlRef | undefined, filter: PlRef | undefined) {\n if (dataset === undefined) {\n model.value = undefined;\n return;\n }\n // Resolve from `props.options` directly — `currentDatasetOption` may not\n // have recomputed yet when this runs synchronously inside a change handler.\n const option = props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));\n model.value = createDatasetSelection(createPrimaryRef(dataset, filter), option?.enrichments);\n}\n\nfunction onDatasetChange(dataset: PlRef | undefined) {\n emitValue(dataset, undefined);\n}\n\nfunction onFilterChange(value: PlRef | null | undefined) {\n const dataset = selectedDataset.value;\n if (!dataset) return;\n emitValue(dataset, value ?? undefined);\n}\n</script>\n\n<template>\n <div class=\"pl-dataset-selector\">\n <PlDropdownRef\n :model-value=\"selectedDataset\"\n :options=\"primaryOptions\"\n :label=\"label\"\n :helper=\"helper\"\n :loading-options-helper=\"loadingOptionsHelper\"\n :error=\"error\"\n :placeholder=\"placeholder\"\n :clearable=\"clearable\"\n :required=\"required\"\n :disabled=\"disabled\"\n @update:model-value=\"onDatasetChange\"\n >\n <template v-if=\"slots.tooltip\" #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlDropdownRef>\n <PlDropdown\n v-if=\"hasFilters\"\n :model-value=\"filterValue\"\n :options=\"filterOptions\"\n :label=\"filterLabel\"\n :placeholder=\"filterPlaceholder\"\n :disabled=\"disabled\"\n @update:model-value=\"onFilterChange\"\n />\n </div>\n</template>\n\n<style scoped>\n.pl-dataset-selector {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"PlDatasetSelector.js","names":[],"sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Select a dataset and (optionally) a filter column, emitting a {@link DatasetSelection}.\n *\n * The filter dropdown is always rendered and is clearable leaving it empty\n * means \"no filter\". When the selected dataset has no compatible filters, the\n * dropdown opens to an empty option list.\n *\n * The emitted value bundles the user's pick (`primary`) with the auto-attached\n * `enrichments` payload from the matching `DatasetOption`. Enrichments are\n * opaque to the UI — block authors unbundle them inside their args resolver.\n */\nexport default {\n name: \"PlDatasetSelector\",\n};\n</script>\n\n<script lang=\"ts\" setup>\nimport type { DatasetOption, DatasetSelection, PlRef } from \"@platforma-sdk/model\";\nimport { createDatasetSelection, createPrimaryRef, plRefsEqual } from \"@platforma-sdk/model\";\nimport type { ListOption } from \"@milaboratories/uikit\";\nimport { PlDropdown, PlDropdownRef } from \"@milaboratories/uikit\";\nimport { computed } from \"vue\";\n\nconst slots = defineSlots<{\n tooltip?: () => unknown;\n}>();\n\nconst model = defineModel<DatasetSelection | undefined>();\n\nconst props = withDefaults(\n defineProps<{\n /** Available datasets, each optionally carrying compatible filter choices. */\n options?: Readonly<DatasetOption[]>;\n /** Label above the dataset dropdown. */\n label?: string;\n /** Helper text below the dataset dropdown (shown when there is no error). */\n helper?: string;\n /** Helper text shown while `options` is undefined (loading). */\n loadingOptionsHelper?: string;\n /** Error message displayed below the dataset dropdown. */\n error?: unknown;\n /** Placeholder when no dataset is selected. */\n placeholder?: string;\n /** Label above the filter dropdown. */\n filterLabel?: string;\n /** Placeholder for the filter dropdown. */\n filterPlaceholder?: string;\n /** Show a clear button on the dataset dropdown. */\n clearable?: boolean;\n /** Mark the dataset dropdown as required. */\n required?: boolean;\n /** Disable all interaction. */\n disabled?: boolean;\n }>(),\n {\n options: undefined,\n label: undefined,\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n filterLabel: \"\",\n filterPlaceholder: \"...\",\n clearable: false,\n required: false,\n disabled: false,\n },\n);\n\nconst selectedDataset = computed<PlRef | undefined>(() => model.value?.primary.column);\n\nconst selectedFilter = computed<PlRef | undefined>(() => model.value?.primary.filter);\n\nconst currentDatasetOption = computed<DatasetOption | undefined>(() => {\n const dataset = selectedDataset.value;\n if (!dataset) return undefined;\n return props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));\n});\n\n// PlDropdownRef expects `Option[]`; project the primary out of each entry.\nconst primaryOptions = computed<readonly { ref: PlRef; label: string }[] | undefined>(() =>\n props.options?.map((o) => o.primary),\n);\n\nconst filterOptions = computed<ListOption<PlRef>[]>(\n () => currentDatasetOption.value?.filters?.map((f) => ({ label: f.label, value: f.ref })) ?? [],\n);\n\n// Resolve from `props.options` directly — `currentDatasetOption` may not have\n// recomputed yet when this runs synchronously inside a change handler.\nfunction findOption(dataset: PlRef): DatasetOption | undefined {\n return props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));\n}\n\nfunction onDatasetChange(dataset: PlRef | undefined) {\n if (dataset === undefined) {\n model.value = undefined;\n return;\n }\n model.value = createDatasetSelection(createPrimaryRef(dataset), findOption(dataset)?.enrichments);\n}\n\nfunction onFilterChange(filter: PlRef | undefined) {\n const dataset = selectedDataset.value;\n if (!dataset) return;\n model.value = createDatasetSelection(\n createPrimaryRef(dataset, filter),\n findOption(dataset)?.enrichments,\n );\n}\n</script>\n\n<template>\n <div class=\"pl-dataset-selector\">\n <PlDropdownRef\n :model-value=\"selectedDataset\"\n :options=\"primaryOptions\"\n :label=\"label\"\n :helper=\"helper\"\n :loading-options-helper=\"loadingOptionsHelper\"\n :error=\"error\"\n :placeholder=\"placeholder\"\n :clearable=\"clearable\"\n :required=\"required\"\n :disabled=\"disabled\"\n @update:model-value=\"onDatasetChange\"\n >\n <template v-if=\"slots.tooltip\" #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlDropdownRef>\n <PlDropdown\n :model-value=\"selectedFilter\"\n :options=\"filterOptions\"\n :label=\"filterLabel\"\n :placeholder=\"filterPlaceholder\"\n :disabled=\"disabled\"\n clearable\n @update:model-value=\"onFilterChange\"\n />\n </div>\n</template>\n\n<style scoped>\n.pl-dataset-selector {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- .pl-dataset-selector[data-v-95f2adf4]{flex-direction:column;gap:12px;display:flex}
1
+ .pl-dataset-selector[data-v-cb8d3a14]{flex-direction:column;gap:12px;display:flex}
@@ -2,9 +2,9 @@ import { DatasetOption, DatasetSelection } from '@platforma-sdk/model';
2
2
  /**
3
3
  * Select a dataset and (optionally) a filter column, emitting a {@link DatasetSelection}.
4
4
  *
5
- * Behaves like {@link PlDropdownRef} when none of the offered datasets carry
6
- * filter options. When the selected dataset has compatible filters, a second
7
- * dropdown appears with the filters plus a "No filter" entry.
5
+ * The filter dropdown is always rendered and is clearable leaving it empty
6
+ * means "no filter". When the selected dataset has no compatible filters, the
7
+ * dropdown opens to an empty option list.
8
8
  *
9
9
  * The emitted value bundles the user's pick (`primary`) with the auto-attached
10
10
  * `enrichments` payload from the matching `DatasetOption`. Enrichments are
@@ -29,8 +29,6 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
29
29
  filterLabel?: string;
30
30
  /** Placeholder for the filter dropdown. */
31
31
  filterPlaceholder?: string;
32
- /** Label of the "no filter" entry prepended to the filter options. */
33
- noFilterLabel?: string;
34
32
  /** Show a clear button on the dataset dropdown. */
35
33
  clearable?: boolean;
36
34
  /** Mark the dataset dropdown as required. */
@@ -58,8 +56,6 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
58
56
  filterLabel?: string;
59
57
  /** Placeholder for the filter dropdown. */
60
58
  filterPlaceholder?: string;
61
- /** Label of the "no filter" entry prepended to the filter options. */
62
- noFilterLabel?: string;
63
59
  /** Show a clear button on the dataset dropdown. */
64
60
  clearable?: boolean;
65
61
  /** Mark the dataset dropdown as required. */
@@ -80,7 +76,6 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
80
76
  disabled: boolean;
81
77
  filterLabel: string;
82
78
  filterPlaceholder: string;
83
- noFilterLabel: string;
84
79
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>, Readonly<{
85
80
  tooltip?: () => unknown;
86
81
  }> & {
@@ -1 +1 @@
1
- {"version":3,"file":"PlDatasetSelector.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"names":[],"mappings":"AAuKA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAS,MAAM,sBAAsB,CAAC;AAOnF;;;;;;;;;;GAUG;;iBA2HU,gBAAgB,GAAG,SAAS;;IAlHrC,8EAA8E;cACpE,QAAQ,CAAC,aAAa,EAAE,CAAC;IACnC,wCAAwC;YAChC,MAAM;IACd,6EAA6E;aACpE,MAAM;IACf,gEAAgE;2BACzC,MAAM;IAC7B,0DAA0D;YAClD,OAAO;IACf,+CAA+C;kBACjC,MAAM;IACpB,uCAAuC;kBACzB,MAAM;IACpB,2CAA2C;wBACvB,MAAM;IAC1B,sEAAsE;oBACtD,MAAM;IACtB,mDAAmD;gBACvC,OAAO;IACnB,6CAA6C;eAClC,OAAO;IAClB,+BAA+B;eACpB,OAAO;;;;iBA2FT,gBAAgB,GAAG,SAAS;;IAlHrC,8EAA8E;cACpE,QAAQ,CAAC,aAAa,EAAE,CAAC;IACnC,wCAAwC;YAChC,MAAM;IACd,6EAA6E;aACpE,MAAM;IACf,gEAAgE;2BACzC,MAAM;IAC7B,0DAA0D;YAClD,OAAO;IACf,+CAA+C;kBACjC,MAAM;IACpB,uCAAuC;kBACzB,MAAM;IACpB,2CAA2C;wBACvB,MAAM;IAC1B,sEAAsE;oBACtD,MAAM;IACtB,mDAAmD;gBACvC,OAAO;IACnB,6CAA6C;eAClC,OAAO;IAClB,+BAA+B;eACpB,OAAO;;;;;WApBV,MAAM;iBAQA,MAAM;aAVV,QAAQ,CAAC,aAAa,EAAE,CAAC;YAI1B,MAAM;0BAEQ,MAAM;eAYjB,OAAO;cAER,OAAO;cAEP,OAAO;iBAVJ,MAAM;uBAEA,MAAM;mBAEV,MAAM;;cAvBd,MAAM,OAAO;;cAAb,MAAM,OAAO;;AAFzB,wBAqQK;AAcL,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"PlDatasetSelector.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"names":[],"mappings":"AAyJA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAS,MAAM,sBAAsB,CAAC;AAOnF;;;;;;;;;;GAUG;;iBA4GU,gBAAgB,GAAG,SAAS;;IAnGrC,8EAA8E;cACpE,QAAQ,CAAC,aAAa,EAAE,CAAC;IACnC,wCAAwC;YAChC,MAAM;IACd,6EAA6E;aACpE,MAAM;IACf,gEAAgE;2BACzC,MAAM;IAC7B,0DAA0D;YAClD,OAAO;IACf,+CAA+C;kBACjC,MAAM;IACpB,uCAAuC;kBACzB,MAAM;IACpB,2CAA2C;wBACvB,MAAM;IAC1B,mDAAmD;gBACvC,OAAO;IACnB,6CAA6C;eAClC,OAAO;IAClB,+BAA+B;eACpB,OAAO;;;;iBA8ET,gBAAgB,GAAG,SAAS;;IAnGrC,8EAA8E;cACpE,QAAQ,CAAC,aAAa,EAAE,CAAC;IACnC,wCAAwC;YAChC,MAAM;IACd,6EAA6E;aACpE,MAAM;IACf,gEAAgE;2BACzC,MAAM;IAC7B,0DAA0D;YAClD,OAAO;IACf,+CAA+C;kBACjC,MAAM;IACpB,uCAAuC;kBACzB,MAAM;IACpB,2CAA2C;wBACvB,MAAM;IAC1B,mDAAmD;gBACvC,OAAO;IACnB,6CAA6C;eAClC,OAAO;IAClB,+BAA+B;eACpB,OAAO;;;;;WAlBV,MAAM;iBAQA,MAAM;aAVV,QAAQ,CAAC,aAAa,EAAE,CAAC;YAI1B,MAAM;0BAEQ,MAAM;eAUjB,OAAO;cAER,OAAO;cAEP,OAAO;iBARJ,MAAM;uBAEA,MAAM;;cArBlB,MAAM,OAAO;;cAAb,MAAM,OAAO;;AAFzB,wBAqPK;AAcL,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
@@ -1,10 +1,10 @@
1
- import { computed as e, createBlock as t, createCommentVNode as n, createElementBlock as r, createSlots as i, createVNode as a, defineComponent as o, mergeModels as s, openBlock as c, renderSlot as l, unref as u, useModel as d, useSlots as f, withCtx as p } from "vue";
2
- import { createDatasetSelection as m, createPrimaryRef as h, plRefsEqual as g } from "@platforma-sdk/model";
3
- import { PlDropdown as _, PlDropdownRef as v } from "@milaboratories/uikit";
1
+ import { computed as e, createElementBlock as t, createSlots as n, createVNode as r, defineComponent as i, mergeModels as a, openBlock as o, renderSlot as s, unref as c, useModel as l, useSlots as u, withCtx as d } from "vue";
2
+ import { createDatasetSelection as f, createPrimaryRef as p, plRefsEqual as m } from "@platforma-sdk/model";
3
+ import { PlDropdown as h, PlDropdownRef as g } from "@milaboratories/uikit";
4
4
  //#region src/components/PlDatasetSelector/PlDatasetSelector.vue?vue&type=script&setup=true&lang.ts
5
- var y = { class: "pl-dataset-selector" }, b = /* @__PURE__ */ o({
5
+ var _ = { class: "pl-dataset-selector" }, v = /* @__PURE__ */ i({
6
6
  name: "PlDatasetSelector",
7
- props: /* @__PURE__ */ s({
7
+ props: /* @__PURE__ */ a({
8
8
  options: { default: void 0 },
9
9
  label: { default: void 0 },
10
10
  helper: { default: void 0 },
@@ -13,7 +13,6 @@ var y = { class: "pl-dataset-selector" }, b = /* @__PURE__ */ o({
13
13
  placeholder: { default: "..." },
14
14
  filterLabel: { default: "" },
15
15
  filterPlaceholder: { default: "..." },
16
- noFilterLabel: { default: "No filter" },
17
16
  clearable: {
18
17
  type: Boolean,
19
18
  default: !1
@@ -31,50 +30,43 @@ var y = { class: "pl-dataset-selector" }, b = /* @__PURE__ */ o({
31
30
  modelModifiers: {}
32
31
  }),
33
32
  emits: ["update:modelValue"],
34
- setup(o) {
35
- let s = f(), b = d(o, "modelValue"), x = o, S = e(() => b.value?.primary.column), C = e(() => b.value?.primary.filter), w = e(() => {
36
- let e = S.value;
37
- if (e) return x.options?.find((t) => g(t.primary.ref, e, !0));
38
- }), T = e(() => x.options?.map((e) => e.primary)), E = e(() => (w.value?.filters?.length ?? 0) > 0), D = e(() => {
39
- let e = w.value?.filters;
40
- return e ? [{
41
- label: x.noFilterLabel,
42
- value: null
43
- }, ...e.map((e) => ({
44
- label: e.label,
45
- value: e.ref
46
- }))] : [];
47
- }), O = e(() => C.value ?? null);
48
- function k(e, t) {
33
+ setup(i) {
34
+ let a = u(), v = l(i, "modelValue"), y = i, b = e(() => v.value?.primary.column), x = e(() => v.value?.primary.filter), S = e(() => {
35
+ let e = b.value;
36
+ if (e) return y.options?.find((t) => m(t.primary.ref, e, !0));
37
+ }), C = e(() => y.options?.map((e) => e.primary)), w = e(() => S.value?.filters?.map((e) => ({
38
+ label: e.label,
39
+ value: e.ref
40
+ })) ?? []);
41
+ function T(e) {
42
+ return y.options?.find((t) => m(t.primary.ref, e, !0));
43
+ }
44
+ function E(e) {
49
45
  if (e === void 0) {
50
- b.value = void 0;
46
+ v.value = void 0;
51
47
  return;
52
48
  }
53
- let n = x.options?.find((t) => g(t.primary.ref, e, !0));
54
- b.value = m(h(e, t), n?.enrichments);
55
- }
56
- function A(e) {
57
- k(e, void 0);
49
+ v.value = f(p(e), T(e)?.enrichments);
58
50
  }
59
- function j(e) {
60
- let t = S.value;
61
- t && k(t, e ?? void 0);
51
+ function D(e) {
52
+ let t = b.value;
53
+ t && (v.value = f(p(t, e), T(t)?.enrichments));
62
54
  }
63
- return (e, d) => (c(), r("div", y, [a(u(v), {
64
- "model-value": S.value,
65
- options: T.value,
66
- label: o.label,
67
- helper: o.helper,
68
- "loading-options-helper": o.loadingOptionsHelper,
69
- error: o.error,
70
- placeholder: o.placeholder,
71
- clearable: o.clearable,
72
- required: o.required,
73
- disabled: o.disabled,
74
- "onUpdate:modelValue": A
75
- }, i({ _: 2 }, [s.tooltip ? {
55
+ return (e, l) => (o(), t("div", _, [r(c(g), {
56
+ "model-value": b.value,
57
+ options: C.value,
58
+ label: i.label,
59
+ helper: i.helper,
60
+ "loading-options-helper": i.loadingOptionsHelper,
61
+ error: i.error,
62
+ placeholder: i.placeholder,
63
+ clearable: i.clearable,
64
+ required: i.required,
65
+ disabled: i.disabled,
66
+ "onUpdate:modelValue": E
67
+ }, n({ _: 2 }, [a.tooltip ? {
76
68
  name: "tooltip",
77
- fn: p(() => [l(e.$slots, "tooltip", {}, void 0, !0)]),
69
+ fn: d(() => [s(e.$slots, "tooltip", {}, void 0, !0)]),
78
70
  key: "0"
79
71
  } : void 0]), 1032, [
80
72
  "model-value",
@@ -87,24 +79,24 @@ var y = { class: "pl-dataset-selector" }, b = /* @__PURE__ */ o({
87
79
  "clearable",
88
80
  "required",
89
81
  "disabled"
90
- ]), E.value ? (c(), t(u(_), {
91
- key: 0,
92
- "model-value": O.value,
93
- options: D.value,
94
- label: o.filterLabel,
95
- placeholder: o.filterPlaceholder,
96
- disabled: o.disabled,
97
- "onUpdate:modelValue": j
82
+ ]), r(c(h), {
83
+ "model-value": x.value,
84
+ options: w.value,
85
+ label: i.filterLabel,
86
+ placeholder: i.filterPlaceholder,
87
+ disabled: i.disabled,
88
+ clearable: "",
89
+ "onUpdate:modelValue": D
98
90
  }, null, 8, [
99
91
  "model-value",
100
92
  "options",
101
93
  "label",
102
94
  "placeholder",
103
95
  "disabled"
104
- ])) : n("", !0)]));
96
+ ])]));
105
97
  }
106
98
  });
107
99
  //#endregion
108
- export { b as default };
100
+ export { v as default };
109
101
 
110
102
  //# sourceMappingURL=PlDatasetSelector.vue2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlDatasetSelector.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Select a dataset and (optionally) a filter column, emitting a {@link DatasetSelection}.\n *\n * Behaves like {@link PlDropdownRef} when none of the offered datasets carry\n * filter options. When the selected dataset has compatible filters, a second\n * dropdown appears with the filters plus a \"No filter\" entry.\n *\n * The emitted value bundles the user's pick (`primary`) with the auto-attached\n * `enrichments` payload from the matching `DatasetOption`. Enrichments are\n * opaque to the UI — block authors unbundle them inside their args resolver.\n */\nexport default {\n name: \"PlDatasetSelector\",\n};\n</script>\n\n<script lang=\"ts\" setup>\nimport type { DatasetOption, DatasetSelection, PlRef } from \"@platforma-sdk/model\";\nimport { createDatasetSelection, createPrimaryRef, plRefsEqual } from \"@platforma-sdk/model\";\nimport type { ListOption } from \"@milaboratories/uikit\";\nimport { PlDropdown, PlDropdownRef } from \"@milaboratories/uikit\";\nimport { computed } from \"vue\";\n\nconst slots = defineSlots<{\n tooltip?: () => unknown;\n}>();\n\nconst model = defineModel<DatasetSelection | undefined>();\n\nconst props = withDefaults(\n defineProps<{\n /** Available datasets, each optionally carrying compatible filter choices. */\n options?: Readonly<DatasetOption[]>;\n /** Label above the dataset dropdown. */\n label?: string;\n /** Helper text below the dataset dropdown (shown when there is no error). */\n helper?: string;\n /** Helper text shown while `options` is undefined (loading). */\n loadingOptionsHelper?: string;\n /** Error message displayed below the dataset dropdown. */\n error?: unknown;\n /** Placeholder when no dataset is selected. */\n placeholder?: string;\n /** Label above the filter dropdown. */\n filterLabel?: string;\n /** Placeholder for the filter dropdown. */\n filterPlaceholder?: string;\n /** Label of the \"no filter\" entry prepended to the filter options. */\n noFilterLabel?: string;\n /** Show a clear button on the dataset dropdown. */\n clearable?: boolean;\n /** Mark the dataset dropdown as required. */\n required?: boolean;\n /** Disable all interaction. */\n disabled?: boolean;\n }>(),\n {\n options: undefined,\n label: undefined,\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n filterLabel: \"\",\n filterPlaceholder: \"...\",\n noFilterLabel: \"No filter\",\n clearable: false,\n required: false,\n disabled: false,\n },\n);\n\nconst selectedDataset = computed<PlRef | undefined>(() => model.value?.primary.column);\n\nconst selectedFilter = computed<PlRef | undefined>(() => model.value?.primary.filter);\n\nconst currentDatasetOption = computed<DatasetOption | undefined>(() => {\n const dataset = selectedDataset.value;\n if (!dataset) return undefined;\n return props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));\n});\n\n// PlDropdownRef expects `Option[]`; project the primary out of each entry.\nconst primaryOptions = computed<readonly { ref: PlRef; label: string }[] | undefined>(() =>\n props.options?.map((o) => o.primary),\n);\n\nconst hasFilters = computed(() => (currentDatasetOption.value?.filters?.length ?? 0) > 0);\n\n/**\n * Filter dropdown options. The first entry (`null`) is the \"No filter\" choice —\n * null distinguishes it from `undefined` (dropdown clear button, disabled here).\n */\nconst filterOptions = computed<ListOption<PlRef | null>[]>(() => {\n const filters = currentDatasetOption.value?.filters;\n if (!filters) return [];\n return [\n { label: props.noFilterLabel, value: null } as ListOption<PlRef | null>,\n ...filters.map((f) => ({ label: f.label, value: f.ref }) as ListOption<PlRef | null>),\n ];\n});\n\nconst filterValue = computed<PlRef | null>(() => selectedFilter.value ?? null);\n\nfunction emitValue(dataset: PlRef | undefined, filter: PlRef | undefined) {\n if (dataset === undefined) {\n model.value = undefined;\n return;\n }\n // Resolve from `props.options` directly — `currentDatasetOption` may not\n // have recomputed yet when this runs synchronously inside a change handler.\n const option = props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));\n model.value = createDatasetSelection(createPrimaryRef(dataset, filter), option?.enrichments);\n}\n\nfunction onDatasetChange(dataset: PlRef | undefined) {\n emitValue(dataset, undefined);\n}\n\nfunction onFilterChange(value: PlRef | null | undefined) {\n const dataset = selectedDataset.value;\n if (!dataset) return;\n emitValue(dataset, value ?? undefined);\n}\n</script>\n\n<template>\n <div class=\"pl-dataset-selector\">\n <PlDropdownRef\n :model-value=\"selectedDataset\"\n :options=\"primaryOptions\"\n :label=\"label\"\n :helper=\"helper\"\n :loading-options-helper=\"loadingOptionsHelper\"\n :error=\"error\"\n :placeholder=\"placeholder\"\n :clearable=\"clearable\"\n :required=\"required\"\n :disabled=\"disabled\"\n @update:model-value=\"onDatasetChange\"\n >\n <template v-if=\"slots.tooltip\" #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlDropdownRef>\n <PlDropdown\n v-if=\"hasFilters\"\n :model-value=\"filterValue\"\n :options=\"filterOptions\"\n :label=\"filterLabel\"\n :placeholder=\"filterPlaceholder\"\n :disabled=\"disabled\"\n @update:model-value=\"onFilterChange\"\n />\n </div>\n</template>\n\n<style scoped>\n.pl-dataset-selector {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n</style>\n"],"mappings":";;;;;CAaE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWR,IAAM,IAAQ,GAEV,EAEE,IAAQ,EAAyC,GAAA,aAAE,EAEnD,IAAQ,GA2CR,IAAkB,QAAkC,EAAM,OAAO,QAAQ,OAAO,EAEhF,IAAiB,QAAkC,EAAM,OAAO,QAAQ,OAAO,EAE/E,IAAuB,QAA0C;GACrE,IAAM,IAAU,EAAgB;AAC3B,SACL,QAAO,EAAM,SAAS,MAAM,MAAM,EAAY,EAAE,QAAQ,KAAK,GAAS,GAAK,CAAC;IAC5E,EAGI,IAAiB,QACrB,EAAM,SAAS,KAAK,MAAM,EAAE,QAAQ,CACrC,EAEK,IAAa,SAAgB,EAAqB,OAAO,SAAS,UAAU,KAAK,EAAE,EAMnF,IAAgB,QAA2C;GAC/D,IAAM,IAAU,EAAqB,OAAO;AAE5C,UADK,IACE,CACL;IAAE,OAAO,EAAM;IAAe,OAAO;IAAM,EAC3C,GAAG,EAAQ,KAAK,OAAO;IAAE,OAAO,EAAE;IAAO,OAAO,EAAE;IAAK,EAA8B,CACtF,GAJoB,EAAE;IAKvB,EAEI,IAAc,QAA6B,EAAe,SAAS,KAAK;EAE9E,SAAS,EAAU,GAA4B,GAA2B;AACxE,OAAI,MAAY,KAAA,GAAW;AACzB,MAAM,QAAQ,KAAA;AACd;;GAIF,IAAM,IAAS,EAAM,SAAS,MAAM,MAAM,EAAY,EAAE,QAAQ,KAAK,GAAS,GAAK,CAAC;AACpF,KAAM,QAAQ,EAAuB,EAAiB,GAAS,EAAO,EAAE,GAAQ,YAAY;;EAG9F,SAAS,EAAgB,GAA4B;AACnD,KAAU,GAAS,KAAA,EAAU;;EAG/B,SAAS,EAAe,GAAiC;GACvD,IAAM,IAAU,EAAgB;AAC3B,QACL,EAAU,GAAS,KAAS,KAAA,EAAU;;yBAKtC,EA2BM,OA3BN,GA2BM,CA1BJ,EAgBgB,EAAA,EAAA,EAAA;GAfb,eAAa,EAAA;GACb,SAAS,EAAA;GACT,OAAO,EAAA;GACP,QAAQ,EAAA;GACR,0BAAwB,EAAA;GACxB,OAAO,EAAA;GACP,aAAa,EAAA;GACb,WAAW,EAAA;GACX,UAAU,EAAA;GACV,UAAU,EAAA;GACV,uBAAoB;kBAEL,EAAM,UAAA;SAAU;eACP,CAAvB,EAAuB,EAAA,QAAA,WAAA,EAAA,EAAA,KAAA,GAAA,GAAA,CAAA,CAAA;;;;;;;;;;;;;MAInB,EAAA,SAAA,GAAA,EADR,EAQE,EAAA,EAAA,EAAA;;GANC,eAAa,EAAA;GACb,SAAS,EAAA;GACT,OAAO,EAAA;GACP,aAAa,EAAA;GACb,UAAU,EAAA;GACV,uBAAoB"}
1
+ {"version":3,"file":"PlDatasetSelector.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Select a dataset and (optionally) a filter column, emitting a {@link DatasetSelection}.\n *\n * The filter dropdown is always rendered and is clearable leaving it empty\n * means \"no filter\". When the selected dataset has no compatible filters, the\n * dropdown opens to an empty option list.\n *\n * The emitted value bundles the user's pick (`primary`) with the auto-attached\n * `enrichments` payload from the matching `DatasetOption`. Enrichments are\n * opaque to the UI — block authors unbundle them inside their args resolver.\n */\nexport default {\n name: \"PlDatasetSelector\",\n};\n</script>\n\n<script lang=\"ts\" setup>\nimport type { DatasetOption, DatasetSelection, PlRef } from \"@platforma-sdk/model\";\nimport { createDatasetSelection, createPrimaryRef, plRefsEqual } from \"@platforma-sdk/model\";\nimport type { ListOption } from \"@milaboratories/uikit\";\nimport { PlDropdown, PlDropdownRef } from \"@milaboratories/uikit\";\nimport { computed } from \"vue\";\n\nconst slots = defineSlots<{\n tooltip?: () => unknown;\n}>();\n\nconst model = defineModel<DatasetSelection | undefined>();\n\nconst props = withDefaults(\n defineProps<{\n /** Available datasets, each optionally carrying compatible filter choices. */\n options?: Readonly<DatasetOption[]>;\n /** Label above the dataset dropdown. */\n label?: string;\n /** Helper text below the dataset dropdown (shown when there is no error). */\n helper?: string;\n /** Helper text shown while `options` is undefined (loading). */\n loadingOptionsHelper?: string;\n /** Error message displayed below the dataset dropdown. */\n error?: unknown;\n /** Placeholder when no dataset is selected. */\n placeholder?: string;\n /** Label above the filter dropdown. */\n filterLabel?: string;\n /** Placeholder for the filter dropdown. */\n filterPlaceholder?: string;\n /** Show a clear button on the dataset dropdown. */\n clearable?: boolean;\n /** Mark the dataset dropdown as required. */\n required?: boolean;\n /** Disable all interaction. */\n disabled?: boolean;\n }>(),\n {\n options: undefined,\n label: undefined,\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n filterLabel: \"\",\n filterPlaceholder: \"...\",\n clearable: false,\n required: false,\n disabled: false,\n },\n);\n\nconst selectedDataset = computed<PlRef | undefined>(() => model.value?.primary.column);\n\nconst selectedFilter = computed<PlRef | undefined>(() => model.value?.primary.filter);\n\nconst currentDatasetOption = computed<DatasetOption | undefined>(() => {\n const dataset = selectedDataset.value;\n if (!dataset) return undefined;\n return props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));\n});\n\n// PlDropdownRef expects `Option[]`; project the primary out of each entry.\nconst primaryOptions = computed<readonly { ref: PlRef; label: string }[] | undefined>(() =>\n props.options?.map((o) => o.primary),\n);\n\nconst filterOptions = computed<ListOption<PlRef>[]>(\n () => currentDatasetOption.value?.filters?.map((f) => ({ label: f.label, value: f.ref })) ?? [],\n);\n\n// Resolve from `props.options` directly — `currentDatasetOption` may not have\n// recomputed yet when this runs synchronously inside a change handler.\nfunction findOption(dataset: PlRef): DatasetOption | undefined {\n return props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));\n}\n\nfunction onDatasetChange(dataset: PlRef | undefined) {\n if (dataset === undefined) {\n model.value = undefined;\n return;\n }\n model.value = createDatasetSelection(createPrimaryRef(dataset), findOption(dataset)?.enrichments);\n}\n\nfunction onFilterChange(filter: PlRef | undefined) {\n const dataset = selectedDataset.value;\n if (!dataset) return;\n model.value = createDatasetSelection(\n createPrimaryRef(dataset, filter),\n findOption(dataset)?.enrichments,\n );\n}\n</script>\n\n<template>\n <div class=\"pl-dataset-selector\">\n <PlDropdownRef\n :model-value=\"selectedDataset\"\n :options=\"primaryOptions\"\n :label=\"label\"\n :helper=\"helper\"\n :loading-options-helper=\"loadingOptionsHelper\"\n :error=\"error\"\n :placeholder=\"placeholder\"\n :clearable=\"clearable\"\n :required=\"required\"\n :disabled=\"disabled\"\n @update:model-value=\"onDatasetChange\"\n >\n <template v-if=\"slots.tooltip\" #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlDropdownRef>\n <PlDropdown\n :model-value=\"selectedFilter\"\n :options=\"filterOptions\"\n :label=\"filterLabel\"\n :placeholder=\"filterPlaceholder\"\n :disabled=\"disabled\"\n clearable\n @update:model-value=\"onFilterChange\"\n />\n </div>\n</template>\n\n<style scoped>\n.pl-dataset-selector {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n</style>\n"],"mappings":";;;;;CAaE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWR,IAAM,IAAQ,GAEV,EAEE,IAAQ,EAAyC,GAAA,aAAE,EAEnD,IAAQ,GAwCR,IAAkB,QAAkC,EAAM,OAAO,QAAQ,OAAO,EAEhF,IAAiB,QAAkC,EAAM,OAAO,QAAQ,OAAO,EAE/E,IAAuB,QAA0C;GACrE,IAAM,IAAU,EAAgB;AAC3B,SACL,QAAO,EAAM,SAAS,MAAM,MAAM,EAAY,EAAE,QAAQ,KAAK,GAAS,GAAK,CAAC;IAC5E,EAGI,IAAiB,QACrB,EAAM,SAAS,KAAK,MAAM,EAAE,QAAQ,CACrC,EAEK,IAAgB,QACd,EAAqB,OAAO,SAAS,KAAK,OAAO;GAAE,OAAO,EAAE;GAAO,OAAO,EAAE;GAAK,EAAE,IAAI,EAAE,CAChG;EAID,SAAS,EAAW,GAA2C;AAC7D,UAAO,EAAM,SAAS,MAAM,MAAM,EAAY,EAAE,QAAQ,KAAK,GAAS,GAAK,CAAC;;EAG9E,SAAS,EAAgB,GAA4B;AACnD,OAAI,MAAY,KAAA,GAAW;AACzB,MAAM,QAAQ,KAAA;AACd;;AAEF,KAAM,QAAQ,EAAuB,EAAiB,EAAQ,EAAE,EAAW,EAAQ,EAAE,YAAY;;EAGnG,SAAS,EAAe,GAA2B;GACjD,IAAM,IAAU,EAAgB;AAC3B,SACL,EAAM,QAAQ,EACZ,EAAiB,GAAS,EAAO,EACjC,EAAW,EAAQ,EAAE,YACtB;;yBAKD,EA2BM,OA3BN,GA2BM,CA1BJ,EAgBgB,EAAA,EAAA,EAAA;GAfb,eAAa,EAAA;GACb,SAAS,EAAA;GACT,OAAO,EAAA;GACP,QAAQ,EAAA;GACR,0BAAwB,EAAA;GACxB,OAAO,EAAA;GACP,aAAa,EAAA;GACb,WAAW,EAAA;GACX,UAAU,EAAA;GACV,UAAU,EAAA;GACV,uBAAoB;kBAEL,EAAM,UAAA;SAAU;eACP,CAAvB,EAAuB,EAAA,QAAA,WAAA,EAAA,EAAA,KAAA,GAAA,GAAA,CAAA,CAAA;;;;;;;;;;;;;MAG3B,EAQE,EAAA,EAAA,EAAA;GAPC,eAAa,EAAA;GACb,SAAS,EAAA;GACT,OAAO,EAAA;GACP,aAAa,EAAA;GACb,UAAU,EAAA;GACX,WAAA;GACC,uBAAoB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/ui-vue",
3
- "version": "1.72.0",
3
+ "version": "1.73.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -26,10 +26,10 @@
26
26
  "lru-cache": "^11.2.2",
27
27
  "vue": "^3.5.24",
28
28
  "zod": "~3.25.76",
29
+ "@milaboratories/pl-model-common": "1.39.0",
29
30
  "@milaboratories/pf-spec-driver": "1.3.9",
30
- "@milaboratories/uikit": "2.13.3",
31
- "@platforma-sdk/model": "1.72.0",
32
- "@milaboratories/pl-model-common": "1.39.0"
31
+ "@milaboratories/uikit": "2.13.4",
32
+ "@platforma-sdk/model": "1.73.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@faker-js/faker": "^9.2.0",
@@ -46,9 +46,9 @@
46
46
  "vite": "^8.0.6",
47
47
  "vitest": "^4.1.3",
48
48
  "@milaboratories/helpers": "1.14.1",
49
- "@milaboratories/ts-builder": "1.3.2",
49
+ "@milaboratories/build-configs": "2.0.0",
50
50
  "@milaboratories/ts-configs": "1.2.3",
51
- "@milaboratories/build-configs": "2.0.0"
51
+ "@milaboratories/ts-builder": "1.3.2"
52
52
  },
53
53
  "scripts": {
54
54
  "dev": "ts-builder serve --target browser-lib",
@@ -316,9 +316,9 @@ export function makeColDef(
316
316
  tooltip:
317
317
  readAnnotation(spec.spec, Annotation.Description)?.trim() ??
318
318
  readAnnotation(labeledSpec.spec, Annotation.Description)?.trim(),
319
- info:
320
- readAnnotation(spec.spec, Annotation.Table.Info)?.trim() ??
321
- readAnnotation(labeledSpec.spec, Annotation.Table.Info)?.trim(),
319
+ // info:
320
+ // readAnnotation(spec.spec, Annotation.Table.Info)?.trim() ??
321
+ // readAnnotation(labeledSpec.spec, Annotation.Table.Info)?.trim(),
322
322
  } satisfies PlAgHeaderComponentParams,
323
323
  cellDataType: (() => {
324
324
  switch (valueType) {
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * Select a dataset and (optionally) a filter column, emitting a {@link DatasetSelection}.
4
4
  *
5
- * Behaves like {@link PlDropdownRef} when none of the offered datasets carry
6
- * filter options. When the selected dataset has compatible filters, a second
7
- * dropdown appears with the filters plus a "No filter" entry.
5
+ * The filter dropdown is always rendered and is clearable leaving it empty
6
+ * means "no filter". When the selected dataset has no compatible filters, the
7
+ * dropdown opens to an empty option list.
8
8
  *
9
9
  * The emitted value bundles the user's pick (`primary`) with the auto-attached
10
10
  * `enrichments` payload from the matching `DatasetOption`. Enrichments are
@@ -46,8 +46,6 @@ const props = withDefaults(
46
46
  filterLabel?: string;
47
47
  /** Placeholder for the filter dropdown. */
48
48
  filterPlaceholder?: string;
49
- /** Label of the "no filter" entry prepended to the filter options. */
50
- noFilterLabel?: string;
51
49
  /** Show a clear button on the dataset dropdown. */
52
50
  clearable?: boolean;
53
51
  /** Mark the dataset dropdown as required. */
@@ -64,7 +62,6 @@ const props = withDefaults(
64
62
  placeholder: "...",
65
63
  filterLabel: "",
66
64
  filterPlaceholder: "...",
67
- noFilterLabel: "No filter",
68
65
  clearable: false,
69
66
  required: false,
70
67
  disabled: false,
@@ -86,42 +83,31 @@ const primaryOptions = computed<readonly { ref: PlRef; label: string }[] | undef
86
83
  props.options?.map((o) => o.primary),
87
84
  );
88
85
 
89
- const hasFilters = computed(() => (currentDatasetOption.value?.filters?.length ?? 0) > 0);
90
-
91
- /**
92
- * Filter dropdown options. The first entry (`null`) is the "No filter" choice —
93
- * null distinguishes it from `undefined` (dropdown clear button, disabled here).
94
- */
95
- const filterOptions = computed<ListOption<PlRef | null>[]>(() => {
96
- const filters = currentDatasetOption.value?.filters;
97
- if (!filters) return [];
98
- return [
99
- { label: props.noFilterLabel, value: null } as ListOption<PlRef | null>,
100
- ...filters.map((f) => ({ label: f.label, value: f.ref }) as ListOption<PlRef | null>),
101
- ];
102
- });
86
+ const filterOptions = computed<ListOption<PlRef>[]>(
87
+ () => currentDatasetOption.value?.filters?.map((f) => ({ label: f.label, value: f.ref })) ?? [],
88
+ );
103
89
 
104
- const filterValue = computed<PlRef | null>(() => selectedFilter.value ?? null);
90
+ // Resolve from `props.options` directly `currentDatasetOption` may not have
91
+ // recomputed yet when this runs synchronously inside a change handler.
92
+ function findOption(dataset: PlRef): DatasetOption | undefined {
93
+ return props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));
94
+ }
105
95
 
106
- function emitValue(dataset: PlRef | undefined, filter: PlRef | undefined) {
96
+ function onDatasetChange(dataset: PlRef | undefined) {
107
97
  if (dataset === undefined) {
108
98
  model.value = undefined;
109
99
  return;
110
100
  }
111
- // Resolve from `props.options` directly `currentDatasetOption` may not
112
- // have recomputed yet when this runs synchronously inside a change handler.
113
- const option = props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));
114
- model.value = createDatasetSelection(createPrimaryRef(dataset, filter), option?.enrichments);
115
- }
116
-
117
- function onDatasetChange(dataset: PlRef | undefined) {
118
- emitValue(dataset, undefined);
101
+ model.value = createDatasetSelection(createPrimaryRef(dataset), findOption(dataset)?.enrichments);
119
102
  }
120
103
 
121
- function onFilterChange(value: PlRef | null | undefined) {
104
+ function onFilterChange(filter: PlRef | undefined) {
122
105
  const dataset = selectedDataset.value;
123
106
  if (!dataset) return;
124
- emitValue(dataset, value ?? undefined);
107
+ model.value = createDatasetSelection(
108
+ createPrimaryRef(dataset, filter),
109
+ findOption(dataset)?.enrichments,
110
+ );
125
111
  }
126
112
  </script>
127
113
 
@@ -145,12 +131,12 @@ function onFilterChange(value: PlRef | null | undefined) {
145
131
  </template>
146
132
  </PlDropdownRef>
147
133
  <PlDropdown
148
- v-if="hasFilters"
149
- :model-value="filterValue"
134
+ :model-value="selectedFilter"
150
135
  :options="filterOptions"
151
136
  :label="filterLabel"
152
137
  :placeholder="filterPlaceholder"
153
138
  :disabled="disabled"
139
+ clearable
154
140
  @update:model-value="onFilterChange"
155
141
  />
156
142
  </div>
@@ -24,7 +24,7 @@ const optionsWithFilters: DatasetOption[] = [
24
24
  ],
25
25
  enrichments: enrichmentsA,
26
26
  },
27
- // Dataset B has no filters — filter dropdown must stay hidden.
27
+ // Dataset B has no filters — filter dropdown is rendered but with no options.
28
28
  { primary: { label: "Dataset B", ref: datasetB } },
29
29
  ];
30
30
 
@@ -51,7 +51,7 @@ async function pickOption(index: number) {
51
51
  }
52
52
 
53
53
  describe("PlDatasetSelector", () => {
54
- it("renders a single dropdown when no dataset has filters", async () => {
54
+ it("always renders both dataset and filter dropdowns", async () => {
55
55
  const wrapper = mount(PlDatasetSelector, {
56
56
  props: { modelValue: undefined, options: optionsNoFilters },
57
57
  attachTo: document.body,
@@ -60,12 +60,11 @@ describe("PlDatasetSelector", () => {
60
60
 
61
61
  const selector = wrapper.find(".pl-dataset-selector");
62
62
  expect(selector.exists()).toBe(true);
63
- // Only PlDropdownRef is rendered — no filter dropdown.
64
- expect(selector.element.children.length).toBe(1);
63
+ expect(selector.element.children.length).toBe(2);
65
64
  wrapper.unmount();
66
65
  });
67
66
 
68
- it("shows the filter dropdown when the selected dataset has filters", async () => {
67
+ it("filter dropdown is rendered when the selected dataset has filters", async () => {
69
68
  const wrapper = mount(PlDatasetSelector, {
70
69
  props: { modelValue: selection(datasetA), options: optionsWithFilters },
71
70
  attachTo: document.body,
@@ -76,14 +75,20 @@ describe("PlDatasetSelector", () => {
76
75
  wrapper.unmount();
77
76
  });
78
77
 
79
- it("hides the filter dropdown when the selected dataset has no filters", async () => {
78
+ it("filter dropdown is still rendered (with no options) when the selected dataset has no filters", async () => {
80
79
  const wrapper = mount(PlDatasetSelector, {
81
80
  props: { modelValue: selection(datasetB), options: optionsWithFilters },
82
81
  attachTo: document.body,
83
82
  });
84
83
  await flushPromises();
85
84
 
86
- expect(wrapper.find(".pl-dataset-selector").element.children.length).toBe(1);
85
+ expect(wrapper.find(".pl-dataset-selector").element.children.length).toBe(2);
86
+
87
+ // Opening the filter dropdown shows no options.
88
+ const inputs = wrapper.findAll("input");
89
+ expect(inputs.length).toBe(2);
90
+ await inputs[1].trigger("focus");
91
+ expect(document.body.querySelectorAll(".dropdown-list-item").length).toBe(0);
87
92
  wrapper.unmount();
88
93
  });
89
94
 
@@ -129,8 +134,8 @@ describe("PlDatasetSelector", () => {
129
134
  const inputs = wrapper.findAll("input");
130
135
  expect(inputs.length).toBe(2);
131
136
  await inputs[1].trigger("focus");
132
- // Options: [No filter, Top 1000, High quality]. Pick "Top 1000".
133
- await pickOption(1);
137
+ // Options: [Top 1000, High quality]. Pick "Top 1000".
138
+ await pickOption(0);
134
139
 
135
140
  const emitted = wrapper.emitted("update:modelValue");
136
141
  expect(emitted).toBeDefined();
@@ -143,7 +148,7 @@ describe("PlDatasetSelector", () => {
143
148
  wrapper.unmount();
144
149
  });
145
150
 
146
- it("emits DatasetSelection with no filter key when 'No filter' is picked", async () => {
151
+ it("emits DatasetSelection with no filter key when the filter dropdown is cleared", async () => {
147
152
  const wrapper = mount(PlDatasetSelector, {
148
153
  props: {
149
154
  modelValue: selection(datasetA, filterA1, enrichmentsA),
@@ -155,9 +160,12 @@ describe("PlDatasetSelector", () => {
155
160
  });
156
161
  await flushPromises();
157
162
 
158
- const inputs = wrapper.findAll("input");
159
- await inputs[1].trigger("focus");
160
- await pickOption(0); // "No filter"
163
+ // The filter dropdown is the second .clear button (the first belongs to
164
+ // the dataset dropdown, but it's only present when the dataset selector
165
+ // itself is clearable; here only the filter is clearable by default).
166
+ const clearBtns = wrapper.findAll(".clear");
167
+ expect(clearBtns.length).toBeGreaterThan(0);
168
+ await clearBtns[clearBtns.length - 1].trigger("click");
161
169
 
162
170
  const emitted = wrapper.emitted("update:modelValue");
163
171
  expect(emitted).toBeDefined();
@@ -168,14 +176,18 @@ describe("PlDatasetSelector", () => {
168
176
  wrapper.unmount();
169
177
  });
170
178
 
171
- it("hides filter dropdown when dataset has filters: [] (empty array)", async () => {
179
+ it("filter dropdown is still rendered (with no options) when dataset has filters: [] (empty array)", async () => {
172
180
  const wrapper = mount(PlDatasetSelector, {
173
181
  props: { modelValue: selection(datasetC), options: optionsWithEmptyFilters },
174
182
  attachTo: document.body,
175
183
  });
176
184
  await flushPromises();
177
185
 
178
- expect(wrapper.find(".pl-dataset-selector").element.children.length).toBe(1);
186
+ expect(wrapper.find(".pl-dataset-selector").element.children.length).toBe(2);
187
+
188
+ const inputs = wrapper.findAll("input");
189
+ await inputs[1].trigger("focus");
190
+ expect(document.body.querySelectorAll(".dropdown-list-item").length).toBe(0);
179
191
  wrapper.unmount();
180
192
  });
181
193
 
@@ -197,8 +209,7 @@ describe("PlDatasetSelector", () => {
197
209
  expect(inputs.length).toBe(2);
198
210
  await inputs[1].trigger("focus");
199
211
  const items = document.body.querySelectorAll(".dropdown-list-item");
200
- expect(items.length).toBe(3); // No filter, Top 1000, High quality
201
- expect(items[0].textContent).toContain("No filter");
212
+ expect(items.length).toBe(2); // Top 1000, High quality — no synthetic "No filter"
202
213
  wrapper.unmount();
203
214
  });
204
215
 
@@ -242,9 +253,10 @@ describe("PlDatasetSelector", () => {
242
253
  });
243
254
  await flushPromises();
244
255
 
245
- const clearBtn = wrapper.find(".clear");
246
- expect(clearBtn.exists()).toBe(true);
247
- await clearBtn.trigger("click");
256
+ // First .clear button is on the dataset dropdown (clearable: true).
257
+ const clearBtns = wrapper.findAll(".clear");
258
+ expect(clearBtns.length).toBeGreaterThan(0);
259
+ await clearBtns[0].trigger("click");
248
260
 
249
261
  const emitted = wrapper.emitted("update:modelValue");
250
262
  expect(emitted).toBeDefined();