@platforma-sdk/ui-vue 1.75.8 → 1.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.75.8 build /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.76.0 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...
@@ -12,11 +12,11 @@ Building browser-lib project...
12
12
  4 export function useGridColumns(props: { api: GridApi }) {
13
13
     ~~~~~~~~~~~~~~
14
14
 
15
- 
15
+ 
16
16
  rendering chunks...
17
17
 
18
18
  [vite:dts] Start generate declaration files...
19
- [vite:dts] Declaration files built in 5276ms.
19
+ [vite:dts] Declaration files built in 5828ms.
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,6 @@ 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_cb8d3a14_lang.css 0.08 kB │ gzip: 0.09 kB
28
27
  dist/components/PlAgDataTable/PlAgDataTableV2.vue?vue&type=style&index=0&lang.css 0.09 kB │ gzip: 0.10 kB
29
28
  dist/components/PlAnnotations/components/FilterSidebar.vue?vue&type=style&index=0&lang.css 0.11 kB │ gzip: 0.09 kB
30
29
  dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue_vue_type_style_index_0_lang.css 0.16 kB │ gzip: 0.13 kB
@@ -90,6 +89,7 @@ dist/components/PlAgCellProgress/PlAgCellProgress.js
90
89
  dist/components/PlAgColumnHeader/PlAgColumnHeader.js 0.23 kB │ gzip: 0.17 kB │ map: 3.22 kB
91
90
  dist/plugins/Monetization/MonetizationSidebar.js 0.23 kB │ gzip: 0.17 kB │ map: 3.72 kB
92
91
  dist/components/PlAgDataTable/PlAgOverlayLoading.js 0.23 kB │ gzip: 0.17 kB │ map: 1.74 kB
92
+ dist/components/PlDatasetSelector/PlDatasetSelector.js 0.23 kB │ gzip: 0.16 kB │ map: 4.56 kB
93
93
  dist/components/PlTableFastSearch/PlTableFastSearch.js 0.23 kB │ gzip: 0.17 kB │ map: 1.37 kB
94
94
  dist/components/PlAgDataTable/PlAgDataTableSheets.vue_vue_type_style_index_0_lang.module.js 0.23 kB │ gzip: 0.19 kB │ map: 0.42 kB
95
95
  dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.js 0.24 kB │ gzip: 0.17 kB │ map: 1.78 kB
@@ -146,7 +146,6 @@ dist/objectHash.js
146
146
  dist/composition/AgGrid/index.js 0.46 kB │ gzip: 0.32 kB │ map: 0.79 kB
147
147
  dist/defineStore.js 0.49 kB │ gzip: 0.32 kB │ map: 1.20 kB
148
148
  dist/internal/utils.js 0.50 kB │ gzip: 0.29 kB │ map: 1.08 kB
149
- dist/components/PlDatasetSelector/PlDatasetSelector.js 0.51 kB │ gzip: 0.29 kB │ map: 1.10 kB
150
149
  dist/components/LoaderPage.js 0.52 kB │ gzip: 0.35 kB │ map: 0.48 kB
151
150
  dist/components/PlAdvancedFilter/PlAdvancedFilter.vue_vue_type_style_index_0_lang.module.js 0.54 kB │ gzip: 0.29 kB │ map: 0.72 kB
152
151
  dist/plugins/Monetization/useButtonTarget.js 0.54 kB │ gzip: 0.35 kB │ map: 1.10 kB
@@ -201,9 +200,9 @@ dist/plugins/Monetization/UserCabinetCard.vue_vue_type_script_setup_true_lang.js
201
200
  dist/components/BlockLayout.vue_vue_type_script_setup_true_lang.js 2.18 kB │ gzip: 1.03 kB │ map: 5.92 kB
202
201
  dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue_vue_type_script_setup_true_lang.js 2.40 kB │ gzip: 1.12 kB │ map: 6.67 kB
203
202
  dist/components/PlAgDataTable/PlAgDataTableSheets.vue_vue_type_script_setup_true_lang.js 2.45 kB │ gzip: 1.17 kB │ map: 5.01 kB
203
+ dist/components/PlDatasetSelector/PlDatasetSelector.vue_vue_type_script_setup_true_lang.js 2.50 kB │ gzip: 1.04 kB │ map: 5.69 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
207
206
  dist/components/PlAgDataTable/compositions/useGrid.js 2.91 kB │ gzip: 1.29 kB │ map: 6.51 kB
208
207
  dist/components/PlAgColumnHeader/PlAgColumnHeader.vue_vue_type_script_setup_true_lang.js 2.93 kB │ gzip: 1.26 kB │ map: 7.97 kB
209
208
  dist/components/PlAgDataTable/sources/row-number.js 2.99 kB │ gzip: 1.31 kB │ map: 7.42 kB
@@ -228,12 +227,12 @@ dist/components/PlAdvancedFilter/FilterEditor.vue_vue_type_script_setup_true_lan
228
227
  dist/components/PlAgDataTable/PlAgDataTableV2.vue_vue_type_script_setup_true_lang.js 12.31 kB │ gzip: 3.90 kB │ map: 29.22 kB
229
228
 
230
229
  [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugins. Here is a breakdown:
231
- - sourcemaps (32%)
230
+ - sourcemaps (35%)
232
231
  - vite:dts (23%)
233
232
  - vite:vue (12%)
234
- - vite:css-post (11%)
235
- - vite:css (7%)
233
+ - vite:css-post (10%)
234
+ - vite:css (9%)
236
235
  See https://rolldown.rs/options/checks#plugintimings for more details.
237
236
  
238
- ✓ built in 6.32s
237
+ ✓ built in 6.96s
239
238
  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.75.8 formatter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.76.0 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 2296ms on 137 files using 8 threads.
11
+ Finished in 1081ms 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.75.8 linter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.76.0 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 30ms 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.75.8 types:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.76.0 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,19 @@
1
1
  # @platforma-sdk/ui-vue
2
2
 
3
+ ## 1.76.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9310b53: `PlDatasetSelector` now renders datasets and their filters in a single dropdown — each dataset row is followed by its filter rows, with the parent dataset label shown as the row description. Removed the `filterLabel` and `filterPlaceholder` props (no longer applicable).
8
+
9
+ ## 1.75.10
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [b631ce0]
14
+ - @platforma-sdk/model@1.75.10
15
+ - @milaboratories/uikit@2.14.7
16
+
3
17
  ## 1.75.8
4
18
 
5
19
  ### Patch Changes
@@ -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,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"}
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,9 +1,7 @@
1
- import e from "../../_virtual/_plugin-vue_export-helper.js";
2
- import t from "./PlDatasetSelector.vue2.js";
3
- import './PlDatasetSelector.style.css';/* empty css */
1
+ import e from "./PlDatasetSelector.vue2.js";
4
2
  //#region src/components/PlDatasetSelector/PlDatasetSelector.vue
5
- var n = /* @__PURE__ */ e(t, [["__scopeId", "data-v-cb8d3a14"]]);
3
+ var t = e;
6
4
  //#endregion
7
- export { n as default };
5
+ export { t as default };
8
6
 
9
7
  //# sourceMappingURL=PlDatasetSelector.js.map
@@ -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 * The filter dropdown is always rendered and is clearableleaving 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
+ {"version":3,"file":"PlDatasetSelector.js","names":[],"sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Select a dataset or one of its filters in a single dropdown, emitting a\n * {@link DatasetSelection}.\n *\n * Each `DatasetOption` contributes one row for its primary plus one row per\n * filter filters are listed directly underneath their parent dataset and\n * carry the parent's primary label as the row description. Filter labels are\n * derived by `buildDatasetOptions` from each filter column's latest\n * `pl7.app/trace` step (the producing block's self-description).\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 } 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 dropdown. */\n label?: string;\n /** Helper text below the 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 dropdown. */\n error?: unknown;\n /** Placeholder when nothing is selected. */\n placeholder?: string;\n /** Show a clear button. */\n clearable?: boolean;\n /** Mark the dropdown as required. */\n required?: boolean;\n /** Disable interaction. */\n disabled?: boolean;\n }>(),\n {\n options: undefined,\n label: undefined,\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n clearable: false,\n required: false,\n disabled: false,\n },\n);\n\ntype Selection = { primary: PlRef; filter?: PlRef };\n\nconst selectionValue = computed<Selection | undefined>(() => {\n const primary = model.value?.primary;\n if (primary === undefined) return undefined;\n return primary.filter === undefined\n ? { primary: primary.column }\n : { primary: primary.column, filter: primary.filter };\n});\n\n// `deepEqual` (used by PlDropdown for matching) treats `{a, b: undefined}` and\n// `{a}` as different shapes, so the option list and the selection value must\n// agree on filter-key presence.\nconst dropdownOptions = computed<ListOption<Selection>[] | undefined>(() => {\n if (props.options === undefined) return undefined;\n const out: ListOption<Selection>[] = [];\n for (const o of props.options) {\n out.push({ label: o.primary.label, value: { primary: o.primary.ref } });\n for (const filter of o.filters ?? []) {\n out.push({\n label: filter.label,\n description: o.primary.label,\n value: { primary: o.primary.ref, filter: filter.ref },\n });\n }\n }\n return out;\n});\n\nfunction findOption(primary: PlRef): DatasetOption | undefined {\n return props.options?.find((o) => plRefsEqual(o.primary.ref, primary, true));\n}\n\nfunction onChange(selection: Selection | undefined) {\n if (selection === undefined) {\n model.value = undefined;\n return;\n }\n model.value = createDatasetSelection(\n createPrimaryRef(selection.primary, selection.filter),\n findOption(selection.primary)?.enrichments,\n );\n}\n</script>\n\n<template>\n <PlDropdown\n :model-value=\"selectionValue\"\n :options=\"dropdownOptions\"\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=\"onChange\"\n >\n <template v-if=\"slots.tooltip\" #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlDropdown>\n</template>\n"],"mappings":""}
@@ -1,10 +1,13 @@
1
1
  import { DatasetOption, DatasetSelection } from '@platforma-sdk/model';
2
2
  /**
3
- * Select a dataset and (optionally) a filter column, emitting a {@link DatasetSelection}.
3
+ * Select a dataset or one of its filters in a single dropdown, emitting a
4
+ * {@link DatasetSelection}.
4
5
  *
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.
6
+ * Each `DatasetOption` contributes one row for its primary plus one row per
7
+ * filter filters are listed directly underneath their parent dataset and
8
+ * carry the parent's primary label as the row description. Filter labels are
9
+ * derived by `buildDatasetOptions` from each filter column's latest
10
+ * `pl7.app/trace` step (the producing block's self-description).
8
11
  *
9
12
  * The emitted value bundles the user's pick (`primary`) with the auto-attached
10
13
  * `enrichments` payload from the matching `DatasetOption`. Enrichments are
@@ -15,25 +18,21 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
15
18
  } & {
16
19
  /** Available datasets, each optionally carrying compatible filter choices. */
17
20
  options?: Readonly<DatasetOption[]>;
18
- /** Label above the dataset dropdown. */
21
+ /** Label above the dropdown. */
19
22
  label?: string;
20
- /** Helper text below the dataset dropdown (shown when there is no error). */
23
+ /** Helper text below the dropdown (shown when there is no error). */
21
24
  helper?: string;
22
25
  /** Helper text shown while `options` is undefined (loading). */
23
26
  loadingOptionsHelper?: string;
24
- /** Error message displayed below the dataset dropdown. */
27
+ /** Error message displayed below the dropdown. */
25
28
  error?: unknown;
26
- /** Placeholder when no dataset is selected. */
29
+ /** Placeholder when nothing is selected. */
27
30
  placeholder?: string;
28
- /** Label above the filter dropdown. */
29
- filterLabel?: string;
30
- /** Placeholder for the filter dropdown. */
31
- filterPlaceholder?: string;
32
- /** Show a clear button on the dataset dropdown. */
31
+ /** Show a clear button. */
33
32
  clearable?: boolean;
34
- /** Mark the dataset dropdown as required. */
33
+ /** Mark the dropdown as required. */
35
34
  required?: boolean;
36
- /** Disable all interaction. */
35
+ /** Disable interaction. */
37
36
  disabled?: boolean;
38
37
  }, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
