@platforma-sdk/ui-vue 1.84.10 → 1.84.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +67 -67
- package/.turbo/turbo-formatter$colon$check.log +2 -2
- package/.turbo/turbo-linter$colon$check.log +1 -1
- package/.turbo/turbo-types$colon$check.log +1 -1
- package/CHANGELOG.md +19 -0
- package/dist/components/BlockLayout.js.map +1 -1
- package/dist/components/BlockLayout.style.js.map +1 -1
- package/dist/components/BlockLayout.vue.d.ts.map +1 -1
- package/dist/components/BlockLayout.vue2.js +5 -1
- package/dist/components/BlockLayout.vue2.js.map +1 -1
- package/dist/components/BlockLoader.js.map +1 -1
- package/dist/components/BlockLoader.vue.d.ts.map +1 -1
- package/dist/components/BlockLoader.vue2.js +2 -0
- package/dist/components/BlockLoader.vue2.js.map +1 -1
- package/dist/components/LoaderPage.js +4 -1
- package/dist/components/LoaderPage.js.map +1 -1
- package/dist/components/LoaderPage.vue.d.ts.map +1 -1
- package/dist/components/NotFound.js.map +1 -1
- package/dist/components/NotFound.vue.d.ts.map +1 -1
- package/dist/components/NotFound.vue2.js +11 -5
- package/dist/components/NotFound.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.js.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.style.js.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.vue.d.ts.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js +26 -2
- package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/OperandButton.js.map +1 -1
- package/dist/components/PlAdvancedFilter/OperandButton.style.js.map +1 -1
- package/dist/components/PlAdvancedFilter/OperandButton.vue.d.ts.map +1 -1
- package/dist/components/PlAdvancedFilter/OperandButton.vue2.js +2 -1
- package/dist/components/PlAdvancedFilter/OperandButton.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +70 -61
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
- package/dist/components/PlAgCellFile/PlAgCellFile.js.map +1 -1
- package/dist/components/PlAgCellFile/PlAgCellFile.vue.d.ts.map +1 -1
- package/dist/components/PlAgCellFile/PlAgCellFile.vue2.js +5 -1
- package/dist/components/PlAgCellFile/PlAgCellFile.vue2.js.map +1 -1
- package/dist/components/PlAgCellProgress/PlAgCellProgress.js.map +1 -1
- package/dist/components/PlAgCellProgress/PlAgCellProgress.vue.d.ts.map +1 -1
- package/dist/components/PlAgCellProgress/PlAgCellProgress.vue2.js +6 -6
- package/dist/components/PlAgCellProgress/PlAgCellProgress.vue2.js.map +1 -1
- package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.js.map +1 -1
- package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue.d.ts.map +1 -1
- package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue2.js +8 -2
- package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue2.js.map +1 -1
- package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.js.map +1 -1
- package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue.d.ts.map +1 -1
- package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue2.js +4 -1
- package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue2.js.map +1 -1
- package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.js.map +1 -1
- package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue.d.ts.map +1 -1
- package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue2.js +7 -2
- package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue2.js.map +1 -1
- package/dist/components/PlAgColumnHeader/PlAgColumnHeader.js.map +1 -1
- package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue.d.ts.map +1 -1
- package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue2.js +28 -20
- package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue2.js.map +1 -1
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.js.map +1 -1
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue.d.ts.map +1 -1
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue2.js +1 -0
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableSheets.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableSheets.style.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue2.js +2 -0
- package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.style.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +5 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgOverlayLoading.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgOverlayLoading.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgOverlayLoading.vue2.js +12 -2
- package/dist/components/PlAgDataTable/PlAgOverlayLoading.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgOverlayNoRows.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgOverlayNoRows.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgOverlayNoRows.vue2.js +7 -1
- package/dist/components/PlAgDataTable/PlAgOverlayNoRows.vue2.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.style.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue.d.ts.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js +35 -27
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js.map +1 -1
- package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.js.map +1 -1
- package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.d.ts.map +1 -1
- package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue2.js +12 -7
- package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue2.js.map +1 -1
- package/dist/components/PlAgRowNumHeader.js.map +1 -1
- package/dist/components/PlAgRowNumHeader.vue.d.ts.map +1 -1
- package/dist/components/PlAgRowNumHeader.vue2.js +14 -7
- package/dist/components/PlAgRowNumHeader.vue2.js.map +1 -1
- package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.js.map +1 -1
- package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue.d.ts.map +1 -1
- package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue2.js +8 -1
- package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.js.map +1 -1
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.style.js.map +1 -1
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue.d.ts.map +1 -1
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js +14 -3
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.style.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.vue.d.ts.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +11 -2
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotations.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotations.style.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotations.vue.d.ts.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.style.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue.d.ts.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js.map +1 -1
- package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.js.map +1 -1
- package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue.d.ts.map +1 -1
- package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue2.js +16 -2
- package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue2.js.map +1 -1
- package/dist/components/PlBtnExportArchive/Item.js.map +1 -1
- package/dist/components/PlBtnExportArchive/Item.style.js.map +1 -1
- package/dist/components/PlBtnExportArchive/Item.vue.d.ts.map +1 -1
- package/dist/components/PlBtnExportArchive/Item.vue2.js +12 -2
- package/dist/components/PlBtnExportArchive/Item.vue2.js.map +1 -1
- package/dist/components/PlBtnExportArchive/PlBtnExportArchive.js.map +1 -1
- package/dist/components/PlBtnExportArchive/PlBtnExportArchive.style.js.map +1 -1
- package/dist/components/PlBtnExportArchive/PlBtnExportArchive.vue.d.ts.map +1 -1
- package/dist/components/PlBtnExportArchive/PlBtnExportArchive.vue2.js +7 -1
- package/dist/components/PlBtnExportArchive/PlBtnExportArchive.vue2.js.map +1 -1
- package/dist/components/PlBtnExportArchive/Summary.js.map +1 -1
- package/dist/components/PlBtnExportArchive/Summary.style.js.map +1 -1
- package/dist/components/PlBtnExportArchive/Summary.vue.d.ts.map +1 -1
- package/dist/components/PlBtnExportArchive/Summary.vue2.js +11 -2
- package/dist/components/PlBtnExportArchive/Summary.vue2.js.map +1 -1
- package/dist/components/PlDatasetSelector/PlDatasetSelector.js.map +1 -1
- package/dist/components/PlDatasetSelector/PlDatasetSelector.vue.d.ts.map +1 -1
- package/dist/components/PlDatasetSelector/PlDatasetSelector.vue2.js +1 -0
- package/dist/components/PlDatasetSelector/PlDatasetSelector.vue2.js.map +1 -1
- package/dist/components/PlTableFastSearch/PlTableFastSearch.js.map +1 -1
- package/dist/components/PlTableFastSearch/PlTableFastSearch.vue.d.ts.map +1 -1
- package/dist/components/PlTableFastSearch/PlTableFastSearch.vue2.js +1 -0
- package/dist/components/PlTableFastSearch/PlTableFastSearch.vue2.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.style.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue.d.ts.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js +12 -2
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js.map +1 -1
- package/package.json +7 -7
- package/src/components/BlockLayout.vue +4 -2
- package/src/components/BlockLoader.vue +2 -1
- package/src/components/LoaderPage.vue +1 -1
- package/src/components/NotFound.vue +7 -3
- package/src/components/PlAdvancedFilter/FilterEditor.vue +36 -6
- package/src/components/PlAdvancedFilter/OperandButton.vue +2 -1
- package/src/components/PlAdvancedFilter/PlAdvancedFilter.vue +20 -4
- package/src/components/PlAgCellFile/PlAgCellFile.vue +2 -1
- package/src/components/PlAgCellProgress/PlAgCellProgress.vue +1 -1
- package/src/components/PlAgCellStatusTag/PlAgCellStatusTag.vue +2 -2
- package/src/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue +13 -3
- package/src/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue +13 -3
- package/src/components/PlAgColumnHeader/PlAgColumnHeader.vue +24 -6
- package/src/components/PlAgCsvExporter/PlAgCsvExporter.vue +6 -1
- package/src/components/PlAgDataTable/PlAgDataTableSheets.vue +6 -1
- package/src/components/PlAgDataTable/PlAgDataTableV2.vue +2 -1
- package/src/components/PlAgDataTable/PlAgOverlayLoading.vue +10 -3
- package/src/components/PlAgDataTable/PlAgOverlayNoRows.vue +4 -2
- package/src/components/PlAgGridColumnManager/PlAgGridColumnManager.vue +18 -5
- package/src/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue +5 -1
- package/src/components/PlAgRowNumHeader.vue +3 -1
- package/src/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue +3 -2
- package/src/components/PlAnnotations/components/AnnotationsSidebar.vue +13 -4
- package/src/components/PlAnnotations/components/FilterSidebar.vue +11 -3
- package/src/components/PlAnnotations/components/PlAnnotations.vue +1 -1
- package/src/components/PlAnnotations/components/PlAnnotationsModal.vue +1 -0
- package/src/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue +34 -7
- package/src/components/PlBtnExportArchive/Item.vue +22 -6
- package/src/components/PlBtnExportArchive/PlBtnExportArchive.vue +18 -3
- package/src/components/PlBtnExportArchive/Summary.vue +15 -5
- package/src/components/PlDatasetSelector/PlDatasetSelector.vue +1 -0
- package/src/components/PlTableFastSearch/PlTableFastSearch.vue +6 -1
- package/src/components/PlTableFilters/PlTableFiltersV2.vue +14 -4
|
@@ -124,6 +124,7 @@ var k = /* @__PURE__ */ d({
|
|
|
124
124
|
return D([I], () => {
|
|
125
125
|
A.showExports = !1;
|
|
126
126
|
}), (e, a) => (p(), c(r, null, [u(v(w), {
|
|
127
|
+
"data-testid": "pl-btn-export-archive",
|
|
127
128
|
disabled: !M.value,
|
|
128
129
|
loading: A.loading,
|
|
129
130
|
class: f({ [e.$style["has-exports"]]: A.exports }),
|
|
@@ -143,15 +144,20 @@ var k = /* @__PURE__ */ d({
|
|
|
143
144
|
key: 0,
|
|
144
145
|
ref_key: "progressesRef",
|
|
145
146
|
ref: I,
|
|
147
|
+
"data-testid": "pl-btn-export-archive-progress",
|
|
146
148
|
class: f(e.$style.progresses)
|
|
147
149
|
}, [
|
|
148
150
|
u(v(T), {
|
|
151
|
+
"data-testid": "pl-btn-export-archive-progress-close",
|
|
149
152
|
class: f(e.$style.close),
|
|
150
153
|
name: "close",
|
|
151
154
|
onClick: a[0] ||= b((e) => A.showExports = !1, ["stop"])
|
|
152
155
|
}, null, 8, ["class"]),
|
|
153
156
|
u(n, { item: P.value }, null, 8, ["item"]),
|
|
154
|
-
l("div", {
|
|
157
|
+
l("div", {
|
|
158
|
+
"data-testid": "pl-btn-export-archive-items",
|
|
159
|
+
class: f([e.$style.itemsContainer, "pl-scrollable-y"])
|
|
160
|
+
}, [(p(!0), c(r, null, g(A.exports?.values(), (e) => (p(), o(t, {
|
|
155
161
|
key: e.fileName,
|
|
156
162
|
item: e
|
|
157
163
|
}, null, 8, ["item"]))), 128))], 2)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlBtnExportArchive.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlBtnExportArchive/PlBtnExportArchive.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { PlBtnGhost, PlIcon16, PlIcon24, useClickOutside } from \"@milaboratories/uikit\";\nimport { ZipWriter } from \"@zip.js/zip.js\";\nimport { reactive, computed, ref } from \"vue\";\nimport type { ExportItem, ExportsMap, FileExportEntry } from \"./types\";\nimport Item from \"./Item.vue\";\nimport { getFileNameFromHandle, ChunkedStreamReader } from \"@platforma-sdk/model\";\nimport { getRawPlatformaInstance } from \"@platforma-sdk/model\";\nimport { uniqueId } from \"@milaboratories/helpers\";\nimport Summary from \"./Summary.vue\";\n\ntype FilePickerAcceptType = {\n description?: string;\n accept?: Record<string, string[]>;\n};\n\nconst props = defineProps<{\n fileExports?: FileExportEntry[];\n suggestedFileName?: string;\n disabled?: boolean;\n filePickerTypes?: FilePickerAcceptType[];\n strategy?: \"parallel\"; // default is sequential\n debugFn?: (fileName: string) => Promise<void>;\n}>();\n\nconst defaultData = () => ({\n loading: false,\n name: \"\",\n exports: undefined as ExportsMap | undefined,\n showExports: false,\n});\n\nconst data = reactive(defaultData());\n\nconst updateExportsItem = (id: string, partial: Partial<ExportItem>) => {\n const it = data.exports?.get(id);\n if (it) {\n data.exports?.set(id, { ...it, ...partial });\n }\n};\n\nconst isReadyToExport = computed(() => {\n return props.fileExports !== undefined && !props.disabled;\n});\n\nconst items = computed(() => {\n return Array.from(data.exports?.values() ?? []);\n});\n\nconst archive = computed<ExportItem>(() => {\n return {\n fileName: data.name,\n current: items.value.reduce((acc, item) => acc + item.current, 0),\n size: items.value.reduce((acc, item) => acc + item.size, 0),\n status: items.value.some((item) => item.status === \"in-progress\")\n ? \"in-progress\"\n : items.value.every((item) => item.status === \"completed\")\n ? \"completed\"\n : \"pending\",\n hasErrors: items.value.some((item) => item.status === \"error\"),\n };\n});\n\ntype ZipRequest = {\n id: string;\n fileName: string;\n size: number;\n stream: ReadableStream<Uint8Array>;\n};\n\nconst exportRawTsvs = async () => {\n if (data.loading) {\n data.showExports = true;\n return;\n }\n\n if (!isReadyToExport.value || !props.fileExports) {\n return;\n }\n\n const defaultFileName = `${new Date().toISOString().split(\"T\")[0]}_Export.zip`;\n const defaultTypes = [\n {\n description: \"ZIP files\",\n accept: {\n \"application/zip\": [\".zip\"],\n },\n },\n ];\n\n // @ts-expect-error - type definition issue TODO: fix this\n const newHandle = await window.showSaveFilePicker({\n types: props.filePickerTypes || defaultTypes,\n suggestedName: props.suggestedFileName || defaultFileName,\n });\n\n data.loading = true;\n data.name = newHandle.name;\n data.showExports = true;\n data.exports = new Map();\n\n try {\n const writableStream = await newHandle.createWritable();\n const zip = new ZipWriter(writableStream, {\n keepOrder: true,\n zip64: true,\n bufferedWrite: false,\n });\n try {\n const requests = [] as ZipRequest[];\n\n for (const entry of props.fileExports) {\n const { importHandle, blobHandle, fileName: customFileName } = entry;\n const fileName = customFileName ?? getFileNameFromHandle(importHandle);\n const { handle, size } = blobHandle;\n\n const id = uniqueId();\n\n data.exports?.set(id, { fileName, current: 0, size, status: \"pending\" });\n\n const stream = ChunkedStreamReader.create({\n fetchChunk: async ({ from, to }) => {\n if (props.debugFn) {\n await props.debugFn(fileName);\n }\n\n return await getRawPlatformaInstance().blobDriver.getContent(handle, { from, to });\n },\n totalSize: size,\n onError: async (error) => {\n updateExportsItem(id, { status: \"error\", error });\n await new Promise((resolve) => setTimeout(resolve, 1000)); // primitive for now\n return \"continue\";\n },\n });\n\n // Create a chunked stream reader for efficient streaming\n requests.push({ id, fileName, size, stream });\n }\n\n const processRequest = async (request: ZipRequest) => {\n const { id, fileName, size, stream } = request;\n const update = (partial: Partial<ExportItem>) => {\n const it = data.exports?.get(id);\n if (it) {\n data.exports?.set(id, { ...it, ...partial });\n }\n };\n await zip.add(fileName, stream, {\n bufferedWrite: true,\n onstart: () => {\n update({ status: \"in-progress\" });\n return undefined;\n },\n onprogress: (current: number) => {\n update({ current, status: \"in-progress\" });\n return undefined;\n },\n onend() {\n update({ current: size, status: \"completed\" });\n return undefined;\n },\n });\n };\n\n if (props.strategy === \"parallel\") {\n await Promise.all(requests.map(processRequest));\n } else {\n for (const request of requests) {\n await processRequest(request);\n }\n }\n } finally {\n await zip.close().catch((error) => {\n console.error(\"Error closing zip\", error);\n });\n }\n } finally {\n data.loading = false;\n }\n};\n\nconst progressesRef = ref();\n\nuseClickOutside([progressesRef], () => {\n data.showExports = false;\n});\n</script>\n\n<template>\n <PlBtnGhost\n :disabled=\"!isReadyToExport\"\n :loading=\"data.loading\"\n :class=\"{ [$style['has-exports']]: data.exports }\"\n @click.stop=\"exportRawTsvs\"\n >\n <slot />\n <template #append>\n <PlIcon24 :class=\"$style.icon\" name=\"download\" />\n </template>\n </PlBtnGhost>\n <Teleport to=\"body\">\n <div v-if=\"data.exports && data.showExports\" ref=\"progressesRef\" :class=\"$style.progresses\">\n <PlIcon16 :class=\"$style.close\" name=\"close\" @click.stop=\"data.showExports = false\" />\n <Summary :item=\"archive\" />\n <div :class=\"$style.itemsContainer\" class=\"pl-scrollable-y\">\n <Item v-for=\"item in data.exports?.values()\" :key=\"item.fileName\" :item=\"item\" />\n </div>\n </div>\n </Teleport>\n</template>\n\n<style module>\n.progresses {\n position: fixed;\n top: 8px;\n right: 8px;\n width: 350px;\n height: auto;\n max-height: 400px;\n overflow: auto;\n background: rgba(0, 0, 0, 0.85);\n border-radius: 8px;\n padding: 20px 8px 8px 20px;\n color: white;\n font-size: 12px;\n font-weight: 600;\n z-index: 1000;\n\n .itemsContainer {\n max-height: 300px;\n }\n\n .close {\n position: absolute;\n top: 8px;\n right: 8px;\n cursor: pointer;\n --icon-color: white;\n }\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PlBtnExportArchive.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlBtnExportArchive/PlBtnExportArchive.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { PlBtnGhost, PlIcon16, PlIcon24, useClickOutside } from \"@milaboratories/uikit\";\nimport { ZipWriter } from \"@zip.js/zip.js\";\nimport { reactive, computed, ref } from \"vue\";\nimport type { ExportItem, ExportsMap, FileExportEntry } from \"./types\";\nimport Item from \"./Item.vue\";\nimport { getFileNameFromHandle, ChunkedStreamReader } from \"@platforma-sdk/model\";\nimport { getRawPlatformaInstance } from \"@platforma-sdk/model\";\nimport { uniqueId } from \"@milaboratories/helpers\";\nimport Summary from \"./Summary.vue\";\n\ntype FilePickerAcceptType = {\n description?: string;\n accept?: Record<string, string[]>;\n};\n\nconst props = defineProps<{\n fileExports?: FileExportEntry[];\n suggestedFileName?: string;\n disabled?: boolean;\n filePickerTypes?: FilePickerAcceptType[];\n strategy?: \"parallel\"; // default is sequential\n debugFn?: (fileName: string) => Promise<void>;\n}>();\n\nconst defaultData = () => ({\n loading: false,\n name: \"\",\n exports: undefined as ExportsMap | undefined,\n showExports: false,\n});\n\nconst data = reactive(defaultData());\n\nconst updateExportsItem = (id: string, partial: Partial<ExportItem>) => {\n const it = data.exports?.get(id);\n if (it) {\n data.exports?.set(id, { ...it, ...partial });\n }\n};\n\nconst isReadyToExport = computed(() => {\n return props.fileExports !== undefined && !props.disabled;\n});\n\nconst items = computed(() => {\n return Array.from(data.exports?.values() ?? []);\n});\n\nconst archive = computed<ExportItem>(() => {\n return {\n fileName: data.name,\n current: items.value.reduce((acc, item) => acc + item.current, 0),\n size: items.value.reduce((acc, item) => acc + item.size, 0),\n status: items.value.some((item) => item.status === \"in-progress\")\n ? \"in-progress\"\n : items.value.every((item) => item.status === \"completed\")\n ? \"completed\"\n : \"pending\",\n hasErrors: items.value.some((item) => item.status === \"error\"),\n };\n});\n\ntype ZipRequest = {\n id: string;\n fileName: string;\n size: number;\n stream: ReadableStream<Uint8Array>;\n};\n\nconst exportRawTsvs = async () => {\n if (data.loading) {\n data.showExports = true;\n return;\n }\n\n if (!isReadyToExport.value || !props.fileExports) {\n return;\n }\n\n const defaultFileName = `${new Date().toISOString().split(\"T\")[0]}_Export.zip`;\n const defaultTypes = [\n {\n description: \"ZIP files\",\n accept: {\n \"application/zip\": [\".zip\"],\n },\n },\n ];\n\n // @ts-expect-error - type definition issue TODO: fix this\n const newHandle = await window.showSaveFilePicker({\n types: props.filePickerTypes || defaultTypes,\n suggestedName: props.suggestedFileName || defaultFileName,\n });\n\n data.loading = true;\n data.name = newHandle.name;\n data.showExports = true;\n data.exports = new Map();\n\n try {\n const writableStream = await newHandle.createWritable();\n const zip = new ZipWriter(writableStream, {\n keepOrder: true,\n zip64: true,\n bufferedWrite: false,\n });\n try {\n const requests = [] as ZipRequest[];\n\n for (const entry of props.fileExports) {\n const { importHandle, blobHandle, fileName: customFileName } = entry;\n const fileName = customFileName ?? getFileNameFromHandle(importHandle);\n const { handle, size } = blobHandle;\n\n const id = uniqueId();\n\n data.exports?.set(id, { fileName, current: 0, size, status: \"pending\" });\n\n const stream = ChunkedStreamReader.create({\n fetchChunk: async ({ from, to }) => {\n if (props.debugFn) {\n await props.debugFn(fileName);\n }\n\n return await getRawPlatformaInstance().blobDriver.getContent(handle, { from, to });\n },\n totalSize: size,\n onError: async (error) => {\n updateExportsItem(id, { status: \"error\", error });\n await new Promise((resolve) => setTimeout(resolve, 1000)); // primitive for now\n return \"continue\";\n },\n });\n\n // Create a chunked stream reader for efficient streaming\n requests.push({ id, fileName, size, stream });\n }\n\n const processRequest = async (request: ZipRequest) => {\n const { id, fileName, size, stream } = request;\n const update = (partial: Partial<ExportItem>) => {\n const it = data.exports?.get(id);\n if (it) {\n data.exports?.set(id, { ...it, ...partial });\n }\n };\n await zip.add(fileName, stream, {\n bufferedWrite: true,\n onstart: () => {\n update({ status: \"in-progress\" });\n return undefined;\n },\n onprogress: (current: number) => {\n update({ current, status: \"in-progress\" });\n return undefined;\n },\n onend() {\n update({ current: size, status: \"completed\" });\n return undefined;\n },\n });\n };\n\n if (props.strategy === \"parallel\") {\n await Promise.all(requests.map(processRequest));\n } else {\n for (const request of requests) {\n await processRequest(request);\n }\n }\n } finally {\n await zip.close().catch((error) => {\n console.error(\"Error closing zip\", error);\n });\n }\n } finally {\n data.loading = false;\n }\n};\n\nconst progressesRef = ref();\n\nuseClickOutside([progressesRef], () => {\n data.showExports = false;\n});\n</script>\n\n<template>\n <PlBtnGhost\n data-testid=\"pl-btn-export-archive\"\n :disabled=\"!isReadyToExport\"\n :loading=\"data.loading\"\n :class=\"{ [$style['has-exports']]: data.exports }\"\n @click.stop=\"exportRawTsvs\"\n >\n <slot />\n <template #append>\n <PlIcon24 :class=\"$style.icon\" name=\"download\" />\n </template>\n </PlBtnGhost>\n <Teleport to=\"body\">\n <div\n v-if=\"data.exports && data.showExports\"\n ref=\"progressesRef\"\n data-testid=\"pl-btn-export-archive-progress\"\n :class=\"$style.progresses\"\n >\n <PlIcon16\n data-testid=\"pl-btn-export-archive-progress-close\"\n :class=\"$style.close\"\n name=\"close\"\n @click.stop=\"data.showExports = false\"\n />\n <Summary :item=\"archive\" />\n <div\n data-testid=\"pl-btn-export-archive-items\"\n :class=\"$style.itemsContainer\"\n class=\"pl-scrollable-y\"\n >\n <Item v-for=\"item in data.exports?.values()\" :key=\"item.fileName\" :item=\"item\" />\n </div>\n </div>\n </Teleport>\n</template>\n\n<style module>\n.progresses {\n position: fixed;\n top: 8px;\n right: 8px;\n width: 350px;\n height: auto;\n max-height: 400px;\n overflow: auto;\n background: rgba(0, 0, 0, 0.85);\n border-radius: 8px;\n padding: 20px 8px 8px 20px;\n color: white;\n font-size: 12px;\n font-weight: 600;\n z-index: 1000;\n\n .itemsContainer {\n max-height: 300px;\n }\n\n .close {\n position: absolute;\n top: 8px;\n right: 8px;\n cursor: pointer;\n --icon-color: white;\n }\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Summary.js","names":[],"sources":["../../../src/components/PlBtnExportArchive/Summary.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ExportItem } from \"./types\";\nimport { prettyBytes } from \"@milaboratories/helpers\";\n\ndefineProps<{\n item: ExportItem;\n}>();\n\nconst emit = defineEmits<{\n (e: \"cancel\"): void;\n}>();\n</script>\n\n<template>\n <div :class=\"$style.summary\">\n <div :class=\"$style.name\">\n {{ item.fileName }}<span v-if=\"false\" @click.stop=\"emit('cancel')\">[TODO: Cancel]</span>\n </div>\n <div
|
|
1
|
+
{"version":3,"file":"Summary.js","names":[],"sources":["../../../src/components/PlBtnExportArchive/Summary.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ExportItem } from \"./types\";\nimport { prettyBytes } from \"@milaboratories/helpers\";\n\ndefineProps<{\n item: ExportItem;\n}>();\n\nconst emit = defineEmits<{\n (e: \"cancel\"): void;\n}>();\n</script>\n\n<template>\n <div data-testid=\"pl-btn-export-archive-summary\" :class=\"$style.summary\">\n <div data-testid=\"pl-btn-export-archive-summary-name\" :class=\"$style.name\">\n {{ item.fileName }}<span v-if=\"false\" @click.stop=\"emit('cancel')\">[TODO: Cancel]</span>\n </div>\n <div\n v-if=\"item.status === 'in-progress'\"\n data-testid=\"pl-btn-export-archive-summary-status\"\n :class=\"$style.details\"\n >\n <span>{{ prettyBytes(item.current, {}) }}</span>\n <span>/</span>\n <span>{{ prettyBytes(item.size, {}) }}</span>\n </div>\n <div\n v-else-if=\"item.status === 'completed'\"\n data-testid=\"pl-btn-export-archive-summary-status\"\n :class=\"$style.details\"\n >\n Done <span>{{ prettyBytes(item.size, {}) }}</span>\n </div>\n <div v-else data-testid=\"pl-btn-export-archive-summary-status\" :class=\"$style.details\">\n Pending\n </div>\n </div>\n</template>\n\n<style module>\n.summary {\n display: flex;\n flex-direction: column;\n margin-bottom: 8px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n padding-bottom: 8px;\n --name-font-size: 14px;\n --details-font-size: 12px;\n}\n\n.name {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--name-font-size);\n font-weight: 600;\n}\n.details {\n font-size: var(--details-font-size);\n font-weight: 400;\n color: rgba(255, 255, 255, 0.6);\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Summary.vue_vue_type_style_index_0_lang.module.js","names":[],"sources":["../../../src/components/PlBtnExportArchive/Summary.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ExportItem } from \"./types\";\nimport { prettyBytes } from \"@milaboratories/helpers\";\n\ndefineProps<{\n item: ExportItem;\n}>();\n\nconst emit = defineEmits<{\n (e: \"cancel\"): void;\n}>();\n</script>\n\n<template>\n <div :class=\"$style.summary\">\n <div :class=\"$style.name\">\n {{ item.fileName }}<span v-if=\"false\" @click.stop=\"emit('cancel')\">[TODO: Cancel]</span>\n </div>\n <div
|
|
1
|
+
{"version":3,"file":"Summary.vue_vue_type_style_index_0_lang.module.js","names":[],"sources":["../../../src/components/PlBtnExportArchive/Summary.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ExportItem } from \"./types\";\nimport { prettyBytes } from \"@milaboratories/helpers\";\n\ndefineProps<{\n item: ExportItem;\n}>();\n\nconst emit = defineEmits<{\n (e: \"cancel\"): void;\n}>();\n</script>\n\n<template>\n <div data-testid=\"pl-btn-export-archive-summary\" :class=\"$style.summary\">\n <div data-testid=\"pl-btn-export-archive-summary-name\" :class=\"$style.name\">\n {{ item.fileName }}<span v-if=\"false\" @click.stop=\"emit('cancel')\">[TODO: Cancel]</span>\n </div>\n <div\n v-if=\"item.status === 'in-progress'\"\n data-testid=\"pl-btn-export-archive-summary-status\"\n :class=\"$style.details\"\n >\n <span>{{ prettyBytes(item.current, {}) }}</span>\n <span>/</span>\n <span>{{ prettyBytes(item.size, {}) }}</span>\n </div>\n <div\n v-else-if=\"item.status === 'completed'\"\n data-testid=\"pl-btn-export-archive-summary-status\"\n :class=\"$style.details\"\n >\n Done <span>{{ prettyBytes(item.size, {}) }}</span>\n </div>\n <div v-else data-testid=\"pl-btn-export-archive-summary-status\" :class=\"$style.details\">\n Pending\n </div>\n </div>\n</template>\n\n<style module>\n.summary {\n display: flex;\n flex-direction: column;\n margin-bottom: 8px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n padding-bottom: 8px;\n --name-font-size: 14px;\n --details-font-size: 12px;\n}\n\n.name {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--name-font-size);\n font-weight: 600;\n}\n.details {\n font-size: var(--details-font-size);\n font-weight: 400;\n color: rgba(255, 255, 255, 0.6);\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Summary.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlBtnExportArchive/Summary.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Summary.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlBtnExportArchive/Summary.vue"],"names":[],"mappings":"AAmEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAuFF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -7,8 +7,15 @@ var u = /* @__PURE__ */ a({
|
|
|
7
7
|
props: { item: {} },
|
|
8
8
|
emits: ["cancel"],
|
|
9
9
|
setup(a, { emit: u }) {
|
|
10
|
-
return (u, d) => (s(), n("div", {
|
|
10
|
+
return (u, d) => (s(), n("div", {
|
|
11
|
+
"data-testid": "pl-btn-export-archive-summary",
|
|
12
|
+
class: o(u.$style.summary)
|
|
13
|
+
}, [r("div", {
|
|
14
|
+
"data-testid": "pl-btn-export-archive-summary-name",
|
|
15
|
+
class: o(u.$style.name)
|
|
16
|
+
}, [i(c(a.item.fileName), 1), t("", !0)], 2), a.item.status === "in-progress" ? (s(), n("div", {
|
|
11
17
|
key: 0,
|
|
18
|
+
"data-testid": "pl-btn-export-archive-summary-status",
|
|
12
19
|
class: o(u.$style.details)
|
|
13
20
|
}, [
|
|
14
21
|
r("span", null, c(l(e)(a.item.current, {})), 1),
|
|
@@ -16,11 +23,13 @@ var u = /* @__PURE__ */ a({
|
|
|
16
23
|
r("span", null, c(l(e)(a.item.size, {})), 1)
|
|
17
24
|
], 2)) : a.item.status === "completed" ? (s(), n("div", {
|
|
18
25
|
key: 1,
|
|
26
|
+
"data-testid": "pl-btn-export-archive-summary-status",
|
|
19
27
|
class: o(u.$style.details)
|
|
20
28
|
}, [d[2] ||= i(" Done ", -1), r("span", null, c(l(e)(a.item.size, {})), 1)], 2)) : (s(), n("div", {
|
|
21
29
|
key: 2,
|
|
30
|
+
"data-testid": "pl-btn-export-archive-summary-status",
|
|
22
31
|
class: o(u.$style.details)
|
|
23
|
-
}, "Pending", 2))], 2));
|
|
32
|
+
}, " Pending ", 2))], 2));
|
|
24
33
|
}
|
|
25
34
|
});
|
|
26
35
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Summary.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlBtnExportArchive/Summary.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ExportItem } from \"./types\";\nimport { prettyBytes } from \"@milaboratories/helpers\";\n\ndefineProps<{\n item: ExportItem;\n}>();\n\nconst emit = defineEmits<{\n (e: \"cancel\"): void;\n}>();\n</script>\n\n<template>\n <div :class=\"$style.summary\">\n <div :class=\"$style.name\">\n {{ item.fileName }}<span v-if=\"false\" @click.stop=\"emit('cancel')\">[TODO: Cancel]</span>\n </div>\n <div
|
|
1
|
+
{"version":3,"file":"Summary.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlBtnExportArchive/Summary.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ExportItem } from \"./types\";\nimport { prettyBytes } from \"@milaboratories/helpers\";\n\ndefineProps<{\n item: ExportItem;\n}>();\n\nconst emit = defineEmits<{\n (e: \"cancel\"): void;\n}>();\n</script>\n\n<template>\n <div data-testid=\"pl-btn-export-archive-summary\" :class=\"$style.summary\">\n <div data-testid=\"pl-btn-export-archive-summary-name\" :class=\"$style.name\">\n {{ item.fileName }}<span v-if=\"false\" @click.stop=\"emit('cancel')\">[TODO: Cancel]</span>\n </div>\n <div\n v-if=\"item.status === 'in-progress'\"\n data-testid=\"pl-btn-export-archive-summary-status\"\n :class=\"$style.details\"\n >\n <span>{{ prettyBytes(item.current, {}) }}</span>\n <span>/</span>\n <span>{{ prettyBytes(item.size, {}) }}</span>\n </div>\n <div\n v-else-if=\"item.status === 'completed'\"\n data-testid=\"pl-btn-export-archive-summary-status\"\n :class=\"$style.details\"\n >\n Done <span>{{ prettyBytes(item.size, {}) }}</span>\n </div>\n <div v-else data-testid=\"pl-btn-export-archive-summary-status\" :class=\"$style.details\">\n Pending\n </div>\n </div>\n</template>\n\n<style module>\n.summary {\n display: flex;\n flex-direction: column;\n margin-bottom: 8px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n padding-bottom: 8px;\n --name-font-size: 14px;\n --details-font-size: 12px;\n}\n\n.name {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--name-font-size);\n font-weight: 600;\n}\n.details {\n font-size: var(--details-font-size);\n font-weight: 400;\n color: rgba(255, 255, 255, 0.6);\n}\n</style>\n"],"mappings":";;;;;;;;;yBAcE,EAuBM,OAAA;GAvBD,eAAY;GAAiC,OAAK,EAAEA,EAAAA,OAAO,QAAO;MACrE,EAEM,OAAA;GAFD,eAAY;GAAsC,OAAK,EAAEA,EAAAA,OAAO,KAAI;UACpE,EAAA,KAAK,SAAQ,EAAA,EAAA,EAAA,EAAA,IAAA,GAAA,CAAA,EAAA,EAAA,EAGV,EAAA,KAAK,WAAM,iBAAA,GAAA,EADnB,EAQM,OAAA;;GANJ,eAAY;GACX,OAAK,EAAEA,EAAAA,OAAO,QAAO;;GAEtB,EAAgD,QAAA,MAAA,EAAvC,EAAA,EAAW,CAAC,EAAA,KAAK,SAAO,EAAA,CAAA,CAAA,EAAA,EAAA;YACjC,EAAc,QAAA,MAAR,KAAC,GAAA;GACP,EAA6C,QAAA,MAAA,EAApC,EAAA,EAAW,CAAC,EAAA,KAAK,MAAI,EAAA,CAAA,CAAA,EAAA,EAAA;WAGnB,EAAA,KAAK,WAAM,eAAA,GAAA,EADxB,EAMM,OAAA;;GAJJ,eAAY;GACX,OAAK,EAAEA,EAAAA,OAAO,QAAO;iBACvB,UACM,GAAA,EAAA,EAA6C,QAAA,MAAA,EAApC,EAAA,EAAW,CAAC,EAAA,KAAK,MAAI,EAAA,CAAA,CAAA,EAAA,EAAA,CAAA,EAAA,EAAA,KAAA,GAAA,EAErC,EAEM,OAAA;;GAFM,eAAY;GAAwC,OAAK,EAAEA,EAAAA,OAAO,QAAO;KAAE,aAEvF,EAAA,EAAA,EAAA,EAAA"}
|
|
@@ -1 +1 @@
|
|
|
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}. Filter labels carry the dataset name as a\n * prefix (e.g. \"Bulk / Top 10\"), so no separate subtitle is rendered.\n * Enrichments from the matching `DatasetOption` are bundled into the\n * emitted value opaquely — block authors unbundle them in their args\n * resolver.\n */\nexport default {\n name: \"PlDatasetSelector\",\n};\n</script>\n\n<script lang=\"ts\" setup>\nimport type {\n DatasetOption,\n DatasetSelection,\n LabeledEnrichmentRefs,\n PlRef,\n} 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; enrichments?: LabeledEnrichmentRefs };\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 optional-key presence.\nfunction makeSelection(\n primary: PlRef,\n filter: PlRef | undefined,\n enrichments: LabeledEnrichmentRefs | undefined,\n): Selection {\n return {\n primary,\n ...(filter !== undefined && { filter }),\n ...(enrichments !== undefined && enrichments.length > 0 && { enrichments }),\n };\n}\n\nconst selectionValue = computed<Selection | undefined>(() => {\n const primary = model.value?.primary;\n if (primary === undefined) return undefined;\n // Read enrichments from the current option, not from `model.value`: the\n // stored enrichments are a snapshot at selection time and won't match\n // `dropdownOptions` after `props.options` recomputes (e.g. when the\n // result pool gains or loses an enrichment column).\n const option = props.options?.find((o) => plRefsEqual(o.primary.ref, primary.column, true));\n return makeSelection(primary.column, primary.filter, option?.enrichments);\n});\n\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({\n label: o.primary.label,\n value: makeSelection(o.primary.ref, undefined, o.enrichments),\n });\n for (const filter of o.filters ?? []) {\n out.push({\n label: filter.label,\n description: o.primary.label,\n value: makeSelection(o.primary.ref, filter.ref, o.enrichments),\n });\n }\n }\n return out;\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 selection.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
|
+
{"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}. Filter labels carry the dataset name as a\n * prefix (e.g. \"Bulk / Top 10\"), so no separate subtitle is rendered.\n * Enrichments from the matching `DatasetOption` are bundled into the\n * emitted value opaquely — block authors unbundle them in their args\n * resolver.\n */\nexport default {\n name: \"PlDatasetSelector\",\n};\n</script>\n\n<script lang=\"ts\" setup>\nimport type {\n DatasetOption,\n DatasetSelection,\n LabeledEnrichmentRefs,\n PlRef,\n} 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; enrichments?: LabeledEnrichmentRefs };\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 optional-key presence.\nfunction makeSelection(\n primary: PlRef,\n filter: PlRef | undefined,\n enrichments: LabeledEnrichmentRefs | undefined,\n): Selection {\n return {\n primary,\n ...(filter !== undefined && { filter }),\n ...(enrichments !== undefined && enrichments.length > 0 && { enrichments }),\n };\n}\n\nconst selectionValue = computed<Selection | undefined>(() => {\n const primary = model.value?.primary;\n if (primary === undefined) return undefined;\n // Read enrichments from the current option, not from `model.value`: the\n // stored enrichments are a snapshot at selection time and won't match\n // `dropdownOptions` after `props.options` recomputes (e.g. when the\n // result pool gains or loses an enrichment column).\n const option = props.options?.find((o) => plRefsEqual(o.primary.ref, primary.column, true));\n return makeSelection(primary.column, primary.filter, option?.enrichments);\n});\n\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({\n label: o.primary.label,\n value: makeSelection(o.primary.ref, undefined, o.enrichments),\n });\n for (const filter of o.filters ?? []) {\n out.push({\n label: filter.label,\n description: o.primary.label,\n value: makeSelection(o.primary.ref, filter.ref, o.enrichments),\n });\n }\n }\n return out;\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 selection.enrichments,\n );\n}\n</script>\n\n<template>\n <PlDropdown\n data-testid=\"pl-dataset-selector\"\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDatasetSelector.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlDatasetSelector.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDatasetSelector/PlDatasetSelector.vue"],"names":[],"mappings":"AAoJA,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAGjB,MAAM,sBAAsB,CAAC;AAO9B;;;;;;;GAOG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY;IASd,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;;iBA6ET,gBAAgB,GAAG,SAAS;;;;IA9FrC,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;;iBA6ET,gBAAgB,GAAG,SAAS;;;;;WA3F7B,MAAM;aAFJ,QAAQ,CAAC,aAAa,EAAE,CAAC;YAI1B,MAAM;0BAEQ,MAAM;iBAIf,MAAM;eAER,OAAO;cAER,OAAO;cAEP,OAAO;;cAxBV,MAAM,OAAO;EAyMrB,CAAC;AAWL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -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 or one of its filters in a single dropdown, emitting a\n * {@link DatasetSelection}. Filter labels carry the dataset name as a\n * prefix (e.g. \"Bulk / Top 10\"), so no separate subtitle is rendered.\n * Enrichments from the matching `DatasetOption` are bundled into the\n * emitted value opaquely — block authors unbundle them in their args\n * resolver.\n */\nexport default {\n name: \"PlDatasetSelector\",\n};\n</script>\n\n<script lang=\"ts\" setup>\nimport type {\n DatasetOption,\n DatasetSelection,\n LabeledEnrichmentRefs,\n PlRef,\n} 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; enrichments?: LabeledEnrichmentRefs };\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 optional-key presence.\nfunction makeSelection(\n primary: PlRef,\n filter: PlRef | undefined,\n enrichments: LabeledEnrichmentRefs | undefined,\n): Selection {\n return {\n primary,\n ...(filter !== undefined && { filter }),\n ...(enrichments !== undefined && enrichments.length > 0 && { enrichments }),\n };\n}\n\nconst selectionValue = computed<Selection | undefined>(() => {\n const primary = model.value?.primary;\n if (primary === undefined) return undefined;\n // Read enrichments from the current option, not from `model.value`: the\n // stored enrichments are a snapshot at selection time and won't match\n // `dropdownOptions` after `props.options` recomputes (e.g. when the\n // result pool gains or loses an enrichment column).\n const option = props.options?.find((o) => plRefsEqual(o.primary.ref, primary.column, true));\n return makeSelection(primary.column, primary.filter, option?.enrichments);\n});\n\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({\n label: o.primary.label,\n value: makeSelection(o.primary.ref, undefined, o.enrichments),\n });\n for (const filter of o.filters ?? []) {\n out.push({\n label: filter.label,\n description: o.primary.label,\n value: makeSelection(o.primary.ref, filter.ref, o.enrichments),\n });\n }\n }\n return out;\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 selection.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":";;;;CAUE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBR,IAAM,IAAQ,GAEV,EAEE,IAAQ,EAAyC,GAAA,aAAE,EAEnD,IAAQ;EAuCd,SAAS,EACP,GACA,GACA,GACW;AACX,UAAO;IACL;IACA,GAAI,MAAW,KAAA,KAAa,EAAE,WAAQ;IACtC,GAAI,MAAgB,KAAA,KAAa,EAAY,SAAS,KAAK,EAAE,gBAAa;IAC3E;;EAGH,IAAM,IAAiB,QAAsC;GAC3D,IAAM,IAAU,EAAM,OAAO;AAC7B,OAAI,MAAY,KAAA,EAAW;GAK3B,IAAM,IAAS,EAAM,SAAS,MAAM,MAAM,EAAY,EAAE,QAAQ,KAAK,EAAQ,QAAQ,GAAK,CAAC;AAC3F,UAAO,EAAc,EAAQ,QAAQ,EAAQ,QAAQ,GAAQ,YAAY;IACzE,EAEI,IAAkB,QAAoD;AAC1E,OAAI,EAAM,YAAY,KAAA,EAAW;GACjC,IAAM,IAA+B,EAAE;AACvC,QAAK,IAAM,KAAK,EAAM,SAAS;AAC7B,MAAI,KAAK;KACP,OAAO,EAAE,QAAQ;KACjB,OAAO,EAAc,EAAE,QAAQ,KAAK,KAAA,GAAW,EAAE,YAAY;KAC9D,CAAC;AACF,SAAK,IAAM,KAAU,EAAE,WAAW,EAAE,CAClC,GAAI,KAAK;KACP,OAAO,EAAO;KACd,aAAa,EAAE,QAAQ;KACvB,OAAO,EAAc,EAAE,QAAQ,KAAK,EAAO,KAAK,EAAE,YAAY;KAC/D,CAAC;;AAGN,UAAO;IACP;EAEF,SAAS,EAAS,GAAkC;AAClD,OAAI,MAAc,KAAA,GAAW;AAC3B,MAAM,QAAQ,KAAA;AACd;;AAEF,KAAM,QAAQ,EACZ,EAAiB,EAAU,SAAS,EAAU,OAAO,EACrD,EAAU,YACX;;yBAKD,
|
|
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}. Filter labels carry the dataset name as a\n * prefix (e.g. \"Bulk / Top 10\"), so no separate subtitle is rendered.\n * Enrichments from the matching `DatasetOption` are bundled into the\n * emitted value opaquely — block authors unbundle them in their args\n * resolver.\n */\nexport default {\n name: \"PlDatasetSelector\",\n};\n</script>\n\n<script lang=\"ts\" setup>\nimport type {\n DatasetOption,\n DatasetSelection,\n LabeledEnrichmentRefs,\n PlRef,\n} 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; enrichments?: LabeledEnrichmentRefs };\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 optional-key presence.\nfunction makeSelection(\n primary: PlRef,\n filter: PlRef | undefined,\n enrichments: LabeledEnrichmentRefs | undefined,\n): Selection {\n return {\n primary,\n ...(filter !== undefined && { filter }),\n ...(enrichments !== undefined && enrichments.length > 0 && { enrichments }),\n };\n}\n\nconst selectionValue = computed<Selection | undefined>(() => {\n const primary = model.value?.primary;\n if (primary === undefined) return undefined;\n // Read enrichments from the current option, not from `model.value`: the\n // stored enrichments are a snapshot at selection time and won't match\n // `dropdownOptions` after `props.options` recomputes (e.g. when the\n // result pool gains or loses an enrichment column).\n const option = props.options?.find((o) => plRefsEqual(o.primary.ref, primary.column, true));\n return makeSelection(primary.column, primary.filter, option?.enrichments);\n});\n\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({\n label: o.primary.label,\n value: makeSelection(o.primary.ref, undefined, o.enrichments),\n });\n for (const filter of o.filters ?? []) {\n out.push({\n label: filter.label,\n description: o.primary.label,\n value: makeSelection(o.primary.ref, filter.ref, o.enrichments),\n });\n }\n }\n return out;\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 selection.enrichments,\n );\n}\n</script>\n\n<template>\n <PlDropdown\n data-testid=\"pl-dataset-selector\"\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":";;;;CAUE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBR,IAAM,IAAQ,GAEV,EAEE,IAAQ,EAAyC,GAAA,aAAE,EAEnD,IAAQ;EAuCd,SAAS,EACP,GACA,GACA,GACW;AACX,UAAO;IACL;IACA,GAAI,MAAW,KAAA,KAAa,EAAE,WAAQ;IACtC,GAAI,MAAgB,KAAA,KAAa,EAAY,SAAS,KAAK,EAAE,gBAAa;IAC3E;;EAGH,IAAM,IAAiB,QAAsC;GAC3D,IAAM,IAAU,EAAM,OAAO;AAC7B,OAAI,MAAY,KAAA,EAAW;GAK3B,IAAM,IAAS,EAAM,SAAS,MAAM,MAAM,EAAY,EAAE,QAAQ,KAAK,EAAQ,QAAQ,GAAK,CAAC;AAC3F,UAAO,EAAc,EAAQ,QAAQ,EAAQ,QAAQ,GAAQ,YAAY;IACzE,EAEI,IAAkB,QAAoD;AAC1E,OAAI,EAAM,YAAY,KAAA,EAAW;GACjC,IAAM,IAA+B,EAAE;AACvC,QAAK,IAAM,KAAK,EAAM,SAAS;AAC7B,MAAI,KAAK;KACP,OAAO,EAAE,QAAQ;KACjB,OAAO,EAAc,EAAE,QAAQ,KAAK,KAAA,GAAW,EAAE,YAAY;KAC9D,CAAC;AACF,SAAK,IAAM,KAAU,EAAE,WAAW,EAAE,CAClC,GAAI,KAAK;KACP,OAAO,EAAO;KACd,aAAa,EAAE,QAAQ;KACvB,OAAO,EAAc,EAAE,QAAQ,KAAK,EAAO,KAAK,EAAE,YAAY;KAC/D,CAAC;;AAGN,UAAO;IACP;EAEF,SAAS,EAAS,GAAkC;AAClD,OAAI,MAAc,KAAA,GAAW;AAC3B,MAAM,QAAQ,KAAA;AACd;;AAEF,KAAM,QAAQ,EACZ,EAAiB,EAAU,SAAS,EAAU,OAAO,EACrD,EAAU,YACX;;yBAKD,EAiBa,EAAA,EAAA,EAAA;GAhBX,eAAY;GACX,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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFastSearch.js","names":[],"sources":["../../../src/components/PlTableFastSearch/PlTableFastSearch.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { PlSearchField } from \"@milaboratories/uikit\";\n\nconst model = defineModel<string>({ required: true });\n</script>\n\n<template>\n <PlSearchField
|
|
1
|
+
{"version":3,"file":"PlTableFastSearch.js","names":[],"sources":["../../../src/components/PlTableFastSearch/PlTableFastSearch.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { PlSearchField } from \"@milaboratories/uikit\";\n\nconst model = defineModel<string>({ required: true });\n</script>\n\n<template>\n <PlSearchField\n v-model=\"model\"\n data-testid=\"pl-table-fast-search\"\n clearable\n placeholder=\"Search...\"\n >\n <template #helper>\n <b>How table search works:</b>\n <br />\n <ul>\n <li>\n <b>Exact match only.</b><br />\n No partials, wildcards, ranges, or regex.\n </li>\n <li>\n <b>Scope:</b> Searches all visible columns. To include a column, make it visible in\n Columns.\n </li>\n <li>\n <b>Text columns:</b> Exact string equality. Characters must match exactly (including case,\n spaces, and punctuation).\n </li>\n <li>\n <b>Number columns:</b> Exact numeric equality. 71 matches 71 and 71.0; it does not match\n 715 or 0.71/0.85.\n </li>\n </ul>\n <b>Examples:</b>\n <br />\n <ul>\n <li>CASSLDRGTEAFF → shows rows where any visible column equals that full string.</li>\n <li>85 → matches 85 / 85.0, not 0.85 or 850.</li>\n </ul>\n </template>\n </PlSearchField>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFastSearch.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlTableFastSearch/PlTableFastSearch.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlTableFastSearch.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlTableFastSearch/PlTableFastSearch.vue"],"names":[],"mappings":"AAmDA,KAAK,gBAAgB,GAAG;IACxB,UAAU,EAAE,MAAM,CAAC;CAClB,CAAC;AAwFF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFastSearch.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlTableFastSearch/PlTableFastSearch.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { PlSearchField } from \"@milaboratories/uikit\";\n\nconst model = defineModel<string>({ required: true });\n</script>\n\n<template>\n <PlSearchField
|
|
1
|
+
{"version":3,"file":"PlTableFastSearch.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlTableFastSearch/PlTableFastSearch.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { PlSearchField } from \"@milaboratories/uikit\";\n\nconst model = defineModel<string>({ required: true });\n</script>\n\n<template>\n <PlSearchField\n v-model=\"model\"\n data-testid=\"pl-table-fast-search\"\n clearable\n placeholder=\"Search...\"\n >\n <template #helper>\n <b>How table search works:</b>\n <br />\n <ul>\n <li>\n <b>Exact match only.</b><br />\n No partials, wildcards, ranges, or regex.\n </li>\n <li>\n <b>Scope:</b> Searches all visible columns. To include a column, make it visible in\n Columns.\n </li>\n <li>\n <b>Text columns:</b> Exact string equality. Characters must match exactly (including case,\n spaces, and punctuation).\n </li>\n <li>\n <b>Number columns:</b> Exact numeric equality. 71 matches 71 and 71.0; it does not match\n 715 or 0.71/0.85.\n </li>\n </ul>\n <b>Examples:</b>\n <br />\n <ul>\n <li>CASSLDRGTEAFF → shows rows where any visible column equals that full string.</li>\n <li>85 → matches 85 / 85.0, not 0.85 or 850.</li>\n </ul>\n </template>\n </PlSearchField>\n</template>\n"],"mappings":";;;;;;;;;;;EAGA,IAAM,IAAQ,EAAmB,GAAA,aAAoB;yBAInD,EAkCgB,EAAA,EAAA,EAAA;eAjCL,EAAA;4CAAK,QAAA;GACd,eAAY;GACZ,WAAA;GACA,aAAY;;GAED,QAAM,QACe,CAAA,GAAA,AAAA,EAAA,OAAA;IAA9B,EAA8B,KAAA,MAA3B,2BAAuB,GAAA;IAC1B,EAAM,MAAA,MAAA,MAAA,GAAA;IACN,EAiBK,MAAA,MAAA;KAhBH,EAGK,MAAA,MAAA;MAFH,EAAwB,KAAA,MAArB,oBAAiB;MAAI,EAAM,KAAA;QAAA,8CAEhC;;KACA,EAGK,MAAA,MAAA,CAFH,EAAa,KAAA,MAAV,SAAM,EAAA,EAAI,mFAEf,CAAA,CAAA;KACA,EAGK,MAAA,MAAA,CAFH,EAAoB,KAAA,MAAjB,gBAAa,EAAA,EAAI,oGAEtB,CAAA,CAAA;KACA,EAGK,MAAA,MAAA,CAFH,EAAsB,KAAA,MAAnB,kBAAe,EAAA,EAAI,wFAExB,CAAA,CAAA;;IAEF,EAAgB,KAAA,MAAb,aAAS,GAAA;IACZ,EAAM,MAAA,MAAA,MAAA,GAAA;IACN,EAGK,MAAA,MAAA,CAFH,EAAqF,MAAA,MAAjF,+EAA4E,EAChF,EAAiD,MAAA,MAA7C,2CAAwC,CAAA,EAAA,GAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFiltersV2.js","names":[],"sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type {\n PTableColumnSpec,\n PlDataTableFiltersWithMeta,\n PFrameHandle,\n PTableColumnId,\n PColumnSpec,\n} from \"@platforma-sdk/model\";\nimport {\n Annotation,\n Domain,\n readAnnotation,\n readDomain,\n getUniqueSourceValuesWithLabels,\n extractPObjectId,\n getPTableColumnId,\n deriveDistinctLabels,\n} from \"@platforma-sdk/model\";\nimport { computed, ref } from \"vue\";\nimport { PlBtnGhost, PlSlideModal, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport {\n PlAdvancedFilter,\n PlAdvancedFilterComponent,\n PlAdvancedFilterSupportedFilters,\n type PlAdvancedFilterItem,\n} from \"../PlAdvancedFilter\";\nimport type { PlAdvancedFilterColumnId } from \"../PlAdvancedFilter/types\";\nimport type { Nil } from \"@milaboratories/helpers\";\nimport { isFunction, isNil } from \"es-toolkit\";\n\nconst props = defineProps<{\n columns: PTableColumnSpec[];\n pframeHandle: Nil | PFrameHandle;\n filters: PlDataTableFiltersWithMeta;\n defaultFilters: Nil | PlDataTableFiltersWithMeta;\n onUpdateFilters: (value: PlDataTableFiltersWithMeta) => void;\n onResetDefaultFilters?: () => void;\n onUpdateDefaultFilters?: (value: PlDataTableFiltersWithMeta) => void;\n}>();\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlTableFiltersV2\");\nconst showManager = ref(false);\nconst hasFilters = computed(() => props.filters.filters.length > 0);\nconst hasDefaultFilters = computed(\n () => !isNil(props.defaultFilters) && props.defaultFilters.filters.length > 0,\n);\nconst filters = computed<PlDataTableFiltersWithMeta>(() => {\n if (isNil(props.defaultFilters) || props.defaultFilters?.filters.length === 0) {\n return props.filters;\n }\n\n return {\n ...props.filters,\n filters: [...(props.defaultFilters?.filters ?? []), ...props.filters.filters],\n };\n});\nconst onUpdateFilters = (_value: PlAdvancedFilter) => {\n const value = _value as PlDataTableFiltersWithMeta;\n\n if (isNil(props.defaultFilters)) {\n return props.onUpdateFilters(value);\n }\n\n const [defaults, ...rest] = value.filters;\n props.onUpdateFilters({ ...value, filters: rest });\n props.onUpdateDefaultFilters?.({ ...props.defaultFilters, filters: [defaults] });\n};\n\nconst options = computed<PlAdvancedFilterItem[]>(() => {\n const columnEntries: { idx: number; spec: PColumnSpec }[] = [];\n props.columns.forEach((col, idx) => {\n if (col.type === \"column\") columnEntries.push({ idx, spec: col.spec });\n });\n const distinctLabelByIdx = new Map<number, string>();\n deriveDistinctLabels(\n columnEntries.map((e) => e.spec),\n {},\n ).forEach((label, i) => distinctLabelByIdx.set(columnEntries[i].idx, label));\n\n return props.columns.map((col, idx) => {\n const id = getPTableColumnId(col);\n const label =\n distinctLabelByIdx.get(idx)?.trim() ||\n readAnnotation(col.spec, Annotation.Label)?.trim() ||\n `Unlabeled ${col.type} ${idx}`;\n const alphabet =\n readDomain(col.spec, Domain.Alphabet) ?? readAnnotation(col.spec, Annotation.Alphabet);\n return {\n id,\n label,\n spec: col.spec,\n alphabet: alphabet ?? undefined,\n };\n });\n});\n\n// Supported filters (same set as FilterSidebar)\nconst supportedFilters = [\n \"isNA\",\n \"isNotNA\",\n \"greaterThan\",\n \"greaterThanOrEqual\",\n \"lessThan\",\n \"lessThanOrEqual\",\n \"patternEquals\",\n \"patternNotEquals\",\n \"patternContainSubsequence\",\n \"patternNotContainSubsequence\",\n \"patternMatchesRegularExpression\",\n \"patternFuzzyContainSubsequence\",\n \"equal\",\n \"notEqual\",\n] as (typeof PlAdvancedFilterSupportedFilters)[number][];\n\n// getSuggestOptions - provide discrete values from column annotations\nfunction handleSuggestOptions(params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n}) {\n if (isNil(props.pframeHandle)) {\n console.warn(\"PFrame handle is not available, cannot fetch suggest options\");\n return [];\n }\n\n const tableColumnId = params.columnId as PTableColumnId;\n if (\n typeof tableColumnId !== \"object\" ||\n tableColumnId === null ||\n tableColumnId.type !== \"column\"\n ) {\n throw new Error(\"ColumnId should be of type 'column' for suggest options\");\n }\n\n return getUniqueSourceValuesWithLabels(props.pframeHandle, {\n columnId: extractPObjectId(tableColumnId.id),\n axisIdx: params.axisIdx,\n limit: 100,\n searchQuery: params.searchType === \"label\" ? params.searchStr : undefined,\n searchQueryValue: params.searchType === \"value\" ? params.searchStr : undefined,\n }).then((v) => v.values);\n}\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget\" :to=\"teleportTarget\">\n <PlBtnGhost\n :icon=\"hasFilters || hasDefaultFilters ? 'filter-on' : 'filter'\"\n @click.stop=\"showManager = true\"\n >\n Filters\n </PlBtnGhost>\n </Teleport>\n\n <PlSlideModal
|
|
1
|
+
{"version":3,"file":"PlTableFiltersV2.js","names":[],"sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type {\n PTableColumnSpec,\n PlDataTableFiltersWithMeta,\n PFrameHandle,\n PTableColumnId,\n PColumnSpec,\n} from \"@platforma-sdk/model\";\nimport {\n Annotation,\n Domain,\n readAnnotation,\n readDomain,\n getUniqueSourceValuesWithLabels,\n extractPObjectId,\n getPTableColumnId,\n deriveDistinctLabels,\n} from \"@platforma-sdk/model\";\nimport { computed, ref } from \"vue\";\nimport { PlBtnGhost, PlSlideModal, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport {\n PlAdvancedFilter,\n PlAdvancedFilterComponent,\n PlAdvancedFilterSupportedFilters,\n type PlAdvancedFilterItem,\n} from \"../PlAdvancedFilter\";\nimport type { PlAdvancedFilterColumnId } from \"../PlAdvancedFilter/types\";\nimport type { Nil } from \"@milaboratories/helpers\";\nimport { isFunction, isNil } from \"es-toolkit\";\n\nconst props = defineProps<{\n columns: PTableColumnSpec[];\n pframeHandle: Nil | PFrameHandle;\n filters: PlDataTableFiltersWithMeta;\n defaultFilters: Nil | PlDataTableFiltersWithMeta;\n onUpdateFilters: (value: PlDataTableFiltersWithMeta) => void;\n onResetDefaultFilters?: () => void;\n onUpdateDefaultFilters?: (value: PlDataTableFiltersWithMeta) => void;\n}>();\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlTableFiltersV2\");\nconst showManager = ref(false);\nconst hasFilters = computed(() => props.filters.filters.length > 0);\nconst hasDefaultFilters = computed(\n () => !isNil(props.defaultFilters) && props.defaultFilters.filters.length > 0,\n);\nconst filters = computed<PlDataTableFiltersWithMeta>(() => {\n if (isNil(props.defaultFilters) || props.defaultFilters?.filters.length === 0) {\n return props.filters;\n }\n\n return {\n ...props.filters,\n filters: [...(props.defaultFilters?.filters ?? []), ...props.filters.filters],\n };\n});\nconst onUpdateFilters = (_value: PlAdvancedFilter) => {\n const value = _value as PlDataTableFiltersWithMeta;\n\n if (isNil(props.defaultFilters)) {\n return props.onUpdateFilters(value);\n }\n\n const [defaults, ...rest] = value.filters;\n props.onUpdateFilters({ ...value, filters: rest });\n props.onUpdateDefaultFilters?.({ ...props.defaultFilters, filters: [defaults] });\n};\n\nconst options = computed<PlAdvancedFilterItem[]>(() => {\n const columnEntries: { idx: number; spec: PColumnSpec }[] = [];\n props.columns.forEach((col, idx) => {\n if (col.type === \"column\") columnEntries.push({ idx, spec: col.spec });\n });\n const distinctLabelByIdx = new Map<number, string>();\n deriveDistinctLabels(\n columnEntries.map((e) => e.spec),\n {},\n ).forEach((label, i) => distinctLabelByIdx.set(columnEntries[i].idx, label));\n\n return props.columns.map((col, idx) => {\n const id = getPTableColumnId(col);\n const label =\n distinctLabelByIdx.get(idx)?.trim() ||\n readAnnotation(col.spec, Annotation.Label)?.trim() ||\n `Unlabeled ${col.type} ${idx}`;\n const alphabet =\n readDomain(col.spec, Domain.Alphabet) ?? readAnnotation(col.spec, Annotation.Alphabet);\n return {\n id,\n label,\n spec: col.spec,\n alphabet: alphabet ?? undefined,\n };\n });\n});\n\n// Supported filters (same set as FilterSidebar)\nconst supportedFilters = [\n \"isNA\",\n \"isNotNA\",\n \"greaterThan\",\n \"greaterThanOrEqual\",\n \"lessThan\",\n \"lessThanOrEqual\",\n \"patternEquals\",\n \"patternNotEquals\",\n \"patternContainSubsequence\",\n \"patternNotContainSubsequence\",\n \"patternMatchesRegularExpression\",\n \"patternFuzzyContainSubsequence\",\n \"equal\",\n \"notEqual\",\n] as (typeof PlAdvancedFilterSupportedFilters)[number][];\n\n// getSuggestOptions - provide discrete values from column annotations\nfunction handleSuggestOptions(params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n}) {\n if (isNil(props.pframeHandle)) {\n console.warn(\"PFrame handle is not available, cannot fetch suggest options\");\n return [];\n }\n\n const tableColumnId = params.columnId as PTableColumnId;\n if (\n typeof tableColumnId !== \"object\" ||\n tableColumnId === null ||\n tableColumnId.type !== \"column\"\n ) {\n throw new Error(\"ColumnId should be of type 'column' for suggest options\");\n }\n\n return getUniqueSourceValuesWithLabels(props.pframeHandle, {\n columnId: extractPObjectId(tableColumnId.id),\n axisIdx: params.axisIdx,\n limit: 100,\n searchQuery: params.searchType === \"label\" ? params.searchStr : undefined,\n searchQueryValue: params.searchType === \"value\" ? params.searchStr : undefined,\n }).then((v) => v.values);\n}\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget\" :to=\"teleportTarget\">\n <PlBtnGhost\n data-testid=\"pl-table-filters\"\n :icon=\"hasFilters || hasDefaultFilters ? 'filter-on' : 'filter'\"\n @click.stop=\"showManager = true\"\n >\n Filters\n </PlBtnGhost>\n </Teleport>\n\n <PlSlideModal\n v-model=\"showManager\"\n data-testid=\"pl-table-filters-panel\"\n :close-on-outside-click=\"false\"\n >\n <template #title>Manage Filters</template>\n\n <div data-testid=\"pl-table-filters-content\" :class=\"$style.root\">\n <PlAdvancedFilterComponent\n :filters=\"filters as PlAdvancedFilter\"\n :options=\"options\"\n :supported-filters=\"supportedFilters\"\n :get-suggest-options=\"handleSuggestOptions\"\n :is-pinned=\"(_, index) => hasDefaultFilters && index === 0\"\n :is-removable=\"(_, index) => (hasDefaultFilters ? index > 0 : true)\"\n :is-draggable=\"(_, index) => (hasDefaultFilters ? index > 0 : true)\"\n :enable-dnd=\"false\"\n :enable-toggling=\"true\"\n :enable-add-group-button=\"true\"\n @update-filters=\"onUpdateFilters\"\n >\n <template #group-title=\"{ index }\">\n <div\n v-if=\"hasDefaultFilters && index === 0\"\n data-testid=\"pl-table-filters-default-group-title\"\n :class=\"$style.defaultGroupTitle\"\n >\n Default Group\n <PlBtnGhost\n v-if=\"isFunction(props.onResetDefaultFilters)\"\n data-testid=\"pl-table-filters-reset-default\"\n icon=\"restart\"\n :class=\"$style.restartBtn\"\n @click.stop=\"props.onResetDefaultFilters()\"\n />\n </div>\n <div v-else data-testid=\"pl-table-filters-custom-group-title\">Custom Group</div>\n </template>\n </PlAdvancedFilterComponent>\n </div>\n </PlSlideModal>\n</template>\n\n<style module>\n.root {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.defaultGroupTitle {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.restartBtn {\n width: 24px;\n height: 24px;\n padding: 4px;\n --button-width: 24px;\n --btn-min-width: 24px;\n --button-height: 24px;\n --btn-min-height: 24x;\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFiltersV2.vue_vue_type_style_index_0_lang.module.js","names":[],"sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type {\n PTableColumnSpec,\n PlDataTableFiltersWithMeta,\n PFrameHandle,\n PTableColumnId,\n PColumnSpec,\n} from \"@platforma-sdk/model\";\nimport {\n Annotation,\n Domain,\n readAnnotation,\n readDomain,\n getUniqueSourceValuesWithLabels,\n extractPObjectId,\n getPTableColumnId,\n deriveDistinctLabels,\n} from \"@platforma-sdk/model\";\nimport { computed, ref } from \"vue\";\nimport { PlBtnGhost, PlSlideModal, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport {\n PlAdvancedFilter,\n PlAdvancedFilterComponent,\n PlAdvancedFilterSupportedFilters,\n type PlAdvancedFilterItem,\n} from \"../PlAdvancedFilter\";\nimport type { PlAdvancedFilterColumnId } from \"../PlAdvancedFilter/types\";\nimport type { Nil } from \"@milaboratories/helpers\";\nimport { isFunction, isNil } from \"es-toolkit\";\n\nconst props = defineProps<{\n columns: PTableColumnSpec[];\n pframeHandle: Nil | PFrameHandle;\n filters: PlDataTableFiltersWithMeta;\n defaultFilters: Nil | PlDataTableFiltersWithMeta;\n onUpdateFilters: (value: PlDataTableFiltersWithMeta) => void;\n onResetDefaultFilters?: () => void;\n onUpdateDefaultFilters?: (value: PlDataTableFiltersWithMeta) => void;\n}>();\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlTableFiltersV2\");\nconst showManager = ref(false);\nconst hasFilters = computed(() => props.filters.filters.length > 0);\nconst hasDefaultFilters = computed(\n () => !isNil(props.defaultFilters) && props.defaultFilters.filters.length > 0,\n);\nconst filters = computed<PlDataTableFiltersWithMeta>(() => {\n if (isNil(props.defaultFilters) || props.defaultFilters?.filters.length === 0) {\n return props.filters;\n }\n\n return {\n ...props.filters,\n filters: [...(props.defaultFilters?.filters ?? []), ...props.filters.filters],\n };\n});\nconst onUpdateFilters = (_value: PlAdvancedFilter) => {\n const value = _value as PlDataTableFiltersWithMeta;\n\n if (isNil(props.defaultFilters)) {\n return props.onUpdateFilters(value);\n }\n\n const [defaults, ...rest] = value.filters;\n props.onUpdateFilters({ ...value, filters: rest });\n props.onUpdateDefaultFilters?.({ ...props.defaultFilters, filters: [defaults] });\n};\n\nconst options = computed<PlAdvancedFilterItem[]>(() => {\n const columnEntries: { idx: number; spec: PColumnSpec }[] = [];\n props.columns.forEach((col, idx) => {\n if (col.type === \"column\") columnEntries.push({ idx, spec: col.spec });\n });\n const distinctLabelByIdx = new Map<number, string>();\n deriveDistinctLabels(\n columnEntries.map((e) => e.spec),\n {},\n ).forEach((label, i) => distinctLabelByIdx.set(columnEntries[i].idx, label));\n\n return props.columns.map((col, idx) => {\n const id = getPTableColumnId(col);\n const label =\n distinctLabelByIdx.get(idx)?.trim() ||\n readAnnotation(col.spec, Annotation.Label)?.trim() ||\n `Unlabeled ${col.type} ${idx}`;\n const alphabet =\n readDomain(col.spec, Domain.Alphabet) ?? readAnnotation(col.spec, Annotation.Alphabet);\n return {\n id,\n label,\n spec: col.spec,\n alphabet: alphabet ?? undefined,\n };\n });\n});\n\n// Supported filters (same set as FilterSidebar)\nconst supportedFilters = [\n \"isNA\",\n \"isNotNA\",\n \"greaterThan\",\n \"greaterThanOrEqual\",\n \"lessThan\",\n \"lessThanOrEqual\",\n \"patternEquals\",\n \"patternNotEquals\",\n \"patternContainSubsequence\",\n \"patternNotContainSubsequence\",\n \"patternMatchesRegularExpression\",\n \"patternFuzzyContainSubsequence\",\n \"equal\",\n \"notEqual\",\n] as (typeof PlAdvancedFilterSupportedFilters)[number][];\n\n// getSuggestOptions - provide discrete values from column annotations\nfunction handleSuggestOptions(params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n}) {\n if (isNil(props.pframeHandle)) {\n console.warn(\"PFrame handle is not available, cannot fetch suggest options\");\n return [];\n }\n\n const tableColumnId = params.columnId as PTableColumnId;\n if (\n typeof tableColumnId !== \"object\" ||\n tableColumnId === null ||\n tableColumnId.type !== \"column\"\n ) {\n throw new Error(\"ColumnId should be of type 'column' for suggest options\");\n }\n\n return getUniqueSourceValuesWithLabels(props.pframeHandle, {\n columnId: extractPObjectId(tableColumnId.id),\n axisIdx: params.axisIdx,\n limit: 100,\n searchQuery: params.searchType === \"label\" ? params.searchStr : undefined,\n searchQueryValue: params.searchType === \"value\" ? params.searchStr : undefined,\n }).then((v) => v.values);\n}\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget\" :to=\"teleportTarget\">\n <PlBtnGhost\n :icon=\"hasFilters || hasDefaultFilters ? 'filter-on' : 'filter'\"\n @click.stop=\"showManager = true\"\n >\n Filters\n </PlBtnGhost>\n </Teleport>\n\n <PlSlideModal
|
|
1
|
+
{"version":3,"file":"PlTableFiltersV2.vue_vue_type_style_index_0_lang.module.js","names":[],"sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type {\n PTableColumnSpec,\n PlDataTableFiltersWithMeta,\n PFrameHandle,\n PTableColumnId,\n PColumnSpec,\n} from \"@platforma-sdk/model\";\nimport {\n Annotation,\n Domain,\n readAnnotation,\n readDomain,\n getUniqueSourceValuesWithLabels,\n extractPObjectId,\n getPTableColumnId,\n deriveDistinctLabels,\n} from \"@platforma-sdk/model\";\nimport { computed, ref } from \"vue\";\nimport { PlBtnGhost, PlSlideModal, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport {\n PlAdvancedFilter,\n PlAdvancedFilterComponent,\n PlAdvancedFilterSupportedFilters,\n type PlAdvancedFilterItem,\n} from \"../PlAdvancedFilter\";\nimport type { PlAdvancedFilterColumnId } from \"../PlAdvancedFilter/types\";\nimport type { Nil } from \"@milaboratories/helpers\";\nimport { isFunction, isNil } from \"es-toolkit\";\n\nconst props = defineProps<{\n columns: PTableColumnSpec[];\n pframeHandle: Nil | PFrameHandle;\n filters: PlDataTableFiltersWithMeta;\n defaultFilters: Nil | PlDataTableFiltersWithMeta;\n onUpdateFilters: (value: PlDataTableFiltersWithMeta) => void;\n onResetDefaultFilters?: () => void;\n onUpdateDefaultFilters?: (value: PlDataTableFiltersWithMeta) => void;\n}>();\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlTableFiltersV2\");\nconst showManager = ref(false);\nconst hasFilters = computed(() => props.filters.filters.length > 0);\nconst hasDefaultFilters = computed(\n () => !isNil(props.defaultFilters) && props.defaultFilters.filters.length > 0,\n);\nconst filters = computed<PlDataTableFiltersWithMeta>(() => {\n if (isNil(props.defaultFilters) || props.defaultFilters?.filters.length === 0) {\n return props.filters;\n }\n\n return {\n ...props.filters,\n filters: [...(props.defaultFilters?.filters ?? []), ...props.filters.filters],\n };\n});\nconst onUpdateFilters = (_value: PlAdvancedFilter) => {\n const value = _value as PlDataTableFiltersWithMeta;\n\n if (isNil(props.defaultFilters)) {\n return props.onUpdateFilters(value);\n }\n\n const [defaults, ...rest] = value.filters;\n props.onUpdateFilters({ ...value, filters: rest });\n props.onUpdateDefaultFilters?.({ ...props.defaultFilters, filters: [defaults] });\n};\n\nconst options = computed<PlAdvancedFilterItem[]>(() => {\n const columnEntries: { idx: number; spec: PColumnSpec }[] = [];\n props.columns.forEach((col, idx) => {\n if (col.type === \"column\") columnEntries.push({ idx, spec: col.spec });\n });\n const distinctLabelByIdx = new Map<number, string>();\n deriveDistinctLabels(\n columnEntries.map((e) => e.spec),\n {},\n ).forEach((label, i) => distinctLabelByIdx.set(columnEntries[i].idx, label));\n\n return props.columns.map((col, idx) => {\n const id = getPTableColumnId(col);\n const label =\n distinctLabelByIdx.get(idx)?.trim() ||\n readAnnotation(col.spec, Annotation.Label)?.trim() ||\n `Unlabeled ${col.type} ${idx}`;\n const alphabet =\n readDomain(col.spec, Domain.Alphabet) ?? readAnnotation(col.spec, Annotation.Alphabet);\n return {\n id,\n label,\n spec: col.spec,\n alphabet: alphabet ?? undefined,\n };\n });\n});\n\n// Supported filters (same set as FilterSidebar)\nconst supportedFilters = [\n \"isNA\",\n \"isNotNA\",\n \"greaterThan\",\n \"greaterThanOrEqual\",\n \"lessThan\",\n \"lessThanOrEqual\",\n \"patternEquals\",\n \"patternNotEquals\",\n \"patternContainSubsequence\",\n \"patternNotContainSubsequence\",\n \"patternMatchesRegularExpression\",\n \"patternFuzzyContainSubsequence\",\n \"equal\",\n \"notEqual\",\n] as (typeof PlAdvancedFilterSupportedFilters)[number][];\n\n// getSuggestOptions - provide discrete values from column annotations\nfunction handleSuggestOptions(params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n}) {\n if (isNil(props.pframeHandle)) {\n console.warn(\"PFrame handle is not available, cannot fetch suggest options\");\n return [];\n }\n\n const tableColumnId = params.columnId as PTableColumnId;\n if (\n typeof tableColumnId !== \"object\" ||\n tableColumnId === null ||\n tableColumnId.type !== \"column\"\n ) {\n throw new Error(\"ColumnId should be of type 'column' for suggest options\");\n }\n\n return getUniqueSourceValuesWithLabels(props.pframeHandle, {\n columnId: extractPObjectId(tableColumnId.id),\n axisIdx: params.axisIdx,\n limit: 100,\n searchQuery: params.searchType === \"label\" ? params.searchStr : undefined,\n searchQueryValue: params.searchType === \"value\" ? params.searchStr : undefined,\n }).then((v) => v.values);\n}\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget\" :to=\"teleportTarget\">\n <PlBtnGhost\n data-testid=\"pl-table-filters\"\n :icon=\"hasFilters || hasDefaultFilters ? 'filter-on' : 'filter'\"\n @click.stop=\"showManager = true\"\n >\n Filters\n </PlBtnGhost>\n </Teleport>\n\n <PlSlideModal\n v-model=\"showManager\"\n data-testid=\"pl-table-filters-panel\"\n :close-on-outside-click=\"false\"\n >\n <template #title>Manage Filters</template>\n\n <div data-testid=\"pl-table-filters-content\" :class=\"$style.root\">\n <PlAdvancedFilterComponent\n :filters=\"filters as PlAdvancedFilter\"\n :options=\"options\"\n :supported-filters=\"supportedFilters\"\n :get-suggest-options=\"handleSuggestOptions\"\n :is-pinned=\"(_, index) => hasDefaultFilters && index === 0\"\n :is-removable=\"(_, index) => (hasDefaultFilters ? index > 0 : true)\"\n :is-draggable=\"(_, index) => (hasDefaultFilters ? index > 0 : true)\"\n :enable-dnd=\"false\"\n :enable-toggling=\"true\"\n :enable-add-group-button=\"true\"\n @update-filters=\"onUpdateFilters\"\n >\n <template #group-title=\"{ index }\">\n <div\n v-if=\"hasDefaultFilters && index === 0\"\n data-testid=\"pl-table-filters-default-group-title\"\n :class=\"$style.defaultGroupTitle\"\n >\n Default Group\n <PlBtnGhost\n v-if=\"isFunction(props.onResetDefaultFilters)\"\n data-testid=\"pl-table-filters-reset-default\"\n icon=\"restart\"\n :class=\"$style.restartBtn\"\n @click.stop=\"props.onResetDefaultFilters()\"\n />\n </div>\n <div v-else data-testid=\"pl-table-filters-custom-group-title\">Custom Group</div>\n </template>\n </PlAdvancedFilterComponent>\n </div>\n </PlSlideModal>\n</template>\n\n<style module>\n.root {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.defaultGroupTitle {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.restartBtn {\n width: 24px;\n height: 24px;\n padding: 4px;\n --button-width: 24px;\n --btn-min-width: 24px;\n --button-height: 24px;\n --btn-min-height: 24x;\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFiltersV2.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlTableFiltersV2.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"names":[],"mappings":"AA+NA,OAAO,KAAK,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,YAAY,EAGb,MAAM,sBAAsB,CAAC;AAoB9B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAGnD,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,YAAY,EAAE,GAAG,GAAG,YAAY,CAAC;IACjC,OAAO,EAAE,0BAA0B,CAAC;IACpC,cAAc,EAAE,GAAG,GAAG,0BAA0B,CAAC;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC7D,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;CACtE,CAAC;AAiTF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -5,7 +5,10 @@ import { Annotation as _, Domain as v, deriveDistinctLabels as y, extractPObject
|
|
|
5
5
|
import { isFunction as T, isNil as E } from "es-toolkit";
|
|
6
6
|
import { PlBtnGhost as D, PlSlideModal as O, usePlBlockPageTitleTeleportTarget as k } from "@milaboratories/uikit";
|
|
7
7
|
//#region src/components/PlTableFilters/PlTableFiltersV2.vue?vue&type=script&setup=true&lang.ts
|
|
8
|
-
var A = {
|
|
8
|
+
var A = {
|
|
9
|
+
key: 1,
|
|
10
|
+
"data-testid": "pl-table-filters-custom-group-title"
|
|
11
|
+
}, j = /* @__PURE__ */ u({
|
|
9
12
|
__name: "PlTableFiltersV2",
|
|
10
13
|
props: {
|
|
11
14
|
columns: {},
|
|
@@ -81,6 +84,7 @@ var A = { key: 1 }, j = /* @__PURE__ */ u({
|
|
|
81
84
|
key: 0,
|
|
82
85
|
to: m(M)
|
|
83
86
|
}, [l(m(D), {
|
|
87
|
+
"data-testid": "pl-table-filters",
|
|
84
88
|
icon: P.value || F.value ? "filter-on" : "filter",
|
|
85
89
|
onClick: u[0] ||= g((e) => N.value = !0, ["stop"])
|
|
86
90
|
}, {
|
|
@@ -89,10 +93,14 @@ var A = { key: 1 }, j = /* @__PURE__ */ u({
|
|
|
89
93
|
}, 8, ["icon"])], 8, ["to"])) : a("", !0), l(m(O), {
|
|
90
94
|
modelValue: N.value,
|
|
91
95
|
"onUpdate:modelValue": u[2] ||= (e) => N.value = e,
|
|
96
|
+
"data-testid": "pl-table-filters-panel",
|
|
92
97
|
"close-on-outside-click": !1
|
|
93
98
|
}, {
|
|
94
99
|
title: h(() => [...u[4] ||= [c("Manage Filters", -1)]]),
|
|
95
|
-
default: h(() => [s("div", {
|
|
100
|
+
default: h(() => [s("div", {
|
|
101
|
+
"data-testid": "pl-table-filters-content",
|
|
102
|
+
class: d(r.$style.root)
|
|
103
|
+
}, [l(m(e), {
|
|
96
104
|
filters: I.value,
|
|
97
105
|
options: R.value,
|
|
98
106
|
"supported-filters": z,
|
|
@@ -107,9 +115,11 @@ var A = { key: 1 }, j = /* @__PURE__ */ u({
|
|
|
107
115
|
}, {
|
|
108
116
|
"group-title": h(({ index: e }) => [F.value && e === 0 ? (f(), o("div", {
|
|
109
117
|
key: 0,
|
|
118
|
+
"data-testid": "pl-table-filters-default-group-title",
|
|
110
119
|
class: d(r.$style.defaultGroupTitle)
|
|
111
120
|
}, [u[5] ||= c(" Default Group ", -1), m(T)(j.onResetDefaultFilters) ? (f(), i(m(D), {
|
|
112
121
|
key: 0,
|
|
122
|
+
"data-testid": "pl-table-filters-reset-default",
|
|
113
123
|
icon: "restart",
|
|
114
124
|
class: d(r.$style.restartBtn),
|
|
115
125
|
onClick: u[1] ||= g((e) => j.onResetDefaultFilters(), ["stop"])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFiltersV2.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type {\n PTableColumnSpec,\n PlDataTableFiltersWithMeta,\n PFrameHandle,\n PTableColumnId,\n PColumnSpec,\n} from \"@platforma-sdk/model\";\nimport {\n Annotation,\n Domain,\n readAnnotation,\n readDomain,\n getUniqueSourceValuesWithLabels,\n extractPObjectId,\n getPTableColumnId,\n deriveDistinctLabels,\n} from \"@platforma-sdk/model\";\nimport { computed, ref } from \"vue\";\nimport { PlBtnGhost, PlSlideModal, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport {\n PlAdvancedFilter,\n PlAdvancedFilterComponent,\n PlAdvancedFilterSupportedFilters,\n type PlAdvancedFilterItem,\n} from \"../PlAdvancedFilter\";\nimport type { PlAdvancedFilterColumnId } from \"../PlAdvancedFilter/types\";\nimport type { Nil } from \"@milaboratories/helpers\";\nimport { isFunction, isNil } from \"es-toolkit\";\n\nconst props = defineProps<{\n columns: PTableColumnSpec[];\n pframeHandle: Nil | PFrameHandle;\n filters: PlDataTableFiltersWithMeta;\n defaultFilters: Nil | PlDataTableFiltersWithMeta;\n onUpdateFilters: (value: PlDataTableFiltersWithMeta) => void;\n onResetDefaultFilters?: () => void;\n onUpdateDefaultFilters?: (value: PlDataTableFiltersWithMeta) => void;\n}>();\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlTableFiltersV2\");\nconst showManager = ref(false);\nconst hasFilters = computed(() => props.filters.filters.length > 0);\nconst hasDefaultFilters = computed(\n () => !isNil(props.defaultFilters) && props.defaultFilters.filters.length > 0,\n);\nconst filters = computed<PlDataTableFiltersWithMeta>(() => {\n if (isNil(props.defaultFilters) || props.defaultFilters?.filters.length === 0) {\n return props.filters;\n }\n\n return {\n ...props.filters,\n filters: [...(props.defaultFilters?.filters ?? []), ...props.filters.filters],\n };\n});\nconst onUpdateFilters = (_value: PlAdvancedFilter) => {\n const value = _value as PlDataTableFiltersWithMeta;\n\n if (isNil(props.defaultFilters)) {\n return props.onUpdateFilters(value);\n }\n\n const [defaults, ...rest] = value.filters;\n props.onUpdateFilters({ ...value, filters: rest });\n props.onUpdateDefaultFilters?.({ ...props.defaultFilters, filters: [defaults] });\n};\n\nconst options = computed<PlAdvancedFilterItem[]>(() => {\n const columnEntries: { idx: number; spec: PColumnSpec }[] = [];\n props.columns.forEach((col, idx) => {\n if (col.type === \"column\") columnEntries.push({ idx, spec: col.spec });\n });\n const distinctLabelByIdx = new Map<number, string>();\n deriveDistinctLabels(\n columnEntries.map((e) => e.spec),\n {},\n ).forEach((label, i) => distinctLabelByIdx.set(columnEntries[i].idx, label));\n\n return props.columns.map((col, idx) => {\n const id = getPTableColumnId(col);\n const label =\n distinctLabelByIdx.get(idx)?.trim() ||\n readAnnotation(col.spec, Annotation.Label)?.trim() ||\n `Unlabeled ${col.type} ${idx}`;\n const alphabet =\n readDomain(col.spec, Domain.Alphabet) ?? readAnnotation(col.spec, Annotation.Alphabet);\n return {\n id,\n label,\n spec: col.spec,\n alphabet: alphabet ?? undefined,\n };\n });\n});\n\n// Supported filters (same set as FilterSidebar)\nconst supportedFilters = [\n \"isNA\",\n \"isNotNA\",\n \"greaterThan\",\n \"greaterThanOrEqual\",\n \"lessThan\",\n \"lessThanOrEqual\",\n \"patternEquals\",\n \"patternNotEquals\",\n \"patternContainSubsequence\",\n \"patternNotContainSubsequence\",\n \"patternMatchesRegularExpression\",\n \"patternFuzzyContainSubsequence\",\n \"equal\",\n \"notEqual\",\n] as (typeof PlAdvancedFilterSupportedFilters)[number][];\n\n// getSuggestOptions - provide discrete values from column annotations\nfunction handleSuggestOptions(params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n}) {\n if (isNil(props.pframeHandle)) {\n console.warn(\"PFrame handle is not available, cannot fetch suggest options\");\n return [];\n }\n\n const tableColumnId = params.columnId as PTableColumnId;\n if (\n typeof tableColumnId !== \"object\" ||\n tableColumnId === null ||\n tableColumnId.type !== \"column\"\n ) {\n throw new Error(\"ColumnId should be of type 'column' for suggest options\");\n }\n\n return getUniqueSourceValuesWithLabels(props.pframeHandle, {\n columnId: extractPObjectId(tableColumnId.id),\n axisIdx: params.axisIdx,\n limit: 100,\n searchQuery: params.searchType === \"label\" ? params.searchStr : undefined,\n searchQueryValue: params.searchType === \"value\" ? params.searchStr : undefined,\n }).then((v) => v.values);\n}\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget\" :to=\"teleportTarget\">\n <PlBtnGhost\n :icon=\"hasFilters || hasDefaultFilters ? 'filter-on' : 'filter'\"\n @click.stop=\"showManager = true\"\n >\n Filters\n </PlBtnGhost>\n </Teleport>\n\n <PlSlideModal v-model=\"showManager\" :close-on-outside-click=\"false\">\n <template #title>Manage Filters</template>\n\n <div :class=\"$style.root\">\n <PlAdvancedFilterComponent\n :filters=\"filters as PlAdvancedFilter\"\n :options=\"options\"\n :supported-filters=\"supportedFilters\"\n :get-suggest-options=\"handleSuggestOptions\"\n :is-pinned=\"(_, index) => hasDefaultFilters && index === 0\"\n :is-removable=\"(_, index) => (hasDefaultFilters ? index > 0 : true)\"\n :is-draggable=\"(_, index) => (hasDefaultFilters ? index > 0 : true)\"\n :enable-dnd=\"false\"\n :enable-toggling=\"true\"\n :enable-add-group-button=\"true\"\n @update-filters=\"onUpdateFilters\"\n >\n <template #group-title=\"{ index }\">\n <div v-if=\"hasDefaultFilters && index === 0\" :class=\"$style.defaultGroupTitle\">\n Default Group\n <PlBtnGhost\n v-if=\"isFunction(props.onResetDefaultFilters)\"\n icon=\"restart\"\n :class=\"$style.restartBtn\"\n @click.stop=\"props.onResetDefaultFilters()\"\n />\n </div>\n <div v-else>Custom Group</div>\n </template>\n </PlAdvancedFilterComponent>\n </div>\n </PlSlideModal>\n</template>\n\n<style module>\n.root {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.defaultGroupTitle {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.restartBtn {\n width: 24px;\n height: 24px;\n padding: 4px;\n --button-width: 24px;\n --btn-min-width: 24px;\n --button-height: 24px;\n --btn-min-height: 24x;\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PlTableFiltersV2.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type {\n PTableColumnSpec,\n PlDataTableFiltersWithMeta,\n PFrameHandle,\n PTableColumnId,\n PColumnSpec,\n} from \"@platforma-sdk/model\";\nimport {\n Annotation,\n Domain,\n readAnnotation,\n readDomain,\n getUniqueSourceValuesWithLabels,\n extractPObjectId,\n getPTableColumnId,\n deriveDistinctLabels,\n} from \"@platforma-sdk/model\";\nimport { computed, ref } from \"vue\";\nimport { PlBtnGhost, PlSlideModal, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport {\n PlAdvancedFilter,\n PlAdvancedFilterComponent,\n PlAdvancedFilterSupportedFilters,\n type PlAdvancedFilterItem,\n} from \"../PlAdvancedFilter\";\nimport type { PlAdvancedFilterColumnId } from \"../PlAdvancedFilter/types\";\nimport type { Nil } from \"@milaboratories/helpers\";\nimport { isFunction, isNil } from \"es-toolkit\";\n\nconst props = defineProps<{\n columns: PTableColumnSpec[];\n pframeHandle: Nil | PFrameHandle;\n filters: PlDataTableFiltersWithMeta;\n defaultFilters: Nil | PlDataTableFiltersWithMeta;\n onUpdateFilters: (value: PlDataTableFiltersWithMeta) => void;\n onResetDefaultFilters?: () => void;\n onUpdateDefaultFilters?: (value: PlDataTableFiltersWithMeta) => void;\n}>();\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlTableFiltersV2\");\nconst showManager = ref(false);\nconst hasFilters = computed(() => props.filters.filters.length > 0);\nconst hasDefaultFilters = computed(\n () => !isNil(props.defaultFilters) && props.defaultFilters.filters.length > 0,\n);\nconst filters = computed<PlDataTableFiltersWithMeta>(() => {\n if (isNil(props.defaultFilters) || props.defaultFilters?.filters.length === 0) {\n return props.filters;\n }\n\n return {\n ...props.filters,\n filters: [...(props.defaultFilters?.filters ?? []), ...props.filters.filters],\n };\n});\nconst onUpdateFilters = (_value: PlAdvancedFilter) => {\n const value = _value as PlDataTableFiltersWithMeta;\n\n if (isNil(props.defaultFilters)) {\n return props.onUpdateFilters(value);\n }\n\n const [defaults, ...rest] = value.filters;\n props.onUpdateFilters({ ...value, filters: rest });\n props.onUpdateDefaultFilters?.({ ...props.defaultFilters, filters: [defaults] });\n};\n\nconst options = computed<PlAdvancedFilterItem[]>(() => {\n const columnEntries: { idx: number; spec: PColumnSpec }[] = [];\n props.columns.forEach((col, idx) => {\n if (col.type === \"column\") columnEntries.push({ idx, spec: col.spec });\n });\n const distinctLabelByIdx = new Map<number, string>();\n deriveDistinctLabels(\n columnEntries.map((e) => e.spec),\n {},\n ).forEach((label, i) => distinctLabelByIdx.set(columnEntries[i].idx, label));\n\n return props.columns.map((col, idx) => {\n const id = getPTableColumnId(col);\n const label =\n distinctLabelByIdx.get(idx)?.trim() ||\n readAnnotation(col.spec, Annotation.Label)?.trim() ||\n `Unlabeled ${col.type} ${idx}`;\n const alphabet =\n readDomain(col.spec, Domain.Alphabet) ?? readAnnotation(col.spec, Annotation.Alphabet);\n return {\n id,\n label,\n spec: col.spec,\n alphabet: alphabet ?? undefined,\n };\n });\n});\n\n// Supported filters (same set as FilterSidebar)\nconst supportedFilters = [\n \"isNA\",\n \"isNotNA\",\n \"greaterThan\",\n \"greaterThanOrEqual\",\n \"lessThan\",\n \"lessThanOrEqual\",\n \"patternEquals\",\n \"patternNotEquals\",\n \"patternContainSubsequence\",\n \"patternNotContainSubsequence\",\n \"patternMatchesRegularExpression\",\n \"patternFuzzyContainSubsequence\",\n \"equal\",\n \"notEqual\",\n] as (typeof PlAdvancedFilterSupportedFilters)[number][];\n\n// getSuggestOptions - provide discrete values from column annotations\nfunction handleSuggestOptions(params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n}) {\n if (isNil(props.pframeHandle)) {\n console.warn(\"PFrame handle is not available, cannot fetch suggest options\");\n return [];\n }\n\n const tableColumnId = params.columnId as PTableColumnId;\n if (\n typeof tableColumnId !== \"object\" ||\n tableColumnId === null ||\n tableColumnId.type !== \"column\"\n ) {\n throw new Error(\"ColumnId should be of type 'column' for suggest options\");\n }\n\n return getUniqueSourceValuesWithLabels(props.pframeHandle, {\n columnId: extractPObjectId(tableColumnId.id),\n axisIdx: params.axisIdx,\n limit: 100,\n searchQuery: params.searchType === \"label\" ? params.searchStr : undefined,\n searchQueryValue: params.searchType === \"value\" ? params.searchStr : undefined,\n }).then((v) => v.values);\n}\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget\" :to=\"teleportTarget\">\n <PlBtnGhost\n data-testid=\"pl-table-filters\"\n :icon=\"hasFilters || hasDefaultFilters ? 'filter-on' : 'filter'\"\n @click.stop=\"showManager = true\"\n >\n Filters\n </PlBtnGhost>\n </Teleport>\n\n <PlSlideModal\n v-model=\"showManager\"\n data-testid=\"pl-table-filters-panel\"\n :close-on-outside-click=\"false\"\n >\n <template #title>Manage Filters</template>\n\n <div data-testid=\"pl-table-filters-content\" :class=\"$style.root\">\n <PlAdvancedFilterComponent\n :filters=\"filters as PlAdvancedFilter\"\n :options=\"options\"\n :supported-filters=\"supportedFilters\"\n :get-suggest-options=\"handleSuggestOptions\"\n :is-pinned=\"(_, index) => hasDefaultFilters && index === 0\"\n :is-removable=\"(_, index) => (hasDefaultFilters ? index > 0 : true)\"\n :is-draggable=\"(_, index) => (hasDefaultFilters ? index > 0 : true)\"\n :enable-dnd=\"false\"\n :enable-toggling=\"true\"\n :enable-add-group-button=\"true\"\n @update-filters=\"onUpdateFilters\"\n >\n <template #group-title=\"{ index }\">\n <div\n v-if=\"hasDefaultFilters && index === 0\"\n data-testid=\"pl-table-filters-default-group-title\"\n :class=\"$style.defaultGroupTitle\"\n >\n Default Group\n <PlBtnGhost\n v-if=\"isFunction(props.onResetDefaultFilters)\"\n data-testid=\"pl-table-filters-reset-default\"\n icon=\"restart\"\n :class=\"$style.restartBtn\"\n @click.stop=\"props.onResetDefaultFilters()\"\n />\n </div>\n <div v-else data-testid=\"pl-table-filters-custom-group-title\">Custom Group</div>\n </template>\n </PlAdvancedFilterComponent>\n </div>\n </PlSlideModal>\n</template>\n\n<style module>\n.root {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.defaultGroupTitle {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.restartBtn {\n width: 24px;\n height: 24px;\n padding: 4px;\n --button-width: 24px;\n --btn-min-width: 24px;\n --button-height: 24px;\n --btn-min-height: 24x;\n}\n</style>\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/ui-vue",
|
|
3
|
-
"version": "1.84.
|
|
3
|
+
"version": "1.84.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
"lru-cache": "^11.2.2",
|
|
27
27
|
"vue": "3.5.24",
|
|
28
28
|
"zod": "~3.25.76",
|
|
29
|
-
"@milaboratories/columns-collection-driver": "0.2.
|
|
30
|
-
"@milaboratories/
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
"@milaboratories/pf-spec-driver": "1.5.
|
|
29
|
+
"@milaboratories/columns-collection-driver": "0.2.9",
|
|
30
|
+
"@milaboratories/uikit": "2.15.39",
|
|
31
|
+
"@platforma-sdk/model": "1.84.17",
|
|
32
|
+
"@milaboratories/pl-model-common": "1.53.0",
|
|
33
|
+
"@milaboratories/pf-spec-driver": "1.5.8"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@faker-js/faker": "^9.2.0",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"typescript": "7.0.2",
|
|
47
47
|
"vite": "^8.0.6",
|
|
48
48
|
"vitest": "^4.1.3",
|
|
49
|
-
"@milaboratories/helpers": "1.14.5",
|
|
50
49
|
"@milaboratories/build-configs": "2.0.2",
|
|
50
|
+
"@milaboratories/helpers": "1.14.5",
|
|
51
51
|
"@milaboratories/ts-configs": "1.4.0",
|
|
52
52
|
"@milaboratories/ts-builder": "1.7.2"
|
|
53
53
|
},
|
|
@@ -41,9 +41,11 @@ const progress = computed(() => app.value?.progress?.());
|
|
|
41
41
|
</script>
|
|
42
42
|
|
|
43
43
|
<template>
|
|
44
|
-
<div class="block block__layout">
|
|
44
|
+
<div data-testid="pl-block-layout" class="block block__layout">
|
|
45
45
|
<BlockLoader :value="progress" />
|
|
46
|
-
<div v-if="sdk.error" :class="$style.error">
|
|
46
|
+
<div v-if="sdk.error" data-testid="pl-block-layout-error" :class="$style.error">
|
|
47
|
+
{{ sdk.error }}
|
|
48
|
+
</div>
|
|
47
49
|
<LoaderPage v-else-if="!sdk.loaded">Loading...</LoaderPage>
|
|
48
50
|
<component :is="CurrentView" v-else-if="CurrentView" :key="href" />
|
|
49
51
|
<NotFound v-else />
|
|
@@ -23,9 +23,10 @@ const progressWidth = computed(() => {
|
|
|
23
23
|
</script>
|
|
24
24
|
|
|
25
25
|
<template>
|
|
26
|
-
<div v-if="isLoader" class="block__loader" />
|
|
26
|
+
<div v-if="isLoader" data-testid="pl-block-loader" class="block__loader" />
|
|
27
27
|
<div
|
|
28
28
|
v-else-if="progressWidth !== undefined"
|
|
29
|
+
data-testid="pl-block-loader-progress"
|
|
29
30
|
class="block__progress"
|
|
30
31
|
:style="{ '--progress-width': progressWidth }"
|
|
31
32
|
/>
|
|
@@ -12,8 +12,12 @@ const goToMain = () => {
|
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
14
|
<template>
|
|
15
|
-
<div class="block__not-found">
|
|
16
|
-
<h1
|
|
17
|
-
|
|
15
|
+
<div data-testid="pl-not-found" class="block__not-found">
|
|
16
|
+
<h1 data-testid="pl-not-found-title">
|
|
17
|
+
Not found route: {{ app.snapshot.navigationState.href }}
|
|
18
|
+
</h1>
|
|
19
|
+
<PlBtnSecondary data-testid="pl-not-found-return" @click.stop="goToMain"
|
|
20
|
+
>Return to main page</PlBtnSecondary
|
|
21
|
+
>
|
|
18
22
|
</div>
|
|
19
23
|
</template>
|