39
38
  "update:modelValue": (value: DatasetSelection | undefined) => any;
@@ -42,25 +41,21 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
42
41
  } & {
43
42
  /** Available datasets, each optionally carrying compatible filter choices. */
44
43
  options?: Readonly<DatasetOption[]>;
45
- /** Label above the dataset dropdown. */
44
+ /** Label above the dropdown. */
46
45
  label?: string;
47
- /** Helper text below the dataset dropdown (shown when there is no error). */
46
+ /** Helper text below the dropdown (shown when there is no error). */
48
47
  helper?: string;
49
48
  /** Helper text shown while `options` is undefined (loading). */
50
49
  loadingOptionsHelper?: string;
51
- /** Error message displayed below the dataset dropdown. */
50
+ /** Error message displayed below the dropdown. */
52
51
  error?: unknown;
53
- /** Placeholder when no dataset is selected. */
52
+ /** Placeholder when nothing is selected. */
54
53
  placeholder?: string;
55
- /** Label above the filter dropdown. */
56
- filterLabel?: string;
57
- /** Placeholder for the filter dropdown. */
58
- filterPlaceholder?: string;
59
- /** Show a clear button on the dataset dropdown. */
54
+ /** Show a clear button. */
60
55
  clearable?: boolean;
61
- /** Mark the dataset dropdown as required. */
56
+ /** Mark the dropdown as required. */
62
57
  required?: boolean;
63
- /** Disable all interaction. */
58
+ /** Disable interaction. */
64
59
  disabled?: boolean;
65
60
  }> & Readonly<{
66
61
  "onUpdate:modelValue"?: ((value: DatasetSelection | undefined) => any) | undefined;
@@ -74,9 +69,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
74
69
  clearable: boolean;
75
70
  required: boolean;
76
71
  disabled: boolean;
77
- filterLabel: string;
78
- filterPlaceholder: string;
79
- }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>, Readonly<{
72
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>, Readonly<{
80
73
  tooltip?: () => unknown;
81
74
  }> & {
82
75
  tooltip?: () => unknown;
@@ -1 +1 @@
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
+ {"version":3,"file":"PlDatasetSelector.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"names":[],"mappings":"AAqIA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAS,MAAM,sBAAsB,CAAC;AAOnF;;;;;;;;;;;;;GAaG;;iBAsGU,gBAAgB,GAAG,SAAS;;IA7FrC,8EAA8E;cACpE,QAAQ,CAAC,aAAa,EAAE,CAAC;IACnC,gCAAgC;YACxB,MAAM;IACd,qEAAqE;aAC5D,MAAM;IACf,gEAAgE;2BACzC,MAAM;IAC7B,kDAAkD;YAC1C,OAAO;IACf,4CAA4C;kBAC9B,MAAM;IACpB,2BAA2B;gBACf,OAAO;IACnB,qCAAqC;eAC1B,OAAO;IAClB,2BAA2B;eAChB,OAAO;;;;iBA4ET,gBAAgB,GAAG,SAAS;;IA7FrC,8EAA8E;cACpE,QAAQ,CAAC,aAAa,EAAE,CAAC;IACnC,gCAAgC;YACxB,MAAM;IACd,qEAAqE;aAC5D,MAAM;IACf,gEAAgE;2BACzC,MAAM;IAC7B,kDAAkD;YAC1C,OAAO;IACf,4CAA4C;kBAC9B,MAAM;IACpB,2BAA2B;gBACf,OAAO;IACnB,qCAAqC;eAC1B,OAAO;IAClB,2BAA2B;eAChB,OAAO;;;;;WAdV,MAAM;iBAQA,MAAM;aAVV,QAAQ,CAAC,aAAa,EAAE,CAAC;YAI1B,MAAM;0BAEQ,MAAM;eAMjB,OAAO;cAER,OAAO;cAEP,OAAO;;cAvBV,MAAM,OAAO;;cAAb,MAAM,OAAO;;AAFzB,wBA0MK;AAcL,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
@@ -1,18 +1,15 @@
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
- //#region src/components/PlDatasetSelector/PlDatasetSelector.vue?vue&type=script&setup=true&lang.ts
5
- var _ = { class: "pl-dataset-selector" }, v = /* @__PURE__ */ i({
1
+ import { computed as e, createBlock as t, createSlots as n, defineComponent as r, mergeModels as i, openBlock as a, renderSlot as o, unref as s, useModel as c, useSlots as l, withCtx as u } from "vue";
2
+ import { createDatasetSelection as d, createPrimaryRef as f, plRefsEqual as p } from "@platforma-sdk/model";
3
+ import { PlDropdown as m } from "@milaboratories/uikit";
4
+ var h = /* @__PURE__ */ r({
6
5
  name: "PlDatasetSelector",
7
- props: /* @__PURE__ */ a({
6
+ props: /* @__PURE__ */ i({
8
7
  options: { default: void 0 },
9
8
  label: { default: void 0 },
10
9
  helper: { default: void 0 },
11
10
  loadingOptionsHelper: { default: void 0 },
12
11
  error: { default: void 0 },
13
12
  placeholder: { default: "..." },
14
- filterLabel: { default: "" },
15
- filterPlaceholder: { default: "..." },
16
13
  clearable: {
17
14
  type: Boolean,
18
15
  default: !1
@@ -30,43 +27,57 @@ var _ = { class: "pl-dataset-selector" }, v = /* @__PURE__ */ i({
30
27
  modelModifiers: {}
31
28
  }),
32
29
  emits: ["update:modelValue"],
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));
30
+ setup(r) {
31
+ let i = l(), h = c(r, "modelValue"), g = r, _ = e(() => {
32
+ let e = h.value?.primary;
33
+ if (e !== void 0) return e.filter === void 0 ? { primary: e.column } : {
34
+ primary: e.column,
35
+ filter: e.filter
36
+ };
37
+ }), v = e(() => {
38
+ if (g.options === void 0) return;
39
+ let e = [];
40
+ for (let t of g.options) {
41
+ e.push({
42
+ label: t.primary.label,
43
+ value: { primary: t.primary.ref }
44
+ });
45
+ for (let n of t.filters ?? []) e.push({
46
+ label: n.label,
47
+ description: t.primary.label,
48
+ value: {
49
+ primary: t.primary.ref,
50
+ filter: n.ref
51
+ }
52
+ });
53
+ }
54
+ return e;
55
+ });
56
+ function y(e) {
57
+ return g.options?.find((t) => p(t.primary.ref, e, !0));
43
58
  }
44
- function E(e) {
59
+ function b(e) {
45
60
  if (e === void 0) {
46
- v.value = void 0;
61
+ h.value = void 0;
47
62
  return;
48
63
  }
49
- v.value = f(p(e), T(e)?.enrichments);
50
- }
51
- function D(e) {
52
- let t = b.value;
53
- t && (v.value = f(p(t, e), T(t)?.enrichments));
64
+ h.value = d(f(e.primary, e.filter), y(e.primary)?.enrichments);
54
65
  }
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 ? {
66
+ return (e, c) => (a(), t(s(m), {
67
+ "model-value": _.value,
68
+ options: v.value,
69
+ label: r.label,
70
+ helper: r.helper,
71
+ "loading-options-helper": r.loadingOptionsHelper,
72
+ error: r.error,
73
+ placeholder: r.placeholder,
74
+ clearable: r.clearable,
75
+ required: r.required,
76
+ disabled: r.disabled,
77
+ "onUpdate:modelValue": b
78
+ }, n({ _: 2 }, [i.tooltip ? {
68
79
  name: "tooltip",
69
- fn: d(() => [s(e.$slots, "tooltip", {}, void 0, !0)]),
80
+ fn: u(() => [o(e.$slots, "tooltip")]),
70
81
  key: "0"
71
82
  } : void 0]), 1032, [
72
83
  "model-value",
@@ -79,24 +90,10 @@ var _ = { class: "pl-dataset-selector" }, v = /* @__PURE__ */ i({
79
90
  "clearable",
80
91
  "required",
81
92
  "disabled"
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
90
- }, null, 8, [
91
- "model-value",
92
- "options",
93
- "label",
94
- "placeholder",
95
- "disabled"
96
- ])]));
93
+ ]));
97
94
  }
98
95
  });
99
96
  //#endregion
100
- export { v as default };
97
+ export { h as default };
101
98
 
102
99
  //# 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 * The filter dropdown is always rendered and is clearableleaving 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"}
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 or one of its filters in a single dropdown, emitting a\n * {@link DatasetSelection}.\n *\n * Each `DatasetOption` contributes one row for its primary plus one row per\n * filter filters are listed directly underneath their parent dataset and\n * carry the parent's primary label as the row description. Filter labels are\n * derived by `buildDatasetOptions` from each filter column's latest\n * `pl7.app/trace` step (the producing block's self-description).\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 } 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 dropdown. */\n label?: string;\n /** Helper text below the 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 dropdown. */\n error?: unknown;\n /** Placeholder when nothing is selected. */\n placeholder?: string;\n /** Show a clear button. */\n clearable?: boolean;\n /** Mark the dropdown as required. */\n required?: boolean;\n /** Disable interaction. */\n disabled?: boolean;\n }>(),\n {\n options: undefined,\n label: undefined,\n helper: undefined,\n loadingOptionsHelper: undefined,\n error: undefined,\n placeholder: \"...\",\n clearable: false,\n required: false,\n disabled: false,\n },\n);\n\ntype Selection = { primary: PlRef; filter?: PlRef };\n\nconst selectionValue = computed<Selection | undefined>(() => {\n const primary = model.value?.primary;\n if (primary === undefined) return undefined;\n return primary.filter === undefined\n ? { primary: primary.column }\n : { primary: primary.column, filter: primary.filter };\n});\n\n// `deepEqual` (used by PlDropdown for matching) treats `{a, b: undefined}` and\n// `{a}` as different shapes, so the option list and the selection value must\n// agree on filter-key presence.\nconst dropdownOptions = computed<ListOption<Selection>[] | undefined>(() => {\n if (props.options === undefined) return undefined;\n const out: ListOption<Selection>[] = [];\n for (const o of props.options) {\n out.push({ label: o.primary.label, value: { primary: o.primary.ref } });\n for (const filter of o.filters ?? []) {\n out.push({\n label: filter.label,\n description: o.primary.label,\n value: { primary: o.primary.ref, filter: filter.ref },\n });\n }\n }\n return out;\n});\n\nfunction findOption(primary: PlRef): DatasetOption | undefined {\n return props.options?.find((o) => plRefsEqual(o.primary.ref, primary, true));\n}\n\nfunction onChange(selection: Selection | undefined) {\n if (selection === undefined) {\n model.value = undefined;\n return;\n }\n model.value = createDatasetSelection(\n createPrimaryRef(selection.primary, selection.filter),\n findOption(selection.primary)?.enrichments,\n );\n}\n</script>\n\n<template>\n <PlDropdown\n :model-value=\"selectionValue\"\n :options=\"dropdownOptions\"\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=\"onChange\"\n >\n <template v-if=\"slots.tooltip\" #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlDropdown>\n</template>\n"],"mappings":";;;;CAgBE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;EAWR,IAAM,IAAQ,GAEV,EAEE,IAAQ,EAAyC,GAAA,aAAE,EAEnD,IAAQ,GAoCR,IAAiB,QAAsC;GAC3D,IAAM,IAAU,EAAM,OAAO;AACzB,aAAY,KAAA,EAChB,QAAO,EAAQ,WAAW,KAAA,IACtB,EAAE,SAAS,EAAQ,QAAO,GAC1B;IAAE,SAAS,EAAQ;IAAQ,QAAQ,EAAQ;IAAQ;IACvD,EAKI,IAAkB,QAAoD;AAC1E,OAAI,EAAM,YAAY,KAAA,EAAW;GACjC,IAAM,IAA+B,EAAE;AACvC,QAAK,IAAM,KAAK,EAAM,SAAS;AAC7B,MAAI,KAAK;KAAE,OAAO,EAAE,QAAQ;KAAO,OAAO,EAAE,SAAS,EAAE,QAAQ,KAAK;KAAE,CAAC;AACvE,SAAK,IAAM,KAAU,EAAE,WAAW,EAAE,CAClC,GAAI,KAAK;KACP,OAAO,EAAO;KACd,aAAa,EAAE,QAAQ;KACvB,OAAO;MAAE,SAAS,EAAE,QAAQ;MAAK,QAAQ,EAAO;MAAK;KACtD,CAAC;;AAGN,UAAO;IACP;EAEF,SAAS,EAAW,GAA2C;AAC7D,UAAO,EAAM,SAAS,MAAM,MAAM,EAAY,EAAE,QAAQ,KAAK,GAAS,GAAK,CAAC;;EAG9E,SAAS,EAAS,GAAkC;AAClD,OAAI,MAAc,KAAA,GAAW;AAC3B,MAAM,QAAQ,KAAA;AACd;;AAEF,KAAM,QAAQ,EACZ,EAAiB,EAAU,SAAS,EAAU,OAAO,EACrD,EAAW,EAAU,QAAQ,EAAE,YAChC;;yBAKD,EAgBa,EAAA,EAAA,EAAA;GAfV,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,UAAA,CAAA,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/ui-vue",
3
- "version": "1.75.8",
3
+ "version": "1.76.0",
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.41.2",
29
+ "@milaboratories/uikit": "2.14.7",
30
30
  "@milaboratories/pf-spec-driver": "1.3.15",
31
- "@milaboratories/uikit": "2.14.6",
32
- "@platforma-sdk/model": "1.75.8"
31
+ "@platforma-sdk/model": "1.75.10",
32
+ "@milaboratories/pl-model-common": "1.41.2"
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/ts-builder": "1.4.0",
49
+ "@milaboratories/ts-configs": "1.2.3",
49
50
  "@milaboratories/build-configs": "2.0.0",
50
- "@milaboratories/helpers": "1.14.2",
51
- "@milaboratories/ts-configs": "1.2.3"
51
+ "@milaboratories/helpers": "1.14.2"
52
52
  },
53
53
  "scripts": {
54
54
  "dev": "ts-builder serve --target browser-lib",
@@ -1,10 +1,13 @@
1
1
  <script lang="ts">
2
2
  /**
3
- * Select a dataset and (optionally) a filter column, emitting a {@link DatasetSelection}.
3
+ * Select a dataset or one of its filters in a single dropdown, emitting a
4
+ * {@link DatasetSelection}.
4
5
  *
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.
6
+ * Each `DatasetOption` contributes one row for its primary plus one row per
7
+ * filter filters are listed directly underneath their parent dataset and
8
+ * carry the parent's primary label as the row description. Filter labels are
9
+ * derived by `buildDatasetOptions` from each filter column's latest
10
+ * `pl7.app/trace` step (the producing block's self-description).
8
11
  *
9
12
  * The emitted value bundles the user's pick (`primary`) with the auto-attached
10
13
  * `enrichments` payload from the matching `DatasetOption`. Enrichments are
@@ -19,7 +22,7 @@ export default {
19
22
  import type { DatasetOption, DatasetSelection, PlRef } from "@platforma-sdk/model";
20
23
  import { createDatasetSelection, createPrimaryRef, plRefsEqual } from "@platforma-sdk/model";
21
24
  import type { ListOption } from "@milaboratories/uikit";
22
- import { PlDropdown, PlDropdownRef } from "@milaboratories/uikit";
25
+ import { PlDropdown } from "@milaboratories/uikit";
23
26
  import { computed } from "vue";
24
27
 
25
28
  const slots = defineSlots<{
@@ -32,25 +35,21 @@ const props = withDefaults(
32
35
  defineProps<{
33
36
  /** Available datasets, each optionally carrying compatible filter choices. */
34
37
  options?: Readonly<DatasetOption[]>;
35
- /** Label above the dataset dropdown. */
38
+ /** Label above the dropdown. */
36
39
  label?: string;
37
- /** Helper text below the dataset dropdown (shown when there is no error). */
40
+ /** Helper text below the dropdown (shown when there is no error). */
38
41
  helper?: string;
39
42
  /** Helper text shown while `options` is undefined (loading). */
40
43
  loadingOptionsHelper?: string;
41
- /** Error message displayed below the dataset dropdown. */
44
+ /** Error message displayed below the dropdown. */
42
45
  error?: unknown;
43
- /** Placeholder when no dataset is selected. */
46
+ /** Placeholder when nothing is selected. */
44
47
  placeholder?: string;
45
- /** Label above the filter dropdown. */
46
- filterLabel?: string;
47
- /** Placeholder for the filter dropdown. */
48
- filterPlaceholder?: string;
49
- /** Show a clear button on the dataset dropdown. */
48
+ /** Show a clear button. */
50
49
  clearable?: boolean;
51
- /** Mark the dataset dropdown as required. */
50
+ /** Mark the dropdown as required. */
52
51
  required?: boolean;
53
- /** Disable all interaction. */
52
+ /** Disable interaction. */
54
53
  disabled?: boolean;
55
54
  }>(),
56
55
  {
@@ -60,92 +59,73 @@ const props = withDefaults(
60
59
  loadingOptionsHelper: undefined,
61
60
  error: undefined,
62
61
  placeholder: "...",
63
- filterLabel: "",
64
- filterPlaceholder: "...",
65
62
  clearable: false,
66
63
  required: false,
67
64
  disabled: false,
68
65
  },
69
66
  );
70
67
 
71
- const selectedDataset = computed<PlRef | undefined>(() => model.value?.primary.column);
68
+ type Selection = { primary: PlRef; filter?: PlRef };
72
69
 
73
- const selectedFilter = computed<PlRef | undefined>(() => model.value?.primary.filter);
74
-
75
- const currentDatasetOption = computed<DatasetOption | undefined>(() => {
76
- const dataset = selectedDataset.value;
77
- if (!dataset) return undefined;
78
- return props.options?.find((o) => plRefsEqual(o.primary.ref, dataset, true));
70
+ const selectionValue = computed<Selection | undefined>(() => {
71
+ const primary = model.value?.primary;
72
+ if (primary === undefined) return undefined;
73
+ return primary.filter === undefined
74
+ ? { primary: primary.column }
75
+ : { primary: primary.column, filter: primary.filter };
79
76
  });
80
77
 
81
- // PlDropdownRef expects `Option[]`; project the primary out of each entry.
82
- const primaryOptions = computed<readonly { ref: PlRef; label: string }[] | undefined>(() =>
83
- props.options?.map((o) => o.primary),
84
- );
85
-
86
- const filterOptions = computed<ListOption<PlRef>[]>(
87
- () => currentDatasetOption.value?.filters?.map((f) => ({ label: f.label, value: f.ref })) ?? [],
88
- );
78
+ // `deepEqual` (used by PlDropdown for matching) treats `{a, b: undefined}` and
79
+ // `{a}` as different shapes, so the option list and the selection value must
80
+ // agree on filter-key presence.
81
+ const dropdownOptions = computed<ListOption<Selection>[] | undefined>(() => {
82
+ if (props.options === undefined) return undefined;
83
+ const out: ListOption<Selection>[] = [];
84
+ for (const o of props.options) {
85
+ out.push({ label: o.primary.label, value: { primary: o.primary.ref } });
86
+ for (const filter of o.filters ?? []) {
87
+ out.push({
88
+ label: filter.label,
89
+ description: o.primary.label,
90
+ value: { primary: o.primary.ref, filter: filter.ref },
91
+ });
92
+ }
93
+ }
94
+ return out;
95
+ });
89
96
 
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));
97
+ function findOption(primary: PlRef): DatasetOption | undefined {
98
+ return props.options?.find((o) => plRefsEqual(o.primary.ref, primary, true));
94
99
  }
95
100
 
96
- function onDatasetChange(dataset: PlRef | undefined) {
97
- if (dataset === undefined) {
101
+ function onChange(selection: Selection | undefined) {
102
+ if (selection === undefined) {
98
103
  model.value = undefined;
99
104
  return;
100
105
  }
101
- model.value = createDatasetSelection(createPrimaryRef(dataset), findOption(dataset)?.enrichments);
102
- }
103
-
104
- function onFilterChange(filter: PlRef | undefined) {
105
- const dataset = selectedDataset.value;
106
- if (!dataset) return;
107
106
  model.value = createDatasetSelection(
108
- createPrimaryRef(dataset, filter),
109
- findOption(dataset)?.enrichments,
107
+ createPrimaryRef(selection.primary, selection.filter),
108
+ findOption(selection.primary)?.enrichments,
110
109
  );
111
110
  }
112
111
  </script>
113
112
 
114
113
  <template>
115
- <div class="pl-dataset-selector">
116
- <PlDropdownRef
117
- :model-value="selectedDataset"
118
- :options="primaryOptions"
119
- :label="label"
120
- :helper="helper"
121
- :loading-options-helper="loadingOptionsHelper"
122
- :error="error"
123
- :placeholder="placeholder"
124
- :clearable="clearable"
125
- :required="required"
126
- :disabled="disabled"
127
- @update:model-value="onDatasetChange"
128
- >
129
- <template v-if="slots.tooltip" #tooltip>
130
- <slot name="tooltip" />
131
- </template>
132
- </PlDropdownRef>
133
- <PlDropdown
134
- :model-value="selectedFilter"
135
- :options="filterOptions"
136
- :label="filterLabel"
137
- :placeholder="filterPlaceholder"
138
- :disabled="disabled"
139
- clearable
140
- @update:model-value="onFilterChange"
141
- />
142
- </div>
114
+ <PlDropdown
115
+ :model-value="selectionValue"
116
+ :options="dropdownOptions"
117
+ :label="label"
118
+ :helper="helper"
119
+ :loading-options-helper="loadingOptionsHelper"
120
+ :error="error"
121
+ :placeholder="placeholder"
122
+ :clearable="clearable"
123
+ :required="required"
124
+ :disabled="disabled"
125
+ @update:model-value="onChange"
126
+ >
127
+ <template v-if="slots.tooltip" #tooltip>
128
+ <slot name="tooltip" />
129
+ </template>
130
+ </PlDropdown>
143
131
  </template>
144
-
145
- <style scoped>
146
- .pl-dataset-selector {
147
- display: flex;
148
- flex-direction: column;
149
- gap: 12px;
150
- }
151
- </style>
@@ -24,18 +24,12 @@ const optionsWithFilters: DatasetOption[] = [
24
24
  ],
25
25
  enrichments: enrichmentsA,
26
26
  },
27
- // Dataset B has no filters — filter dropdown is rendered but with no options.
27
+ // Dataset B has no filters — it appears as a single row with no children.
28
28
  { primary: { label: "Dataset B", ref: datasetB } },
29
29
  ];
30
30
 
31
- const datasetC = createPlRef("3", "out-c", true);
32
-
33
31
  const optionsNoFilters: DatasetOption[] = [{ primary: { label: "Dataset B", ref: datasetB } }];
34
32
 
35
- const optionsWithEmptyFilters: DatasetOption[] = [
36
- { primary: { label: "Dataset C", ref: datasetC }, filters: [] },
37
- ];
38
-
39
33
  function selection(
40
34
  ref: typeof datasetA,
41
35
  filter?: typeof filterA1,
@@ -45,57 +39,46 @@ function selection(
45
39
  }
46
40
 
47
41
  async function pickOption(index: number) {
48
- const options = [...document.body.querySelectorAll(".dropdown-list-item")] as HTMLElement[];
49
- options[index].click();
42
+ const items = [...document.body.querySelectorAll(".dropdown-list-item")] as HTMLElement[];
43
+ items[index].click();
50
44
  await flushPromises();
51
45
  }
52
46
 
53
47
  describe("PlDatasetSelector", () => {
54
- it("always renders both dataset and filter dropdowns", async () => {
48
+ it("renders a single dropdown that lists datasets and filters together", async () => {
55
49
  const wrapper = mount(PlDatasetSelector, {
56
- props: { modelValue: undefined, options: optionsNoFilters },
50
+ props: { modelValue: undefined, options: optionsWithFilters },
57
51
  attachTo: document.body,
58
52
  });
59
53
  await flushPromises();
60
54
 
61
- const selector = wrapper.find(".pl-dataset-selector");
62
- expect(selector.exists()).toBe(true);
63
- expect(selector.element.children.length).toBe(2);
64
- wrapper.unmount();
65
- });
66
-
67
- it("filter dropdown is rendered when the selected dataset has filters", async () => {
68
- const wrapper = mount(PlDatasetSelector, {
69
- props: { modelValue: selection(datasetA), options: optionsWithFilters },
70
- attachTo: document.body,
71
- });
72
- await flushPromises();
55
+ expect(wrapper.findAll("input").length).toBe(1);
56
+ await wrapper.find("input").trigger("focus");
73
57
 
74
- expect(wrapper.find(".pl-dataset-selector").element.children.length).toBe(2);
58
+ const items = document.body.querySelectorAll(".dropdown-list-item");
59
+ // Dataset A + 2 filters under it + Dataset B.
60
+ expect(items.length).toBe(4);
75
61
  wrapper.unmount();
76
62
  });
77
63
 
78
- it("filter dropdown is still rendered (with no options) when the selected dataset has no filters", async () => {
64
+ it("uses the filter option's label as the row's display label", async () => {
79
65
  const wrapper = mount(PlDatasetSelector, {
80
- props: { modelValue: selection(datasetB), options: optionsWithFilters },
66
+ props: { modelValue: undefined, options: optionsWithFilters },
81
67
  attachTo: document.body,
82
68
  });
83
69
  await flushPromises();
84
70
 
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);
71
+ await wrapper.find("input").trigger("focus");
72
+ const items = [...document.body.querySelectorAll(".dropdown-list-item")] as HTMLElement[];
73
+ expect(items[1].textContent).toContain("Top 1000");
74
+ expect(items[2].textContent).toContain("High quality");
92
75
  wrapper.unmount();
93
76
  });
94
77
 
95
- it("emits DatasetSelection bundling primary + enrichments when dataset changes", async () => {
78
+ it("emits DatasetSelection bundling primary + enrichments when a dataset is picked", async () => {
96
79
  const wrapper = mount(PlDatasetSelector, {
97
80
  props: {
98
- modelValue: selection(datasetA, filterA1, enrichmentsA),
81
+ modelValue: undefined,
99
82
  options: optionsWithFilters,
100
83
  "onUpdate:modelValue": (e: DatasetSelection | undefined) =>
101
84
  wrapper.setProps({ modelValue: e }),
@@ -104,25 +87,25 @@ describe("PlDatasetSelector", () => {
104
87
  });
105
88
  await flushPromises();
106
89
 
107
- const inputs = wrapper.findAll("input");
108
- await inputs[0].trigger("focus");
109
- // Dataset A is index 0; pick Dataset B (index 1) — has no enrichments.
110
- await pickOption(1);
90
+ await wrapper.find("input").trigger("focus");
91
+ // Items in order: Dataset A, filterA1, filterA2, Dataset B.
92
+ await pickOption(0);
111
93
 
112
94
  const emitted = wrapper.emitted("update:modelValue");
113
95
  expect(emitted).toBeDefined();
114
96
  const last = emitted![emitted!.length - 1][0] as DatasetSelection;
115
97
  expect(last).toEqual({
116
98
  __isDatasetSelection: "v1",
117
- primary: { __isPrimaryRef: "v1", column: datasetB },
99
+ primary: { __isPrimaryRef: "v1", column: datasetA },
100
+ enrichments: enrichmentsA,
118
101
  });
119
102
  wrapper.unmount();
120
103
  });
121
104
 
122
- it("emits DatasetSelection with filter set when a filter is picked", async () => {
105
+ it("emits DatasetSelection with filter set when a filter row is picked", async () => {
123
106
  const wrapper = mount(PlDatasetSelector, {
124
107
  props: {
125
- modelValue: selection(datasetA, undefined, enrichmentsA),
108
+ modelValue: undefined,
126
109
  options: optionsWithFilters,
127
110
  "onUpdate:modelValue": (e: DatasetSelection | undefined) =>
128
111
  wrapper.setProps({ modelValue: e }),
@@ -131,11 +114,9 @@ describe("PlDatasetSelector", () => {
131
114
  });
132
115
  await flushPromises();
133
116
 
134
- const inputs = wrapper.findAll("input");
135
- expect(inputs.length).toBe(2);
136
- await inputs[1].trigger("focus");
137
- // Options: [Top 1000, High quality]. Pick "Top 1000".
138
- await pickOption(0);
117
+ await wrapper.find("input").trigger("focus");
118
+ // Pick filterA1 — index 1 in the flat list.
119
+ await pickOption(1);
139
120
 
140
121
  const emitted = wrapper.emitted("update:modelValue");
141
122
  expect(emitted).toBeDefined();
@@ -148,11 +129,11 @@ describe("PlDatasetSelector", () => {
148
129
  wrapper.unmount();
149
130
  });
150
131
 
151
- it("emits DatasetSelection with no filter key when the filter dropdown is cleared", async () => {
132
+ it("emits DatasetSelection without enrichments when the picked option carries none", async () => {
152
133
  const wrapper = mount(PlDatasetSelector, {
153
134
  props: {
154
- modelValue: selection(datasetA, filterA1, enrichmentsA),
155
- options: optionsWithFilters,
135
+ modelValue: undefined,
136
+ options: optionsNoFilters,
156
137
  "onUpdate:modelValue": (e: DatasetSelection | undefined) =>
157
138
  wrapper.setProps({ modelValue: e }),
158
139
  },
@@ -160,42 +141,26 @@ describe("PlDatasetSelector", () => {
160
141
  });
161
142
  await flushPromises();
162
143
 
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");
144
+ await wrapper.find("input").trigger("focus");
145
+ await pickOption(0);
169
146
 
170
147
  const emitted = wrapper.emitted("update:modelValue");
171
148
  expect(emitted).toBeDefined();
172
149
  const last = emitted![emitted!.length - 1][0] as DatasetSelection;
173
- expect(last.primary).toEqual({ __isPrimaryRef: "v1", column: datasetA });
174
- expect("filter" in last.primary).toBe(false);
175
- expect(last.enrichments).toEqual(enrichmentsA);
176
- wrapper.unmount();
177
- });
178
-
179
- it("filter dropdown is still rendered (with no options) when dataset has filters: [] (empty array)", async () => {
180
- const wrapper = mount(PlDatasetSelector, {
181
- props: { modelValue: selection(datasetC), options: optionsWithEmptyFilters },
182
- attachTo: document.body,
150
+ expect(last).toEqual({
151
+ __isDatasetSelection: "v1",
152
+ primary: { __isPrimaryRef: "v1", column: datasetB },
183
153
  });
184
- await flushPromises();
185
-
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);
154
+ expect("enrichments" in last).toBe(false);
191
155
  wrapper.unmount();
192
156
  });
193
157
 
194
- it("does not emit on mount when no filter is selected", async () => {
158
+ it("emits undefined when cleared", async () => {
195
159
  const wrapper = mount(PlDatasetSelector, {
196
160
  props: {
197
- modelValue: selection(datasetA),
161
+ modelValue: selection(datasetA, filterA1, enrichmentsA),
198
162
  options: optionsWithFilters,
163
+ clearable: true,
199
164
  "onUpdate:modelValue": (e: DatasetSelection | undefined) =>
200
165
  wrapper.setProps({ modelValue: e }),
201
166
  },
@@ -203,49 +168,22 @@ describe("PlDatasetSelector", () => {
203
168
  });
204
169
  await flushPromises();
205
170
 
206
- expect(wrapper.emitted("update:modelValue")).toBeUndefined();
207
-
208
- const inputs = wrapper.findAll("input");
209
- expect(inputs.length).toBe(2);
210
- await inputs[1].trigger("focus");
211
- const items = document.body.querySelectorAll(".dropdown-list-item");
212
- expect(items.length).toBe(2); // Top 1000, High quality — no synthetic "No filter"
213
- wrapper.unmount();
214
- });
215
-
216
- it("emits DatasetSelection without enrichments when the option carries none", async () => {
217
- const wrapper = mount(PlDatasetSelector, {
218
- props: {
219
- modelValue: undefined,
220
- options: optionsNoFilters,
221
- "onUpdate:modelValue": (e: DatasetSelection | undefined) =>
222
- wrapper.setProps({ modelValue: e }),
223
- },
224
- attachTo: document.body,
225
- });
226
- await flushPromises();
227
-
228
- const inputs = wrapper.findAll("input");
229
- await inputs[0].trigger("focus");
230
- await pickOption(0);
171
+ const clearBtn = wrapper.find(".clear");
172
+ expect(clearBtn.exists()).toBe(true);
173
+ await clearBtn.trigger("click");
231
174
 
232
175
  const emitted = wrapper.emitted("update:modelValue");
233
176
  expect(emitted).toBeDefined();
234
- const last = emitted![emitted!.length - 1][0] as DatasetSelection;
235
- expect(last).toEqual({
236
- __isDatasetSelection: "v1",
237
- primary: { __isPrimaryRef: "v1", column: datasetB },
238
- });
239
- expect("enrichments" in last).toBe(false);
177
+ const last = emitted![emitted!.length - 1][0];
178
+ expect(last).toBeUndefined();
240
179
  wrapper.unmount();
241
180
  });
242
181
 
243
- it("emits undefined when cleared via the dataset dropdown", async () => {
182
+ it("does not emit on mount when a value is provided", async () => {
244
183
  const wrapper = mount(PlDatasetSelector, {
245
184
  props: {
246
- modelValue: selection(datasetA, filterA1, enrichmentsA),
185
+ modelValue: selection(datasetA),
247
186
  options: optionsWithFilters,
248
- clearable: true,
249
187
  "onUpdate:modelValue": (e: DatasetSelection | undefined) =>
250
188
  wrapper.setProps({ modelValue: e }),
251
189
  },
@@ -253,15 +191,7 @@ describe("PlDatasetSelector", () => {
253
191
  });
254
192
  await flushPromises();
255
193
 
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");
260
-
261
- const emitted = wrapper.emitted("update:modelValue");
262
- expect(emitted).toBeDefined();
263
- const last = emitted![emitted!.length - 1][0];
264
- expect(last).toBeUndefined();
194
+ expect(wrapper.emitted("update:modelValue")).toBeUndefined();
265
195
  wrapper.unmount();
266
196
  });
267
197
  });
@@ -1 +0,0 @@
1
- .pl-dataset-selector[data-v-cb8d3a14]{flex-direction:column;gap:12px;display:flex}