@platforma-sdk/ui-vue 1.44.5 → 1.44.6
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 +34 -36
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +7 -0
- package/dist/AgGridVue/createAgGridColDef.js +2 -3
- package/dist/AgGridVue/createAgGridColDef.js.map +1 -1
- package/dist/AgGridVue/useAgGridOptions.js +2 -3
- package/dist/AgGridVue/useAgGridOptions.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue2.js +2 -3
- package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +2 -3
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgRowCount.vue.js +7 -8
- package/dist/components/PlAgDataTable/PlAgRowCount.vue.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/focus-row.js +20 -21
- package/dist/components/PlAgDataTable/sources/focus-row.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-source-v2.js +2 -3
- package/dist/components/PlAgDataTable/sources/table-source-v2.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.js +2 -3
- package/dist/components/PlAgDataTable/sources/table-state-v2.js.map +1 -1
- package/dist/components/PlAgDataTable/types.js +9 -10
- package/dist/components/PlAgDataTable/types.js.map +1 -1
- package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.js +9 -10
- package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.js.map +1 -1
- package/dist/components/PlAgRowNumHeader.vue.js +2 -3
- package/dist/components/PlAgRowNumHeader.vue.js.map +1 -1
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js +2 -3
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/DynamicForm.vue2.js +2 -3
- package/dist/components/PlAnnotations/components/DynamicForm.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +2 -3
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js +9 -10
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js.map +1 -1
- package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue2.js +2 -3
- package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue2.js.map +1 -1
- package/dist/components/PlMultiSequenceAlignment/Toolbar.vue2.js +2 -3
- package/dist/components/PlMultiSequenceAlignment/Toolbar.vue2.js.map +1 -1
- package/dist/components/PlMultiSequenceAlignment/data.js +8 -9
- package/dist/components/PlMultiSequenceAlignment/data.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableAddFilterV2.vue.js +2 -3
- package/dist/components/PlTableFilters/PlTableAddFilterV2.vue.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFilterEntryV2.vue.js +2 -3
- package/dist/components/PlTableFilters/PlTableFilterEntryV2.vue.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js +2 -3
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js.map +1 -1
- package/dist/components/PlTableFilters/filters-state.js +9 -10
- package/dist/components/PlTableFilters/filters-state.js.map +1 -1
- package/dist/composition/fileContent.js +0 -1
- package/dist/composition/fileContent.js.map +1 -1
- package/dist/createModel.js +2 -3
- package/dist/createModel.js.map +1 -1
- package/dist/defineApp.js +8 -9
- package/dist/defineApp.js.map +1 -1
- package/dist/internal/UpdateSerializer.js +10 -11
- package/dist/internal/UpdateSerializer.js.map +1 -1
- package/dist/internal/createAppModel.js +11 -12
- package/dist/internal/createAppModel.js.map +1 -1
- package/dist/internal/createAppV1.js +2 -3
- package/dist/internal/createAppV1.js.map +1 -1
- package/dist/internal/createAppV2.js +31 -32
- package/dist/internal/createAppV2.js.map +1 -1
- package/package.json +5 -5
- package/dist/lib/util/helpers/dist/parse.js +0 -24
- package/dist/lib/util/helpers/dist/parse.js.map +0 -1
- package/dist/lib/util/helpers/dist/test_timeouts.js +0 -9
- package/dist/lib/util/helpers/dist/test_timeouts.js.map +0 -1
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { isJsonEqual as O } from "../../lib/util/helpers/dist/objects.js";
|
|
2
|
-
import "../../lib/util/helpers/dist/test_timeouts.js";
|
|
3
2
|
import { ensureError as T, getRawPlatformaInstance as $, readAnnotation as C, Annotation as h, canonicalizeJson as v, getAxisId as S, parseJson as A, isLabelColumn as j, matchAxisId as B, readAnnotationJson as J, isLinkerColumn as N, createRowSelectionColumn as W, pTableValue as R } from "@platforma-sdk/model";
|
|
4
3
|
import { ref as M, watch as F, onWatcherCleanup as H } from "vue";
|
|
5
4
|
import { objectHash as I } from "../../objectHash.js";
|
|
6
5
|
import { highlightByChemicalProperties as V } from "./chemical-properties.js";
|
|
7
6
|
import { parseMarkup as z, highlightByMarkup as Q, markupAlignedSequence as Y } from "./markup.js";
|
|
8
7
|
import { getResidueCounts as Z } from "./residue-counts.js";
|
|
9
|
-
const x = () => $().pFrameDriver, D = 1e3,
|
|
8
|
+
const x = () => $().pFrameDriver, D = 1e3, we = E(
|
|
10
9
|
_
|
|
11
|
-
),
|
|
10
|
+
), ge = E(
|
|
12
11
|
G
|
|
13
|
-
),
|
|
12
|
+
), he = E(
|
|
14
13
|
K
|
|
15
|
-
),
|
|
14
|
+
), be = E(
|
|
16
15
|
X
|
|
17
16
|
);
|
|
18
17
|
async function _({ pFrame: n, sequenceColumnPredicate: r }) {
|
|
@@ -363,9 +362,9 @@ function E(n) {
|
|
|
363
362
|
}
|
|
364
363
|
export {
|
|
365
364
|
D as SEQUENCE_LIMIT,
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
365
|
+
ge as useLabelColumnsOptions,
|
|
366
|
+
he as useMarkupColumnsOptions,
|
|
367
|
+
be as useMultipleAlignmentData,
|
|
368
|
+
we as useSequenceColumnsOptions
|
|
370
369
|
};
|
|
371
370
|
//# sourceMappingURL=data.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data.js","sources":["../../../src/components/PlMultiSequenceAlignment/data.ts"],"sourcesContent":["import { isJsonEqual } from '@milaboratories/helpers';\nimport type { ListOptionNormalized } from '@milaboratories/uikit';\nimport {\n Annotation,\n type CalculateTableDataRequest,\n type CalculateTableDataResponse,\n type CanonicalizedJson,\n canonicalizeJson,\n createRowSelectionColumn,\n ensureError,\n getAxisId,\n getRawPlatformaInstance,\n isLabelColumn,\n isLinkerColumn,\n type JoinEntry,\n matchAxisId,\n parseJson,\n type PColumnIdAndSpec,\n type PFrameHandle,\n type PlMultiSequenceAlignmentColorSchemeOption,\n type PlMultiSequenceAlignmentSettings,\n type PlSelectionModel,\n type PObjectId,\n type PTableColumnId,\n type PTableSorting,\n pTableValue,\n readAnnotation,\n readAnnotationJson,\n} from '@platforma-sdk/model';\nimport { onWatcherCleanup, ref, watch } from 'vue';\nimport { objectHash } from '../../objectHash';\nimport { highlightByChemicalProperties } from './chemical-properties';\nimport type { Markup } from './markup';\nimport {\n highlightByMarkup,\n markupAlignedSequence,\n parseMarkup,\n} from './markup';\nimport type * as MultiSequenceAlignmentWorker from './multi-sequence-alignment.worker';\nimport type * as PhylogeneticTreeWorker from './phylogenetic-tree.worker';\nimport { getResidueCounts } from './residue-counts';\nimport type { HighlightLegend, ResidueCounts } from './types';\n\nconst getPFrameDriver = () => getRawPlatformaInstance().pFrameDriver;\n\nexport const SEQUENCE_LIMIT = 1000;\n\nexport const useSequenceColumnsOptions = refreshOnDeepChange(\n getSequenceColumnsOptions,\n);\n\nexport const useLabelColumnsOptions = refreshOnDeepChange(\n getLabelColumnsOptions,\n);\n\nexport const useMarkupColumnsOptions = refreshOnDeepChange(\n getMarkupColumnsOptions,\n);\n\nexport const useMultipleAlignmentData = refreshOnDeepChange(\n getMultipleAlignmentData,\n);\n\nasync function getSequenceColumnsOptions({ pFrame, sequenceColumnPredicate }: {\n pFrame: PFrameHandle | undefined;\n sequenceColumnPredicate: (column: PColumnIdAndSpec) => boolean;\n}): Promise<OptionsWithDefaults<PObjectId> | undefined> {\n if (!pFrame) return;\n\n const pFrameDriver = getPFrameDriver();\n const columns = await pFrameDriver.listColumns(pFrame);\n\n const options = columns.values()\n .filter((column) => sequenceColumnPredicate(column))\n .map(({ spec, columnId }) => ({\n label: readAnnotation(spec, Annotation.Label) ?? 'Unlabeled column',\n value: columnId,\n }))\n .toArray();\n\n const defaults = options.map(({ value }) => value);\n\n return { options, defaults };\n}\n\nasync function getLabelColumnsOptions({ pFrame, sequenceColumnIds }: {\n pFrame: PFrameHandle | undefined;\n sequenceColumnIds: PObjectId[] | undefined;\n}): Promise<OptionsWithDefaults<PTableColumnId> | undefined> {\n if (!pFrame || !sequenceColumnIds) return;\n\n const pFrameDriver = getPFrameDriver();\n const columns = await pFrameDriver.listColumns(pFrame);\n\n const sequenceColumnsAxes = new Map(\n sequenceColumnIds.values().flatMap((id) => {\n const column = columns.find(({ columnId }) => columnId === id);\n if (!column) {\n throw new Error(`Couldn't find sequence column (ID: \\`${id}\\`).`);\n }\n return column.spec.axesSpec.values()\n .map((spec) => [canonicalizeJson(getAxisId(spec)), spec]);\n }),\n );\n\n const optionMap = new Map<CanonicalizedJson<PTableColumnId>, string>();\n for (const [axisIdJson, axisSpec] of sequenceColumnsAxes.entries()) {\n const axisId = parseJson(axisIdJson);\n const labelColumn = columns.find(({ spec }) =>\n isLabelColumn(spec) && matchAxisId(axisId, getAxisId(spec.axesSpec[0])),\n );\n optionMap.set(\n labelColumn\n ? canonicalizeJson({ type: 'column', id: labelColumn.columnId })\n : canonicalizeJson({ type: 'axis', id: axisId }),\n readAnnotation(labelColumn?.spec, Annotation.Label)\n ?? readAnnotation(axisSpec, Annotation.Label)\n ?? 'Unlabeled axis',\n );\n }\n\n const { hits: compatibleColumns } = await pFrameDriver.findColumns(pFrame, {\n columnFilter: {},\n compatibleWith: sequenceColumnsAxes.keys()\n .map((axisIdJson) => parseJson(axisIdJson))\n .toArray(),\n strictlyCompatible: false,\n });\n\n for (const { columnId, spec } of compatibleColumns) {\n const columnIdJson = canonicalizeJson<PTableColumnId>({\n type: 'column',\n id: columnId,\n });\n if (optionMap.has(columnIdJson)) continue;\n optionMap.set(\n columnIdJson,\n readAnnotation(spec, Annotation.Label) ?? 'Unlabeled column',\n );\n }\n\n const options = optionMap.entries()\n .map(([value, label]) => ({ label, value: parseJson(value) }))\n .toArray();\n\n const defaults = options.values()\n .filter(({ value }) => {\n if (value.type === 'axis') return true;\n const column = columns.find(({ columnId }) => columnId === value.id);\n return column && isLabelColumn(column.spec);\n })\n .map(({ value }) => value)\n .toArray();\n\n return { options, defaults };\n}\n\nasync function getMarkupColumnsOptions({ pFrame, sequenceColumnIds }: {\n pFrame: PFrameHandle | undefined;\n sequenceColumnIds: PObjectId[] | undefined;\n}): Promise<ListOptionNormalized<PObjectId[]>[] | undefined> {\n if (!pFrame || !sequenceColumnIds) return;\n\n const pFrameDriver = getPFrameDriver();\n const columns = await pFrameDriver.listColumns(pFrame);\n\n const sequenceColumns = sequenceColumnIds.map((columnId) => {\n const column = columns.find((column) => column.columnId === columnId);\n if (!column) {\n throw new Error(\n `Couldn't find sequence column (ID: \\`${sequenceColumnIds[0]}\\`).`,\n );\n }\n return column;\n });\n\n const columnPairs = sequenceColumns\n .flatMap((sequenceColumn) =>\n columns\n .filter((column) =>\n readAnnotationJson(column.spec, Annotation.Sequence.IsAnnotation)\n && isJsonEqual(sequenceColumn.spec.axesSpec, column.spec.axesSpec)\n && Object.entries(sequenceColumn.spec.domain ?? {})\n .every(([key, value]) => column.spec.domain?.[key] === value),\n )\n .map((markupColumn) => ({ markupColumn, sequenceColumn })),\n );\n\n const groupedByDomainDiff = Map.groupBy(\n columnPairs,\n ({ markupColumn, sequenceColumn }) => {\n const domainDiff = Object.fromEntries(\n Object.entries(markupColumn.spec.domain ?? {})\n .filter(([key]) => sequenceColumn.spec.domain?.[key] == undefined),\n );\n return canonicalizeJson(domainDiff);\n },\n );\n\n return groupedByDomainDiff.entries()\n .map(([domainDiffJson, columnPairs]) => ({\n label: Object.values(parseJson(domainDiffJson)).join(', '),\n value: columnPairs.map(({ markupColumn }) => markupColumn.columnId),\n }))\n .toArray();\n}\n\nasync function getMultipleAlignmentData(\n {\n pFrame,\n sequenceColumnIds,\n labelColumnIds,\n selection,\n colorScheme,\n alignmentParams,\n shouldBuildPhylogeneticTree,\n }: {\n pFrame: PFrameHandle | undefined;\n sequenceColumnIds: PObjectId[] | undefined;\n labelColumnIds: PTableColumnId[] | undefined;\n selection: PlSelectionModel | undefined;\n colorScheme: PlMultiSequenceAlignmentColorSchemeOption;\n alignmentParams: PlMultiSequenceAlignmentSettings['alignmentParams'];\n shouldBuildPhylogeneticTree: boolean;\n },\n abortSignal: AbortSignal,\n): Promise<MultipleAlignmentData | undefined> {\n if (!pFrame || !sequenceColumnIds?.length || !labelColumnIds) return;\n\n const table = await getTableData({\n pFrame,\n sequenceColumnIds,\n labelColumnIds,\n selection,\n colorScheme,\n });\n\n const rowCount = table.at(0)?.data.data.length ?? 0;\n\n if (rowCount < 2) return;\n\n const exceedsLimit = rowCount > SEQUENCE_LIMIT;\n const rawSequences = extractSequences(sequenceColumnIds, table);\n const labels = extractLabels(labelColumnIds, table);\n const markups = colorScheme.type === 'markup'\n ? extractMarkups(colorScheme.columnIds, table)\n : undefined;\n\n const highlightLegend: HighlightLegend = {};\n\n const alignedSequences = await Promise.all(\n rawSequences.map(async ({ name, rows }) => ({\n name,\n rows: await alignSequences(\n rows,\n JSON.parse(JSON.stringify(alignmentParams)),\n abortSignal,\n ),\n })),\n );\n\n let phylogeneticTree: PhylogeneticTreeWorker.TreeNodeData[] | undefined;\n if (shouldBuildPhylogeneticTree) {\n phylogeneticTree = await buildPhylogeneticTree(\n alignedSequences,\n abortSignal,\n );\n const rowOrder = phylogeneticTree.values()\n .filter(({ id }) => id >= 0)\n .map(({ id }) => id)\n .toArray();\n for (const sequencesColumn of alignedSequences) {\n sequencesColumn.rows = rowOrder.map((i) => sequencesColumn.rows[i]);\n }\n for (const labelsColumn of labels) {\n labelsColumn.rows = rowOrder.map((i) => labelsColumn.rows[i]);\n }\n for (const markupsColumn of markups ?? []) {\n markupsColumn.rows = rowOrder.map((i) => markupsColumn.rows[i]);\n }\n }\n\n const sequences = await Promise.all(\n alignedSequences.map(async ({ name, rows }, index) => {\n const residueCounts = getResidueCounts(rows);\n const image = generateHighlightImage({\n colorScheme,\n sequences: rows,\n residueCounts,\n markup: markups?.at(index),\n });\n if (image) {\n Object.assign(highlightLegend, image.legend);\n }\n return {\n name,\n rows,\n residueCounts,\n ...image && {\n highlightImageUrl: await blobToBase64(image.blob),\n },\n } satisfies MultipleAlignmentData['sequences'][number];\n }),\n );\n\n return {\n sequences,\n labels,\n ...Object.keys(highlightLegend).length && {\n highlightLegend,\n },\n ...phylogeneticTree && {\n phylogeneticTree,\n },\n exceedsLimit,\n };\n}\n\nasync function getTableData(\n { pFrame, sequenceColumnIds, labelColumnIds, selection, colorScheme }: {\n pFrame: PFrameHandle;\n sequenceColumnIds: PObjectId[];\n labelColumnIds: PTableColumnId[];\n selection: PlSelectionModel | undefined;\n colorScheme: PlMultiSequenceAlignmentColorSchemeOption;\n },\n): Promise<CalculateTableDataResponse> {\n const pFrameDriver = getPFrameDriver();\n const columns = await pFrameDriver.listColumns(pFrame);\n const linkerColumns = columns.filter((column) => isLinkerColumn(column.spec));\n\n const filterColumn = createRowSelectionColumn({ selection });\n\n // inner join of sequence columns\n let primaryEntry: JoinEntry<PObjectId> = {\n type: 'inner',\n entries: sequenceColumnIds.map((column) => ({\n type: 'column',\n column,\n })),\n };\n\n // if we have linkers, left join them\n if (linkerColumns.length > 0) {\n primaryEntry = {\n type: 'outer',\n primary: primaryEntry,\n secondary: linkerColumns.map(({ columnId }) => ({\n type: 'column',\n column: columnId,\n })),\n };\n }\n\n // inner join with filters\n if (filterColumn) {\n primaryEntry = {\n type: 'inner',\n entries: [\n primaryEntry,\n {\n type: 'inlineColumn',\n column: filterColumn,\n },\n ],\n };\n }\n\n // left join with labels\n const secondaryEntry: JoinEntry<PObjectId>[] = labelColumnIds\n .flatMap((column) => {\n if (column.type !== 'column') return [];\n return { type: 'column', column: column.id };\n });\n\n // and markup\n if (colorScheme.type === 'markup') {\n for (const column of colorScheme.columnIds) {\n secondaryEntry.push({ type: 'column', column });\n }\n }\n\n const sorting: PTableSorting[] = Array.from(\n new Set(\n sequenceColumnIds.values().flatMap((id) => {\n const column = columns.find(({ columnId }) => columnId === id);\n if (!column) {\n throw new Error(`Couldn't find sequence column (ID: ${id})`);\n }\n return column.spec.axesSpec\n .map((spec) => canonicalizeJson(getAxisId(spec)));\n }),\n ),\n )\n .sort()\n .map((id) => ({\n column: { type: 'axis', id: parseJson(id) },\n ascending: true,\n naAndAbsentAreLeastValues: true,\n }));\n\n const request: CalculateTableDataRequest<PObjectId> = {\n src: {\n type: 'outer',\n primary: primaryEntry,\n secondary: secondaryEntry,\n },\n filters: [],\n sorting,\n };\n\n return pFrameDriver.calculateTableData(\n pFrame,\n JSON.parse(JSON.stringify(request)),\n {\n offset: 0,\n // +1 is a hack to check whether the selection is over the limit\n length: SEQUENCE_LIMIT + 1,\n },\n );\n}\n\nconst extractSequences = (\n columnIds: PObjectId[],\n table: CalculateTableDataResponse,\n): { name: string; rows: string[] }[] =>\n columnIds.map((columnId) => {\n const column = table.find(({ spec }) => spec.id === columnId);\n if (!column) {\n throw new Error(`Couldn't find sequence column (ID: \\`${columnId}\\`).`);\n }\n const name = readAnnotation(column.spec.spec, Annotation.Label)\n ?? 'Unlabeled column';\n const rows = column.data.data\n .keys()\n .take(SEQUENCE_LIMIT)\n .map((row) =>\n pTableValue(column.data, row, { absent: '', na: '' })?.toString()\n ?? '',\n )\n .toArray();\n return { name, rows };\n });\n\nconst extractLabels = (\n columnIds: PTableColumnId[],\n table: CalculateTableDataResponse,\n): { rows: string[] }[] =>\n columnIds.map((columnId) => {\n const column = table.find(({ spec }) => {\n if (columnId.type === 'axis' && spec.type === 'axis') {\n return isJsonEqual(columnId.id, spec.id);\n }\n if (columnId.type === 'column' && spec.type === 'column') {\n return columnId.id === spec.id;\n }\n });\n if (!column) {\n throw new Error(`Couldn't find label column (ID: \\`${columnId}\\`).`);\n }\n const rows = column.data.data\n .keys()\n .take(SEQUENCE_LIMIT)\n .map((row) =>\n pTableValue(column.data, row, { absent: '', na: '' })?.toString()\n ?? '',\n )\n .toArray();\n return { rows };\n });\n\nconst extractMarkups = (\n columnIds: PObjectId[],\n table: CalculateTableDataResponse,\n): { labels: Record<string, string>; rows: Markup[] }[] =>\n columnIds.map((columnId) => {\n const column = table.find(({ spec }) => spec.id === columnId);\n if (!column) {\n throw new Error(`Couldn't find markup column (ID: \\`${columnId}\\`).`);\n }\n const labels = readAnnotationJson(\n column.spec.spec,\n Annotation.Sequence.Annotation.Mapping,\n ) ?? {};\n const rows = column.data.data\n .keys()\n .take(SEQUENCE_LIMIT)\n .map((row) =>\n parseMarkup(\n pTableValue(column.data, row, { absent: '', na: '' })?.toString()\n ?? '',\n ),\n )\n .toArray();\n return { labels, rows };\n });\n\nconst alignSequences = (() => {\n const cache = new Map<string, string[]>();\n return async (\n sequences: string[],\n alignmentParams: PlMultiSequenceAlignmentSettings['alignmentParams'],\n abortSignal: AbortSignal,\n ): Promise<string[]> => {\n const hash = await objectHash([sequences, alignmentParams]);\n let result = cache.get(hash);\n if (result) return result;\n result = await runInWorker<\n MultiSequenceAlignmentWorker.RequestMessage,\n MultiSequenceAlignmentWorker.ResponseMessage\n >(\n new Worker(\n new URL('./multi-sequence-alignment.worker.ts', import.meta.url),\n { type: 'module' },\n ),\n { sequences, params: alignmentParams },\n abortSignal,\n );\n cache.set(hash, result);\n return result;\n };\n})();\n\nfunction generateHighlightImage(\n { colorScheme, sequences, residueCounts, markup }: {\n colorScheme: PlMultiSequenceAlignmentColorSchemeOption;\n sequences: string[];\n residueCounts: ResidueCounts;\n markup: { labels: Record<string, string>; rows: Markup[] } | undefined;\n },\n): { blob: Blob; legend: HighlightLegend } | undefined {\n if (colorScheme.type === 'chemical-properties') {\n return highlightByChemicalProperties({ sequences, residueCounts });\n }\n if (colorScheme.type === 'markup') {\n if (!markup) {\n throw new Error('Missing markup data.');\n }\n return highlightByMarkup({\n markupRows: sequences.map((sequence, row) => {\n const markupRow = markup.rows.at(row);\n if (!markupRow) throw new Error(`Missing markup for row ${row}.`);\n return markupAlignedSequence(sequence, markupRow);\n }),\n columnCount: sequences.at(0)?.length ?? 0,\n labels: markup.labels,\n });\n }\n}\n\nconst blobToBase64 = (blob: Blob): Promise<string> =>\n new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.addEventListener('load', () => resolve(reader.result as string));\n reader.addEventListener('error', () => reject(reader.error));\n reader.readAsDataURL(blob);\n });\n\nconst buildPhylogeneticTree = (() => {\n const cache = new Map<string, PhylogeneticTreeWorker.TreeNodeData[]>();\n return async (data: { rows: string[] }[], abortSignal: AbortSignal) => {\n const concatenatedSequences = data.at(0)?.rows\n .keys()\n .map((row) => data.map((column) => column.rows.at(row) ?? '').join(''))\n .toArray() ?? [];\n const hash = await objectHash(concatenatedSequences);\n let result = cache.get(hash);\n if (result) return result;\n result = await runInWorker<\n PhylogeneticTreeWorker.RequestMessage,\n PhylogeneticTreeWorker.ResponseMessage\n >(\n new Worker(\n new URL('./phylogenetic-tree.worker.ts', import.meta.url),\n { type: 'module' },\n ),\n concatenatedSequences,\n abortSignal,\n );\n cache.set(hash, result);\n return result;\n };\n})();\n\nconst runInWorker = <RequestMessage, ResponseMessage>(\n worker: Worker,\n message: RequestMessage,\n abortSignal: AbortSignal,\n) =>\n new Promise<ResponseMessage>((resolve, reject) => {\n worker.addEventListener('message', ({ data }) => {\n resolve(data);\n worker.terminate();\n });\n worker.addEventListener('error', ({ error, message }) => {\n reject(error ?? message);\n worker.terminate();\n });\n abortSignal.addEventListener('abort', () => {\n reject(abortSignal.reason);\n worker.terminate();\n });\n worker.postMessage(message);\n });\n\nfunction refreshOnDeepChange<T, P>(\n cb: (params: P, abortSignal: AbortSignal) => Promise<T>,\n) {\n const data = ref<T>();\n const isLoading = ref(true);\n const error = ref<Error>();\n let requestId: symbol;\n return (paramsGetter: () => P) => {\n watch(paramsGetter, async (params, prevParams) => {\n if (isJsonEqual(params, prevParams)) return;\n const abortController = new AbortController();\n const currentRequestId = requestId = Symbol();\n onWatcherCleanup(() => {\n abortController.abort();\n });\n try {\n error.value = undefined;\n isLoading.value = true;\n const result = await cb(params, abortController.signal);\n if (currentRequestId === requestId) {\n data.value = result;\n }\n } catch (err) {\n console.error(err);\n if (currentRequestId === requestId) {\n error.value = ensureError(err);\n }\n } finally {\n if (currentRequestId === requestId) {\n isLoading.value = false;\n }\n }\n }, { immediate: true });\n return { data, isLoading, error };\n };\n}\n\ntype MultipleAlignmentData = {\n sequences: {\n name: string;\n rows: string[];\n residueCounts: ResidueCounts;\n highlightImageUrl?: string;\n }[];\n labels: {\n rows: string[];\n }[];\n highlightLegend?: HighlightLegend;\n phylogeneticTree?: PhylogeneticTreeWorker.TreeNodeData[];\n exceedsLimit: boolean;\n};\n\ntype OptionsWithDefaults<T> = {\n options: ListOptionNormalized<T>[];\n defaults: T[];\n};\n"],"names":["getPFrameDriver","getRawPlatformaInstance","SEQUENCE_LIMIT","useSequenceColumnsOptions","refreshOnDeepChange","getSequenceColumnsOptions","useLabelColumnsOptions","getLabelColumnsOptions","useMarkupColumnsOptions","getMarkupColumnsOptions","useMultipleAlignmentData","getMultipleAlignmentData","pFrame","sequenceColumnPredicate","options","column","spec","columnId","readAnnotation","Annotation","defaults","value","sequenceColumnIds","pFrameDriver","columns","sequenceColumnsAxes","id","canonicalizeJson","getAxisId","optionMap","axisIdJson","axisSpec","axisId","parseJson","labelColumn","isLabelColumn","matchAxisId","compatibleColumns","columnIdJson","label","columnPairs","sequenceColumn","readAnnotationJson","isJsonEqual","key","_a","markupColumn","domainDiff","domainDiffJson","labelColumnIds","selection","colorScheme","alignmentParams","shouldBuildPhylogeneticTree","abortSignal","table","getTableData","rowCount","exceedsLimit","rawSequences","extractSequences","labels","extractLabels","markups","extractMarkups","highlightLegend","alignedSequences","name","rows","alignSequences","phylogeneticTree","buildPhylogeneticTree","rowOrder","sequencesColumn","i","labelsColumn","markupsColumn","index","residueCounts","getResidueCounts","image","generateHighlightImage","blobToBase64","linkerColumns","isLinkerColumn","filterColumn","createRowSelectionColumn","primaryEntry","secondaryEntry","sorting","request","columnIds","row","pTableValue","parseMarkup","cache","sequences","hash","objectHash","result","runInWorker","markup","highlightByChemicalProperties","highlightByMarkup","sequence","markupRow","markupAlignedSequence","blob","resolve","reject","reader","data","concatenatedSequences","worker","message","error","cb","ref","isLoading","requestId","paramsGetter","watch","params","prevParams","abortController","currentRequestId","onWatcherCleanup","err","ensureError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data.js","sources":["../../../src/components/PlMultiSequenceAlignment/data.ts"],"sourcesContent":["import { isJsonEqual } from '@milaboratories/helpers';\nimport type { ListOptionNormalized } from '@milaboratories/uikit';\nimport {\n Annotation,\n type CalculateTableDataRequest,\n type CalculateTableDataResponse,\n type CanonicalizedJson,\n canonicalizeJson,\n createRowSelectionColumn,\n ensureError,\n getAxisId,\n getRawPlatformaInstance,\n isLabelColumn,\n isLinkerColumn,\n type JoinEntry,\n matchAxisId,\n parseJson,\n type PColumnIdAndSpec,\n type PFrameHandle,\n type PlMultiSequenceAlignmentColorSchemeOption,\n type PlMultiSequenceAlignmentSettings,\n type PlSelectionModel,\n type PObjectId,\n type PTableColumnId,\n type PTableSorting,\n pTableValue,\n readAnnotation,\n readAnnotationJson,\n} from '@platforma-sdk/model';\nimport { onWatcherCleanup, ref, watch } from 'vue';\nimport { objectHash } from '../../objectHash';\nimport { highlightByChemicalProperties } from './chemical-properties';\nimport type { Markup } from './markup';\nimport {\n highlightByMarkup,\n markupAlignedSequence,\n parseMarkup,\n} from './markup';\nimport type * as MultiSequenceAlignmentWorker from './multi-sequence-alignment.worker';\nimport type * as PhylogeneticTreeWorker from './phylogenetic-tree.worker';\nimport { getResidueCounts } from './residue-counts';\nimport type { HighlightLegend, ResidueCounts } from './types';\n\nconst getPFrameDriver = () => getRawPlatformaInstance().pFrameDriver;\n\nexport const SEQUENCE_LIMIT = 1000;\n\nexport const useSequenceColumnsOptions = refreshOnDeepChange(\n getSequenceColumnsOptions,\n);\n\nexport const useLabelColumnsOptions = refreshOnDeepChange(\n getLabelColumnsOptions,\n);\n\nexport const useMarkupColumnsOptions = refreshOnDeepChange(\n getMarkupColumnsOptions,\n);\n\nexport const useMultipleAlignmentData = refreshOnDeepChange(\n getMultipleAlignmentData,\n);\n\nasync function getSequenceColumnsOptions({ pFrame, sequenceColumnPredicate }: {\n pFrame: PFrameHandle | undefined;\n sequenceColumnPredicate: (column: PColumnIdAndSpec) => boolean;\n}): Promise<OptionsWithDefaults<PObjectId> | undefined> {\n if (!pFrame) return;\n\n const pFrameDriver = getPFrameDriver();\n const columns = await pFrameDriver.listColumns(pFrame);\n\n const options = columns.values()\n .filter((column) => sequenceColumnPredicate(column))\n .map(({ spec, columnId }) => ({\n label: readAnnotation(spec, Annotation.Label) ?? 'Unlabeled column',\n value: columnId,\n }))\n .toArray();\n\n const defaults = options.map(({ value }) => value);\n\n return { options, defaults };\n}\n\nasync function getLabelColumnsOptions({ pFrame, sequenceColumnIds }: {\n pFrame: PFrameHandle | undefined;\n sequenceColumnIds: PObjectId[] | undefined;\n}): Promise<OptionsWithDefaults<PTableColumnId> | undefined> {\n if (!pFrame || !sequenceColumnIds) return;\n\n const pFrameDriver = getPFrameDriver();\n const columns = await pFrameDriver.listColumns(pFrame);\n\n const sequenceColumnsAxes = new Map(\n sequenceColumnIds.values().flatMap((id) => {\n const column = columns.find(({ columnId }) => columnId === id);\n if (!column) {\n throw new Error(`Couldn't find sequence column (ID: \\`${id}\\`).`);\n }\n return column.spec.axesSpec.values()\n .map((spec) => [canonicalizeJson(getAxisId(spec)), spec]);\n }),\n );\n\n const optionMap = new Map<CanonicalizedJson<PTableColumnId>, string>();\n for (const [axisIdJson, axisSpec] of sequenceColumnsAxes.entries()) {\n const axisId = parseJson(axisIdJson);\n const labelColumn = columns.find(({ spec }) =>\n isLabelColumn(spec) && matchAxisId(axisId, getAxisId(spec.axesSpec[0])),\n );\n optionMap.set(\n labelColumn\n ? canonicalizeJson({ type: 'column', id: labelColumn.columnId })\n : canonicalizeJson({ type: 'axis', id: axisId }),\n readAnnotation(labelColumn?.spec, Annotation.Label)\n ?? readAnnotation(axisSpec, Annotation.Label)\n ?? 'Unlabeled axis',\n );\n }\n\n const { hits: compatibleColumns } = await pFrameDriver.findColumns(pFrame, {\n columnFilter: {},\n compatibleWith: sequenceColumnsAxes.keys()\n .map((axisIdJson) => parseJson(axisIdJson))\n .toArray(),\n strictlyCompatible: false,\n });\n\n for (const { columnId, spec } of compatibleColumns) {\n const columnIdJson = canonicalizeJson<PTableColumnId>({\n type: 'column',\n id: columnId,\n });\n if (optionMap.has(columnIdJson)) continue;\n optionMap.set(\n columnIdJson,\n readAnnotation(spec, Annotation.Label) ?? 'Unlabeled column',\n );\n }\n\n const options = optionMap.entries()\n .map(([value, label]) => ({ label, value: parseJson(value) }))\n .toArray();\n\n const defaults = options.values()\n .filter(({ value }) => {\n if (value.type === 'axis') return true;\n const column = columns.find(({ columnId }) => columnId === value.id);\n return column && isLabelColumn(column.spec);\n })\n .map(({ value }) => value)\n .toArray();\n\n return { options, defaults };\n}\n\nasync function getMarkupColumnsOptions({ pFrame, sequenceColumnIds }: {\n pFrame: PFrameHandle | undefined;\n sequenceColumnIds: PObjectId[] | undefined;\n}): Promise<ListOptionNormalized<PObjectId[]>[] | undefined> {\n if (!pFrame || !sequenceColumnIds) return;\n\n const pFrameDriver = getPFrameDriver();\n const columns = await pFrameDriver.listColumns(pFrame);\n\n const sequenceColumns = sequenceColumnIds.map((columnId) => {\n const column = columns.find((column) => column.columnId === columnId);\n if (!column) {\n throw new Error(\n `Couldn't find sequence column (ID: \\`${sequenceColumnIds[0]}\\`).`,\n );\n }\n return column;\n });\n\n const columnPairs = sequenceColumns\n .flatMap((sequenceColumn) =>\n columns\n .filter((column) =>\n readAnnotationJson(column.spec, Annotation.Sequence.IsAnnotation)\n && isJsonEqual(sequenceColumn.spec.axesSpec, column.spec.axesSpec)\n && Object.entries(sequenceColumn.spec.domain ?? {})\n .every(([key, value]) => column.spec.domain?.[key] === value),\n )\n .map((markupColumn) => ({ markupColumn, sequenceColumn })),\n );\n\n const groupedByDomainDiff = Map.groupBy(\n columnPairs,\n ({ markupColumn, sequenceColumn }) => {\n const domainDiff = Object.fromEntries(\n Object.entries(markupColumn.spec.domain ?? {})\n .filter(([key]) => sequenceColumn.spec.domain?.[key] == undefined),\n );\n return canonicalizeJson(domainDiff);\n },\n );\n\n return groupedByDomainDiff.entries()\n .map(([domainDiffJson, columnPairs]) => ({\n label: Object.values(parseJson(domainDiffJson)).join(', '),\n value: columnPairs.map(({ markupColumn }) => markupColumn.columnId),\n }))\n .toArray();\n}\n\nasync function getMultipleAlignmentData(\n {\n pFrame,\n sequenceColumnIds,\n labelColumnIds,\n selection,\n colorScheme,\n alignmentParams,\n shouldBuildPhylogeneticTree,\n }: {\n pFrame: PFrameHandle | undefined;\n sequenceColumnIds: PObjectId[] | undefined;\n labelColumnIds: PTableColumnId[] | undefined;\n selection: PlSelectionModel | undefined;\n colorScheme: PlMultiSequenceAlignmentColorSchemeOption;\n alignmentParams: PlMultiSequenceAlignmentSettings['alignmentParams'];\n shouldBuildPhylogeneticTree: boolean;\n },\n abortSignal: AbortSignal,\n): Promise<MultipleAlignmentData | undefined> {\n if (!pFrame || !sequenceColumnIds?.length || !labelColumnIds) return;\n\n const table = await getTableData({\n pFrame,\n sequenceColumnIds,\n labelColumnIds,\n selection,\n colorScheme,\n });\n\n const rowCount = table.at(0)?.data.data.length ?? 0;\n\n if (rowCount < 2) return;\n\n const exceedsLimit = rowCount > SEQUENCE_LIMIT;\n const rawSequences = extractSequences(sequenceColumnIds, table);\n const labels = extractLabels(labelColumnIds, table);\n const markups = colorScheme.type === 'markup'\n ? extractMarkups(colorScheme.columnIds, table)\n : undefined;\n\n const highlightLegend: HighlightLegend = {};\n\n const alignedSequences = await Promise.all(\n rawSequences.map(async ({ name, rows }) => ({\n name,\n rows: await alignSequences(\n rows,\n JSON.parse(JSON.stringify(alignmentParams)),\n abortSignal,\n ),\n })),\n );\n\n let phylogeneticTree: PhylogeneticTreeWorker.TreeNodeData[] | undefined;\n if (shouldBuildPhylogeneticTree) {\n phylogeneticTree = await buildPhylogeneticTree(\n alignedSequences,\n abortSignal,\n );\n const rowOrder = phylogeneticTree.values()\n .filter(({ id }) => id >= 0)\n .map(({ id }) => id)\n .toArray();\n for (const sequencesColumn of alignedSequences) {\n sequencesColumn.rows = rowOrder.map((i) => sequencesColumn.rows[i]);\n }\n for (const labelsColumn of labels) {\n labelsColumn.rows = rowOrder.map((i) => labelsColumn.rows[i]);\n }\n for (const markupsColumn of markups ?? []) {\n markupsColumn.rows = rowOrder.map((i) => markupsColumn.rows[i]);\n }\n }\n\n const sequences = await Promise.all(\n alignedSequences.map(async ({ name, rows }, index) => {\n const residueCounts = getResidueCounts(rows);\n const image = generateHighlightImage({\n colorScheme,\n sequences: rows,\n residueCounts,\n markup: markups?.at(index),\n });\n if (image) {\n Object.assign(highlightLegend, image.legend);\n }\n return {\n name,\n rows,\n residueCounts,\n ...image && {\n highlightImageUrl: await blobToBase64(image.blob),\n },\n } satisfies MultipleAlignmentData['sequences'][number];\n }),\n );\n\n return {\n sequences,\n labels,\n ...Object.keys(highlightLegend).length && {\n highlightLegend,\n },\n ...phylogeneticTree && {\n phylogeneticTree,\n },\n exceedsLimit,\n };\n}\n\nasync function getTableData(\n { pFrame, sequenceColumnIds, labelColumnIds, selection, colorScheme }: {\n pFrame: PFrameHandle;\n sequenceColumnIds: PObjectId[];\n labelColumnIds: PTableColumnId[];\n selection: PlSelectionModel | undefined;\n colorScheme: PlMultiSequenceAlignmentColorSchemeOption;\n },\n): Promise<CalculateTableDataResponse> {\n const pFrameDriver = getPFrameDriver();\n const columns = await pFrameDriver.listColumns(pFrame);\n const linkerColumns = columns.filter((column) => isLinkerColumn(column.spec));\n\n const filterColumn = createRowSelectionColumn({ selection });\n\n // inner join of sequence columns\n let primaryEntry: JoinEntry<PObjectId> = {\n type: 'inner',\n entries: sequenceColumnIds.map((column) => ({\n type: 'column',\n column,\n })),\n };\n\n // if we have linkers, left join them\n if (linkerColumns.length > 0) {\n primaryEntry = {\n type: 'outer',\n primary: primaryEntry,\n secondary: linkerColumns.map(({ columnId }) => ({\n type: 'column',\n column: columnId,\n })),\n };\n }\n\n // inner join with filters\n if (filterColumn) {\n primaryEntry = {\n type: 'inner',\n entries: [\n primaryEntry,\n {\n type: 'inlineColumn',\n column: filterColumn,\n },\n ],\n };\n }\n\n // left join with labels\n const secondaryEntry: JoinEntry<PObjectId>[] = labelColumnIds\n .flatMap((column) => {\n if (column.type !== 'column') return [];\n return { type: 'column', column: column.id };\n });\n\n // and markup\n if (colorScheme.type === 'markup') {\n for (const column of colorScheme.columnIds) {\n secondaryEntry.push({ type: 'column', column });\n }\n }\n\n const sorting: PTableSorting[] = Array.from(\n new Set(\n sequenceColumnIds.values().flatMap((id) => {\n const column = columns.find(({ columnId }) => columnId === id);\n if (!column) {\n throw new Error(`Couldn't find sequence column (ID: ${id})`);\n }\n return column.spec.axesSpec\n .map((spec) => canonicalizeJson(getAxisId(spec)));\n }),\n ),\n )\n .sort()\n .map((id) => ({\n column: { type: 'axis', id: parseJson(id) },\n ascending: true,\n naAndAbsentAreLeastValues: true,\n }));\n\n const request: CalculateTableDataRequest<PObjectId> = {\n src: {\n type: 'outer',\n primary: primaryEntry,\n secondary: secondaryEntry,\n },\n filters: [],\n sorting,\n };\n\n return pFrameDriver.calculateTableData(\n pFrame,\n JSON.parse(JSON.stringify(request)),\n {\n offset: 0,\n // +1 is a hack to check whether the selection is over the limit\n length: SEQUENCE_LIMIT + 1,\n },\n );\n}\n\nconst extractSequences = (\n columnIds: PObjectId[],\n table: CalculateTableDataResponse,\n): { name: string; rows: string[] }[] =>\n columnIds.map((columnId) => {\n const column = table.find(({ spec }) => spec.id === columnId);\n if (!column) {\n throw new Error(`Couldn't find sequence column (ID: \\`${columnId}\\`).`);\n }\n const name = readAnnotation(column.spec.spec, Annotation.Label)\n ?? 'Unlabeled column';\n const rows = column.data.data\n .keys()\n .take(SEQUENCE_LIMIT)\n .map((row) =>\n pTableValue(column.data, row, { absent: '', na: '' })?.toString()\n ?? '',\n )\n .toArray();\n return { name, rows };\n });\n\nconst extractLabels = (\n columnIds: PTableColumnId[],\n table: CalculateTableDataResponse,\n): { rows: string[] }[] =>\n columnIds.map((columnId) => {\n const column = table.find(({ spec }) => {\n if (columnId.type === 'axis' && spec.type === 'axis') {\n return isJsonEqual(columnId.id, spec.id);\n }\n if (columnId.type === 'column' && spec.type === 'column') {\n return columnId.id === spec.id;\n }\n });\n if (!column) {\n throw new Error(`Couldn't find label column (ID: \\`${columnId}\\`).`);\n }\n const rows = column.data.data\n .keys()\n .take(SEQUENCE_LIMIT)\n .map((row) =>\n pTableValue(column.data, row, { absent: '', na: '' })?.toString()\n ?? '',\n )\n .toArray();\n return { rows };\n });\n\nconst extractMarkups = (\n columnIds: PObjectId[],\n table: CalculateTableDataResponse,\n): { labels: Record<string, string>; rows: Markup[] }[] =>\n columnIds.map((columnId) => {\n const column = table.find(({ spec }) => spec.id === columnId);\n if (!column) {\n throw new Error(`Couldn't find markup column (ID: \\`${columnId}\\`).`);\n }\n const labels = readAnnotationJson(\n column.spec.spec,\n Annotation.Sequence.Annotation.Mapping,\n ) ?? {};\n const rows = column.data.data\n .keys()\n .take(SEQUENCE_LIMIT)\n .map((row) =>\n parseMarkup(\n pTableValue(column.data, row, { absent: '', na: '' })?.toString()\n ?? '',\n ),\n )\n .toArray();\n return { labels, rows };\n });\n\nconst alignSequences = (() => {\n const cache = new Map<string, string[]>();\n return async (\n sequences: string[],\n alignmentParams: PlMultiSequenceAlignmentSettings['alignmentParams'],\n abortSignal: AbortSignal,\n ): Promise<string[]> => {\n const hash = await objectHash([sequences, alignmentParams]);\n let result = cache.get(hash);\n if (result) return result;\n result = await runInWorker<\n MultiSequenceAlignmentWorker.RequestMessage,\n MultiSequenceAlignmentWorker.ResponseMessage\n >(\n new Worker(\n new URL('./multi-sequence-alignment.worker.ts', import.meta.url),\n { type: 'module' },\n ),\n { sequences, params: alignmentParams },\n abortSignal,\n );\n cache.set(hash, result);\n return result;\n };\n})();\n\nfunction generateHighlightImage(\n { colorScheme, sequences, residueCounts, markup }: {\n colorScheme: PlMultiSequenceAlignmentColorSchemeOption;\n sequences: string[];\n residueCounts: ResidueCounts;\n markup: { labels: Record<string, string>; rows: Markup[] } | undefined;\n },\n): { blob: Blob; legend: HighlightLegend } | undefined {\n if (colorScheme.type === 'chemical-properties') {\n return highlightByChemicalProperties({ sequences, residueCounts });\n }\n if (colorScheme.type === 'markup') {\n if (!markup) {\n throw new Error('Missing markup data.');\n }\n return highlightByMarkup({\n markupRows: sequences.map((sequence, row) => {\n const markupRow = markup.rows.at(row);\n if (!markupRow) throw new Error(`Missing markup for row ${row}.`);\n return markupAlignedSequence(sequence, markupRow);\n }),\n columnCount: sequences.at(0)?.length ?? 0,\n labels: markup.labels,\n });\n }\n}\n\nconst blobToBase64 = (blob: Blob): Promise<string> =>\n new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.addEventListener('load', () => resolve(reader.result as string));\n reader.addEventListener('error', () => reject(reader.error));\n reader.readAsDataURL(blob);\n });\n\nconst buildPhylogeneticTree = (() => {\n const cache = new Map<string, PhylogeneticTreeWorker.TreeNodeData[]>();\n return async (data: { rows: string[] }[], abortSignal: AbortSignal) => {\n const concatenatedSequences = data.at(0)?.rows\n .keys()\n .map((row) => data.map((column) => column.rows.at(row) ?? '').join(''))\n .toArray() ?? [];\n const hash = await objectHash(concatenatedSequences);\n let result = cache.get(hash);\n if (result) return result;\n result = await runInWorker<\n PhylogeneticTreeWorker.RequestMessage,\n PhylogeneticTreeWorker.ResponseMessage\n >(\n new Worker(\n new URL('./phylogenetic-tree.worker.ts', import.meta.url),\n { type: 'module' },\n ),\n concatenatedSequences,\n abortSignal,\n );\n cache.set(hash, result);\n return result;\n };\n})();\n\nconst runInWorker = <RequestMessage, ResponseMessage>(\n worker: Worker,\n message: RequestMessage,\n abortSignal: AbortSignal,\n) =>\n new Promise<ResponseMessage>((resolve, reject) => {\n worker.addEventListener('message', ({ data }) => {\n resolve(data);\n worker.terminate();\n });\n worker.addEventListener('error', ({ error, message }) => {\n reject(error ?? message);\n worker.terminate();\n });\n abortSignal.addEventListener('abort', () => {\n reject(abortSignal.reason);\n worker.terminate();\n });\n worker.postMessage(message);\n });\n\nfunction refreshOnDeepChange<T, P>(\n cb: (params: P, abortSignal: AbortSignal) => Promise<T>,\n) {\n const data = ref<T>();\n const isLoading = ref(true);\n const error = ref<Error>();\n let requestId: symbol;\n return (paramsGetter: () => P) => {\n watch(paramsGetter, async (params, prevParams) => {\n if (isJsonEqual(params, prevParams)) return;\n const abortController = new AbortController();\n const currentRequestId = requestId = Symbol();\n onWatcherCleanup(() => {\n abortController.abort();\n });\n try {\n error.value = undefined;\n isLoading.value = true;\n const result = await cb(params, abortController.signal);\n if (currentRequestId === requestId) {\n data.value = result;\n }\n } catch (err) {\n console.error(err);\n if (currentRequestId === requestId) {\n error.value = ensureError(err);\n }\n } finally {\n if (currentRequestId === requestId) {\n isLoading.value = false;\n }\n }\n }, { immediate: true });\n return { data, isLoading, error };\n };\n}\n\ntype MultipleAlignmentData = {\n sequences: {\n name: string;\n rows: string[];\n residueCounts: ResidueCounts;\n highlightImageUrl?: string;\n }[];\n labels: {\n rows: string[];\n }[];\n highlightLegend?: HighlightLegend;\n phylogeneticTree?: PhylogeneticTreeWorker.TreeNodeData[];\n exceedsLimit: boolean;\n};\n\ntype OptionsWithDefaults<T> = {\n options: ListOptionNormalized<T>[];\n defaults: T[];\n};\n"],"names":["getPFrameDriver","getRawPlatformaInstance","SEQUENCE_LIMIT","useSequenceColumnsOptions","refreshOnDeepChange","getSequenceColumnsOptions","useLabelColumnsOptions","getLabelColumnsOptions","useMarkupColumnsOptions","getMarkupColumnsOptions","useMultipleAlignmentData","getMultipleAlignmentData","pFrame","sequenceColumnPredicate","options","column","spec","columnId","readAnnotation","Annotation","defaults","value","sequenceColumnIds","pFrameDriver","columns","sequenceColumnsAxes","id","canonicalizeJson","getAxisId","optionMap","axisIdJson","axisSpec","axisId","parseJson","labelColumn","isLabelColumn","matchAxisId","compatibleColumns","columnIdJson","label","columnPairs","sequenceColumn","readAnnotationJson","isJsonEqual","key","_a","markupColumn","domainDiff","domainDiffJson","labelColumnIds","selection","colorScheme","alignmentParams","shouldBuildPhylogeneticTree","abortSignal","table","getTableData","rowCount","exceedsLimit","rawSequences","extractSequences","labels","extractLabels","markups","extractMarkups","highlightLegend","alignedSequences","name","rows","alignSequences","phylogeneticTree","buildPhylogeneticTree","rowOrder","sequencesColumn","i","labelsColumn","markupsColumn","index","residueCounts","getResidueCounts","image","generateHighlightImage","blobToBase64","linkerColumns","isLinkerColumn","filterColumn","createRowSelectionColumn","primaryEntry","secondaryEntry","sorting","request","columnIds","row","pTableValue","parseMarkup","cache","sequences","hash","objectHash","result","runInWorker","markup","highlightByChemicalProperties","highlightByMarkup","sequence","markupRow","markupAlignedSequence","blob","resolve","reject","reader","data","concatenatedSequences","worker","message","error","cb","ref","isLoading","requestId","paramsGetter","watch","params","prevParams","abortController","currentRequestId","onWatcherCleanup","err","ensureError"],"mappings":";;;;;;;AA2CA,MAAMA,IAAkB,MAAMC,EAAA,EAA0B,cAE3CC,IAAiB,KAEjBC,KAA4BC;AAAA,EACvCC;AACF,GAEaC,KAAyBF;AAAA,EACpCG;AACF,GAEaC,KAA0BJ;AAAA,EACrCK;AACF,GAEaC,KAA2BN;AAAA,EACtCO;AACF;AAEA,eAAeN,EAA0B,EAAE,QAAAO,GAAQ,yBAAAC,KAGK;AACtD,MAAI,CAACD,EAAQ;AAKb,QAAME,KAFU,MADKd,EAAA,EACc,YAAYY,CAAM,GAE7B,OAAA,EACrB,OAAO,CAACG,MAAWF,EAAwBE,CAAM,CAAC,EAClD,IAAI,CAAC,EAAE,MAAAC,GAAM,UAAAC,SAAgB;AAAA,IAC5B,OAAOC,EAAeF,GAAMG,EAAW,KAAK,KAAK;AAAA,IACjD,OAAOF;AAAA,EAAA,EACP,EACD,QAAA,GAEGG,IAAWN,EAAQ,IAAI,CAAC,EAAE,OAAAO,EAAA,MAAYA,CAAK;AAEjD,SAAO,EAAE,SAAAP,GAAS,UAAAM,EAAA;AACpB;AAEA,eAAeb,EAAuB,EAAE,QAAAK,GAAQ,mBAAAU,KAGa;AAC3D,MAAI,CAACV,KAAU,CAACU,EAAmB;AAEnC,QAAMC,IAAevB,EAAA,GACfwB,IAAU,MAAMD,EAAa,YAAYX,CAAM,GAE/Ca,IAAsB,IAAI;AAAA,IAC9BH,EAAkB,OAAA,EAAS,QAAQ,CAACI,MAAO;AACzC,YAAMX,IAASS,EAAQ,KAAK,CAAC,EAAE,UAAAP,EAAA,MAAeA,MAAaS,CAAE;AAC7D,UAAI,CAACX;AACH,cAAM,IAAI,MAAM,wCAAwCW,CAAE,MAAM;AAElE,aAAOX,EAAO,KAAK,SAAS,OAAA,EACzB,IAAI,CAACC,MAAS,CAACW,EAAiBC,EAAUZ,CAAI,CAAC,GAAGA,CAAI,CAAC;AAAA,IAC5D,CAAC;AAAA,EAAA,GAGGa,wBAAgB,IAAA;AACtB,aAAW,CAACC,GAAYC,CAAQ,KAAKN,EAAoB,WAAW;AAClE,UAAMO,IAASC,EAAUH,CAAU,GAC7BI,IAAcV,EAAQ;AAAA,MAAK,CAAC,EAAE,MAAAR,EAAA,MAClCmB,EAAcnB,CAAI,KAAKoB,EAAYJ,GAAQJ,EAAUZ,EAAK,SAAS,CAAC,CAAC,CAAC;AAAA,IAAA;AAExE,IAAAa,EAAU;AAAA,MACRK,IACIP,EAAiB,EAAE,MAAM,UAAU,IAAIO,EAAY,SAAA,CAAU,IAC7DP,EAAiB,EAAE,MAAM,QAAQ,IAAIK,GAAQ;AAAA,MACjDd,EAAegB,KAAA,gBAAAA,EAAa,MAAMf,EAAW,KAAK,KAC/CD,EAAea,GAAUZ,EAAW,KAAK,KACzC;AAAA,IAAA;AAAA,EAEP;AAEA,QAAM,EAAE,MAAMkB,EAAA,IAAsB,MAAMd,EAAa,YAAYX,GAAQ;AAAA,IACzE,cAAc,CAAA;AAAA,IACd,gBAAgBa,EAAoB,KAAA,EACjC,IAAI,CAACK,MAAeG,EAAUH,CAAU,CAAC,EACzC,QAAA;AAAA,IACH,oBAAoB;AAAA,EAAA,CACrB;AAED,aAAW,EAAE,UAAAb,GAAU,MAAAD,EAAA,KAAUqB,GAAmB;AAClD,UAAMC,IAAeX,EAAiC;AAAA,MACpD,MAAM;AAAA,MACN,IAAIV;AAAA,IAAA,CACL;AACD,IAAIY,EAAU,IAAIS,CAAY,KAC9BT,EAAU;AAAA,MACRS;AAAA,MACApB,EAAeF,GAAMG,EAAW,KAAK,KAAK;AAAA,IAAA;AAAA,EAE9C;AAEA,QAAML,IAAUe,EAAU,QAAA,EACvB,IAAI,CAAC,CAACR,GAAOkB,CAAK,OAAO,EAAE,OAAAA,GAAO,OAAON,EAAUZ,CAAK,EAAA,EAAI,EAC5D,QAAA,GAEGD,IAAWN,EAAQ,OAAA,EACtB,OAAO,CAAC,EAAE,OAAAO,QAAY;AACrB,QAAIA,EAAM,SAAS,OAAQ,QAAO;AAClC,UAAMN,IAASS,EAAQ,KAAK,CAAC,EAAE,UAAAP,QAAeA,MAAaI,EAAM,EAAE;AACnE,WAAON,KAAUoB,EAAcpB,EAAO,IAAI;AAAA,EAC5C,CAAC,EACA,IAAI,CAAC,EAAE,OAAAM,EAAA,MAAYA,CAAK,EACxB,QAAA;AAEH,SAAO,EAAE,SAAAP,GAAS,UAAAM,EAAA;AACpB;AAEA,eAAeX,EAAwB,EAAE,QAAAG,GAAQ,mBAAAU,KAGY;AAC3D,MAAI,CAACV,KAAU,CAACU,EAAmB;AAGnC,QAAME,IAAU,MADKxB,EAAA,EACc,YAAYY,CAAM,GAY/C4B,IAVkBlB,EAAkB,IAAI,CAACL,MAAa;AAC1D,UAAMF,IAASS,EAAQ,KAAK,CAACT,MAAWA,EAAO,aAAaE,CAAQ;AACpE,QAAI,CAACF;AACH,YAAM,IAAI;AAAA,QACR,wCAAwCO,EAAkB,CAAC,CAAC;AAAA,MAAA;AAGhE,WAAOP;AAAA,EACT,CAAC,EAGE;AAAA,IAAQ,CAAC0B,MACRjB,EACG;AAAA,MAAO,CAACT,MACP2B,EAAmB3B,EAAO,MAAMI,EAAW,SAAS,YAAY,KAC7DwB,EAAYF,EAAe,KAAK,UAAU1B,EAAO,KAAK,QAAQ,KAC9D,OAAO,QAAQ0B,EAAe,KAAK,UAAU,CAAA,CAAE,EAC/C,MAAM,CAAC,CAACG,GAAKvB,CAAK;;AAAM,iBAAAwB,IAAA9B,EAAO,KAAK,WAAZ,gBAAA8B,EAAqBD,QAASvB;AAAA,OAAK;AAAA,IAAA,EAE/D,IAAI,CAACyB,OAAkB,EAAE,cAAAA,GAAc,gBAAAL,IAAiB;AAAA,EAAA;AAc/D,SAX4B,IAAI;AAAA,IAC9BD;AAAA,IACA,CAAC,EAAE,cAAAM,GAAc,gBAAAL,QAAqB;AACpC,YAAMM,IAAa,OAAO;AAAA,QACxB,OAAO,QAAQD,EAAa,KAAK,UAAU,CAAA,CAAE,EAC1C,OAAO,CAAC,CAACF,CAAG,MAAA;;AAAM,mBAAAC,IAAAJ,EAAe,KAAK,WAApB,gBAAAI,EAA6BD,OAAQ;AAAA,SAAS;AAAA,MAAA;AAErE,aAAOjB,EAAiBoB,CAAU;AAAA,IACpC;AAAA,EAAA,EAGyB,UACxB,IAAI,CAAC,CAACC,GAAgBR,CAAW,OAAO;AAAA,IACvC,OAAO,OAAO,OAAOP,EAAUe,CAAc,CAAC,EAAE,KAAK,IAAI;AAAA,IACzD,OAAOR,EAAY,IAAI,CAAC,EAAE,cAAAM,EAAA,MAAmBA,EAAa,QAAQ;AAAA,EAAA,EAClE,EACD,QAAA;AACL;AAEA,eAAenC,EACb;AAAA,EACE,QAAAC;AAAA,EACA,mBAAAU;AAAA,EACA,gBAAA2B;AAAA,EACA,WAAAC;AAAA,EACA,aAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,6BAAAC;AACF,GASAC,GAC4C;;AAC5C,MAAI,CAAC1C,KAAU,EAACU,KAAA,QAAAA,EAAmB,WAAU,CAAC2B,EAAgB;AAE9D,QAAMM,IAAQ,MAAMC,GAAa;AAAA,IAC/B,QAAA5C;AAAA,IACA,mBAAAU;AAAA,IACA,gBAAA2B;AAAA,IACA,WAAAC;AAAA,IACA,aAAAC;AAAA,EAAA,CACD,GAEKM,MAAWZ,IAAAU,EAAM,GAAG,CAAC,MAAV,gBAAAV,EAAa,KAAK,KAAK,WAAU;AAElD,MAAIY,IAAW,EAAG;AAElB,QAAMC,IAAeD,IAAWvD,GAC1ByD,IAAeC,GAAiBtC,GAAmBiC,CAAK,GACxDM,IAASC,GAAcb,GAAgBM,CAAK,GAC5CQ,IAAUZ,EAAY,SAAS,WACjCa,GAAeb,EAAY,WAAWI,CAAK,IAC3C,QAEEU,IAAmC,CAAA,GAEnCC,IAAmB,MAAM,QAAQ;AAAA,IACrCP,EAAa,IAAI,OAAO,EAAE,MAAAQ,GAAM,MAAAC,SAAY;AAAA,MAC1C,MAAAD;AAAA,MACA,MAAM,MAAME;AAAA,QACVD;AAAA,QACA,KAAK,MAAM,KAAK,UAAUhB,CAAe,CAAC;AAAA,QAC1CE;AAAA,MAAA;AAAA,IACF,EACA;AAAA,EAAA;AAGJ,MAAIgB;AACJ,MAAIjB,GAA6B;AAC/B,IAAAiB,IAAmB,MAAMC;AAAA,MACvBL;AAAA,MACAZ;AAAA,IAAA;AAEF,UAAMkB,IAAWF,EAAiB,OAAA,EAC/B,OAAO,CAAC,EAAE,IAAA5C,EAAA,MAASA,KAAM,CAAC,EAC1B,IAAI,CAAC,EAAE,IAAAA,QAASA,CAAE,EAClB,QAAA;AACH,eAAW+C,KAAmBP;AAC5B,MAAAO,EAAgB,OAAOD,EAAS,IAAI,CAACE,MAAMD,EAAgB,KAAKC,CAAC,CAAC;AAEpE,eAAWC,KAAgBd;AACzB,MAAAc,EAAa,OAAOH,EAAS,IAAI,CAACE,MAAMC,EAAa,KAAKD,CAAC,CAAC;AAE9D,eAAWE,KAAiBb,KAAW;AACrC,MAAAa,EAAc,OAAOJ,EAAS,IAAI,CAACE,MAAME,EAAc,KAAKF,CAAC,CAAC;AAAA,EAElE;AAyBA,SAAO;AAAA,IACL,WAxBgB,MAAM,QAAQ;AAAA,MAC9BR,EAAiB,IAAI,OAAO,EAAE,MAAAC,GAAM,MAAAC,EAAA,GAAQS,MAAU;AACpD,cAAMC,IAAgBC,EAAiBX,CAAI,GACrCY,IAAQC,GAAuB;AAAA,UACnC,aAAA9B;AAAA,UACA,WAAWiB;AAAA,UACX,eAAAU;AAAA,UACA,QAAQf,KAAA,gBAAAA,EAAS,GAAGc;AAAA,QAAK,CAC1B;AACD,eAAIG,KACF,OAAO,OAAOf,GAAiBe,EAAM,MAAM,GAEtC;AAAA,UACL,MAAAb;AAAA,UACA,MAAAC;AAAA,UACA,eAAAU;AAAA,UACA,GAAGE,KAAS;AAAA,YACV,mBAAmB,MAAME,GAAaF,EAAM,IAAI;AAAA,UAAA;AAAA,QAClD;AAAA,MAEJ,CAAC;AAAA,IAAA;AAAA,IAKD,QAAAnB;AAAA,IACA,GAAG,OAAO,KAAKI,CAAe,EAAE,UAAU;AAAA,MACxC,iBAAAA;AAAA,IAAA;AAAA,IAEF,GAAGK,KAAoB;AAAA,MACrB,kBAAAA;AAAA,IAAA;AAAA,IAEF,cAAAZ;AAAA,EAAA;AAEJ;AAEA,eAAeF,GACb,EAAE,QAAA5C,GAAQ,mBAAAU,GAAmB,gBAAA2B,GAAgB,WAAAC,GAAW,aAAAC,KAOnB;AACrC,QAAM5B,IAAevB,EAAA,GACfwB,IAAU,MAAMD,EAAa,YAAYX,CAAM,GAC/CuE,IAAgB3D,EAAQ,OAAO,CAACT,MAAWqE,EAAerE,EAAO,IAAI,CAAC,GAEtEsE,IAAeC,EAAyB,EAAE,WAAApC,GAAW;AAG3D,MAAIqC,IAAqC;AAAA,IACvC,MAAM;AAAA,IACN,SAASjE,EAAkB,IAAI,CAACP,OAAY;AAAA,MAC1C,MAAM;AAAA,MACN,QAAAA;AAAA,IAAA,EACA;AAAA,EAAA;AAIJ,EAAIoE,EAAc,SAAS,MACzBI,IAAe;AAAA,IACb,MAAM;AAAA,IACN,SAASA;AAAA,IACT,WAAWJ,EAAc,IAAI,CAAC,EAAE,UAAAlE,SAAgB;AAAA,MAC9C,MAAM;AAAA,MACN,QAAQA;AAAA,IAAA,EACR;AAAA,EAAA,IAKFoE,MACFE,IAAe;AAAA,IACb,MAAM;AAAA,IACN,SAAS;AAAA,MACPA;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,QAAQF;AAAA,MAAA;AAAA,IACV;AAAA,EACF;AAKJ,QAAMG,IAAyCvC,EAC5C,QAAQ,CAAClC,MACJA,EAAO,SAAS,WAAiB,CAAA,IAC9B,EAAE,MAAM,UAAU,QAAQA,EAAO,GAAA,CACzC;AAGH,MAAIoC,EAAY,SAAS;AACvB,eAAWpC,KAAUoC,EAAY;AAC/B,MAAAqC,EAAe,KAAK,EAAE,MAAM,UAAU,QAAAzE,GAAQ;AAIlD,QAAM0E,IAA2B,MAAM;AAAA,IACrC,IAAI;AAAA,MACFnE,EAAkB,OAAA,EAAS,QAAQ,CAACI,MAAO;AACzC,cAAMX,IAASS,EAAQ,KAAK,CAAC,EAAE,UAAAP,EAAA,MAAeA,MAAaS,CAAE;AAC7D,YAAI,CAACX;AACH,gBAAM,IAAI,MAAM,sCAAsCW,CAAE,GAAG;AAE7D,eAAOX,EAAO,KAAK,SAChB,IAAI,CAACC,MAASW,EAAiBC,EAAUZ,CAAI,CAAC,CAAC;AAAA,MACpD,CAAC;AAAA,IAAA;AAAA,EACH,EAEC,KAAA,EACA,IAAI,CAACU,OAAQ;AAAA,IACZ,QAAQ,EAAE,MAAM,QAAQ,IAAIO,EAAUP,CAAE,EAAA;AAAA,IACxC,WAAW;AAAA,IACX,2BAA2B;AAAA,EAAA,EAC3B,GAEEgE,IAAgD;AAAA,IACpD,KAAK;AAAA,MACH,MAAM;AAAA,MACN,SAASH;AAAA,MACT,WAAWC;AAAA,IAAA;AAAA,IAEb,SAAS,CAAA;AAAA,IACT,SAAAC;AAAA,EAAA;AAGF,SAAOlE,EAAa;AAAA,IAClBX;AAAA,IACA,KAAK,MAAM,KAAK,UAAU8E,CAAO,CAAC;AAAA,IAClC;AAAA,MACE,QAAQ;AAAA;AAAA,MAER,QAAQxF,IAAiB;AAAA,IAAA;AAAA,EAC3B;AAEJ;AAEA,MAAM0D,KAAmB,CACvB+B,GACApC,MAEAoC,EAAU,IAAI,CAAC1E,MAAa;AAC1B,QAAMF,IAASwC,EAAM,KAAK,CAAC,EAAE,MAAAvC,QAAWA,EAAK,OAAOC,CAAQ;AAC5D,MAAI,CAACF;AACH,UAAM,IAAI,MAAM,wCAAwCE,CAAQ,MAAM;AAExE,QAAMkD,IAAOjD,EAAeH,EAAO,KAAK,MAAMI,EAAW,KAAK,KACzD,oBACCiD,IAAOrD,EAAO,KAAK,KACtB,OACA,KAAKb,CAAc,EACnB;AAAA,IAAI,CAAC0F,MAAA;;AACJ,eAAA/C,IAAAgD,EAAY9E,EAAO,MAAM6E,GAAK,EAAE,QAAQ,IAAI,IAAI,IAAI,MAApD,gBAAA/C,EAAuD,eACpD;AAAA;AAAA,EAAA,EAEJ,QAAA;AACH,SAAO,EAAE,MAAAsB,GAAM,MAAAC,EAAA;AACjB,CAAC,GAEGN,KAAgB,CACpB6B,GACApC,MAEAoC,EAAU,IAAI,CAAC1E,MAAa;AAC1B,QAAMF,IAASwC,EAAM,KAAK,CAAC,EAAE,MAAAvC,QAAW;AACtC,QAAIC,EAAS,SAAS,UAAUD,EAAK,SAAS;AAC5C,aAAO2B,EAAY1B,EAAS,IAAID,EAAK,EAAE;AAEzC,QAAIC,EAAS,SAAS,YAAYD,EAAK,SAAS;AAC9C,aAAOC,EAAS,OAAOD,EAAK;AAAA,EAEhC,CAAC;AACD,MAAI,CAACD;AACH,UAAM,IAAI,MAAM,qCAAqCE,CAAQ,MAAM;AAUrE,SAAO,EAAE,MARIF,EAAO,KAAK,KACtB,OACA,KAAKb,CAAc,EACnB;AAAA,IAAI,CAAC0F,MAAA;;AACJ,eAAA/C,IAAAgD,EAAY9E,EAAO,MAAM6E,GAAK,EAAE,QAAQ,IAAI,IAAI,IAAI,MAApD,gBAAA/C,EAAuD,eACpD;AAAA;AAAA,EAAA,EAEJ,QAAA,EACM;AACX,CAAC,GAEGmB,KAAiB,CACrB2B,GACApC,MAEAoC,EAAU,IAAI,CAAC1E,MAAa;AAC1B,QAAMF,IAASwC,EAAM,KAAK,CAAC,EAAE,MAAAvC,QAAWA,EAAK,OAAOC,CAAQ;AAC5D,MAAI,CAACF;AACH,UAAM,IAAI,MAAM,sCAAsCE,CAAQ,MAAM;AAEtE,QAAM4C,IAASnB;AAAA,IACb3B,EAAO,KAAK;AAAA,IACZI,EAAW,SAAS,WAAW;AAAA,EAAA,KAC5B,CAAA,GACCiD,IAAOrD,EAAO,KAAK,KACtB,OACA,KAAKb,CAAc,EACnB;AAAA,IAAI,CAAC0F,MAAA;;AACJ,aAAAE;AAAA,UACEjD,IAAAgD,EAAY9E,EAAO,MAAM6E,GAAK,EAAE,QAAQ,IAAI,IAAI,IAAI,MAApD,gBAAA/C,EAAuD,eACpD;AAAA,MAAA;AAAA;AAAA,EACL,EAED,QAAA;AACH,SAAO,EAAE,QAAAgB,GAAQ,MAAAO,EAAA;AACnB,CAAC,GAEGC,KAAkB,uBAAM;AAC5B,QAAM0B,wBAAY,IAAA;AAClB,SAAO,OACLC,GACA5C,GACAE,MACsB;AACtB,UAAM2C,IAAO,MAAMC,EAAW,CAACF,GAAW5C,CAAe,CAAC;AAC1D,QAAI+C,IAASJ,EAAM,IAAIE,CAAI;AAC3B,WAAIE,MACJA,IAAS,MAAMC;AAAA,MAIb,IAAI;AAAA,QACF,IAAA;AAAA;AAAA,UAAA,KAAA,IAAA,IAAA,4DAAA,YAAA,GAAA,EAAA;AAAA,UAAA,YAAA;AAAA,QAAA;AAAA,QACA,EAAE,MAAM,SAAA;AAAA,MAAS;AAAA,MAEnB,EAAE,WAAAJ,GAAW,QAAQ5C,EAAA;AAAA,MACrBE;AAAA,IAAA,GAEFyC,EAAM,IAAIE,GAAME,CAAM,GACfA;AAAA,EACT;AACF,GAAA;AAEA,SAASlB,GACP,EAAE,aAAA9B,GAAa,WAAA6C,GAAW,eAAAlB,GAAe,QAAAuB,KAMY;;AACrD,MAAIlD,EAAY,SAAS;AACvB,WAAOmD,EAA8B,EAAE,WAAAN,GAAW,eAAAlB,GAAe;AAEnE,MAAI3B,EAAY,SAAS,UAAU;AACjC,QAAI,CAACkD;AACH,YAAM,IAAI,MAAM,sBAAsB;AAExC,WAAOE,EAAkB;AAAA,MACvB,YAAYP,EAAU,IAAI,CAACQ,GAAUZ,MAAQ;AAC3C,cAAMa,IAAYJ,EAAO,KAAK,GAAGT,CAAG;AACpC,YAAI,CAACa,EAAW,OAAM,IAAI,MAAM,0BAA0Bb,CAAG,GAAG;AAChE,eAAOc,EAAsBF,GAAUC,CAAS;AAAA,MAClD,CAAC;AAAA,MACD,eAAa5D,IAAAmD,EAAU,GAAG,CAAC,MAAd,gBAAAnD,EAAiB,WAAU;AAAA,MACxC,QAAQwD,EAAO;AAAA,IAAA,CAChB;AAAA,EACH;AACF;AAEA,MAAMnB,KAAe,CAACyB,MACpB,IAAI,QAAgB,CAACC,GAASC,MAAW;AACvC,QAAMC,IAAS,IAAI,WAAA;AACnB,EAAAA,EAAO,iBAAiB,QAAQ,MAAMF,EAAQE,EAAO,MAAgB,CAAC,GACtEA,EAAO,iBAAiB,SAAS,MAAMD,EAAOC,EAAO,KAAK,CAAC,GAC3DA,EAAO,cAAcH,CAAI;AAC3B,CAAC,GAEGpC,KAAyB,uBAAM;AACnC,QAAMwB,wBAAY,IAAA;AAClB,SAAO,OAAOgB,GAA4BzD,MAA6B;;AACrE,UAAM0D,MAAwBnE,IAAAkE,EAAK,GAAG,CAAC,MAAT,gBAAAlE,EAAY,KACvC,OACA,IAAI,CAAC+C,MAAQmB,EAAK,IAAI,CAAChG,MAAWA,EAAO,KAAK,GAAG6E,CAAG,KAAK,EAAE,EAAE,KAAK,EAAE,GACpE,cAAa,CAAA,GACVK,IAAO,MAAMC,EAAWc,CAAqB;AACnD,QAAIb,IAASJ,EAAM,IAAIE,CAAI;AAC3B,WAAIE,MACJA,IAAS,MAAMC;AAAA,MAIb,IAAI;AAAA,QACF,IAAA;AAAA;AAAA,UAAA,KAAA,IAAA,IAAA,qDAAA,YAAA,GAAA,EAAA;AAAA,UAAA,YAAA;AAAA,QAAA;AAAA,QACA,EAAE,MAAM,SAAA;AAAA,MAAS;AAAA,MAEnBY;AAAA,MACA1D;AAAA,IAAA,GAEFyC,EAAM,IAAIE,GAAME,CAAM,GACfA;AAAA,EACT;AACF,GAAA,GAEMC,IAAc,CAClBa,GACAC,GACA5D,MAEA,IAAI,QAAyB,CAACsD,GAASC,MAAW;AAChD,EAAAI,EAAO,iBAAiB,WAAW,CAAC,EAAE,MAAAF,QAAW;AAC/C,IAAAH,EAAQG,CAAI,GACZE,EAAO,UAAA;AAAA,EACT,CAAC,GACDA,EAAO,iBAAiB,SAAS,CAAC,EAAE,OAAAE,GAAO,SAAAD,QAAc;AACvD,IAAAL,EAAOM,KAASD,CAAO,GACvBD,EAAO,UAAA;AAAA,EACT,CAAC,GACD3D,EAAY,iBAAiB,SAAS,MAAM;AAC1C,IAAAuD,EAAOvD,EAAY,MAAM,GACzB2D,EAAO,UAAA;AAAA,EACT,CAAC,GACDA,EAAO,YAAYC,CAAO;AAC5B,CAAC;AAEH,SAAS9G,EACPgH,GACA;AACA,QAAML,IAAOM,EAAA,GACPC,IAAYD,EAAI,EAAI,GACpBF,IAAQE,EAAA;AACd,MAAIE;AACJ,SAAO,CAACC,OACNC,EAAMD,GAAc,OAAOE,GAAQC,MAAe;AAChD,QAAIhF,EAAY+E,GAAQC,CAAU,EAAG;AACrC,UAAMC,IAAkB,IAAI,gBAAA,GACtBC,IAAmBN,IAAY,OAAA;AACrC,IAAAO,EAAiB,MAAM;AACrB,MAAAF,EAAgB,MAAA;AAAA,IAClB,CAAC;AACD,QAAI;AACF,MAAAT,EAAM,QAAQ,QACdG,EAAU,QAAQ;AAClB,YAAMnB,IAAS,MAAMiB,EAAGM,GAAQE,EAAgB,MAAM;AACtD,MAAIC,MAAqBN,MACvBR,EAAK,QAAQZ;AAAA,IAEjB,SAAS4B,GAAK;AACZ,cAAQ,MAAMA,CAAG,GACbF,MAAqBN,MACvBJ,EAAM,QAAQa,EAAYD,CAAG;AAAA,IAEjC,UAAA;AACE,MAAIF,MAAqBN,MACvBD,EAAU,QAAQ;AAAA,IAEtB;AAAA,EACF,GAAG,EAAE,WAAW,IAAM,GACf,EAAE,MAAAP,GAAM,WAAAO,GAAW,OAAAH,EAAA;AAE9B;"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { defineComponent as k, mergeModels as x, useModel as y, computed as b, ref as v, watch as w, createBlock as c, openBlock as n, unref as r, withCtx as u, createElementVNode as B, createVNode as s, createElementBlock as P, createCommentVNode as V, createTextVNode as m } from "vue";
|
|
2
2
|
import { deepClone as M } from "../../lib/util/helpers/dist/objects.js";
|
|
3
|
-
import "../../lib/util/helpers/dist/test_timeouts.js";
|
|
4
3
|
import { PlSlideModal as N, PlDropdown as g, PlBtnPrimary as A, PlBtnGhost as U } from "@milaboratories/uikit";
|
|
5
4
|
import { getFilterDefault as j } from "./filters_logic.js";
|
|
6
5
|
import D from "./PlTableFilterEntryV2.vue.js";
|
|
@@ -8,7 +7,7 @@ const E = { class: "d-flex flex-column gap-24" }, T = {
|
|
|
8
7
|
key: 0,
|
|
9
8
|
class: "text-subtitle-m",
|
|
10
9
|
style: { color: "var(--txt-mask)" }
|
|
11
|
-
},
|
|
10
|
+
}, $ = /* @__PURE__ */ k({
|
|
12
11
|
__name: "PlTableAddFilterV2",
|
|
13
12
|
props: /* @__PURE__ */ x({
|
|
14
13
|
filters: {},
|
|
@@ -93,6 +92,6 @@ const E = { class: "d-flex flex-column gap-24" }, T = {
|
|
|
93
92
|
}
|
|
94
93
|
});
|
|
95
94
|
export {
|
|
96
|
-
|
|
95
|
+
$ as default
|
|
97
96
|
};
|
|
98
97
|
//# sourceMappingURL=PlTableAddFilterV2.vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableAddFilterV2.vue.js","sources":["../../../src/components/PlTableFilters/PlTableAddFilterV2.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n deepClone,\n} from '@milaboratories/helpers';\nimport {\n PlBtnGhost,\n PlBtnPrimary,\n PlDropdown,\n PlSlideModal,\n type ListOption,\n} from '@milaboratories/uikit';\nimport {\n computed,\n ref,\n watch,\n} from 'vue';\nimport {\n type PlDataTableFilterStateInternal,\n} from './types';\nimport {\n getFilterDefault,\n} from './filters_logic';\nimport PlTableFilterEntryV2 from './PlTableFilterEntryV2.vue';\n\nconst show = defineModel<boolean>({ required: true });\nconst props = defineProps<{\n filters: Readonly<PlDataTableFilterStateInternal[]>;\n setFilter(idx: number, filter: PlDataTableFilterStateInternal): void;\n}>();\n\nconst filterOptions = computed<ListOption<number>[]>(() => {\n return props.filters\n .map((s, i) => {\n return {\n value: i,\n text: s.label,\n };\n })\n .filter((o) => props.filters[o.value].filter === null);\n});\n\nconst newFilterIdx = ref<number>();\nconst newFilter = ref<PlDataTableFilterStateInternal | null>(null);\nwatch(\n () => newFilterIdx.value,\n (newFilterIdx) => {\n if (newFilterIdx === undefined) {\n newFilter.value = null;\n } else {\n const filterClone = deepClone(props.filters[newFilterIdx]);\n if (!filterClone.filter) {\n filterClone.filter = {\n value: filterClone.defaultFilter ?? getFilterDefault(filterClone.options[0].value),\n disabled: false,\n open: true,\n };\n }\n newFilter.value = filterClone;\n }\n },\n);\nconst discardFilter = () => {\n newFilterIdx.value = undefined;\n show.value = false;\n};\nconst applyFilter = () => {\n if (newFilterIdx.value !== undefined && newFilter.value) {\n props.setFilter(newFilterIdx.value, newFilter.value);\n }\n discardFilter();\n};\n</script>\n\n<template>\n <PlSlideModal v-model=\"show\" :close-on-outside-click=\"false\">\n <template #title>Add Filter</template>\n <div class=\"d-flex flex-column gap-24\">\n <PlDropdown\n v-model=\"newFilterIdx\"\n :options=\"filterOptions\"\n label=\"Column\"\n placeholder=\"Choose...\"\n />\n <div\n v-if=\"newFilterIdx === undefined\"\n class=\"text-subtitle-m\"\n style=\"color: var(--txt-mask)\"\n >\n Choose a column to view and adjust its options\n </div>\n <PlTableFilterEntryV2\n v-if=\"newFilter\"\n v-model=\"newFilter\"\n />\n </div>\n <template #actions>\n <PlBtnPrimary :disabled=\"!newFilter\" @click=\"applyFilter\">Add Filter</PlBtnPrimary>\n <PlBtnGhost :justify-center=\"false\" @click=\"discardFilter\">Cancel</PlBtnGhost>\n </template>\n </PlSlideModal>\n</template>\n"],"names":["show","_useModel","__props","props","filterOptions","computed","s","i","newFilterIdx","ref","newFilter","watch","filterClone","deepClone","getFilterDefault","discardFilter","applyFilter"],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlTableAddFilterV2.vue.js","sources":["../../../src/components/PlTableFilters/PlTableAddFilterV2.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n deepClone,\n} from '@milaboratories/helpers';\nimport {\n PlBtnGhost,\n PlBtnPrimary,\n PlDropdown,\n PlSlideModal,\n type ListOption,\n} from '@milaboratories/uikit';\nimport {\n computed,\n ref,\n watch,\n} from 'vue';\nimport {\n type PlDataTableFilterStateInternal,\n} from './types';\nimport {\n getFilterDefault,\n} from './filters_logic';\nimport PlTableFilterEntryV2 from './PlTableFilterEntryV2.vue';\n\nconst show = defineModel<boolean>({ required: true });\nconst props = defineProps<{\n filters: Readonly<PlDataTableFilterStateInternal[]>;\n setFilter(idx: number, filter: PlDataTableFilterStateInternal): void;\n}>();\n\nconst filterOptions = computed<ListOption<number>[]>(() => {\n return props.filters\n .map((s, i) => {\n return {\n value: i,\n text: s.label,\n };\n })\n .filter((o) => props.filters[o.value].filter === null);\n});\n\nconst newFilterIdx = ref<number>();\nconst newFilter = ref<PlDataTableFilterStateInternal | null>(null);\nwatch(\n () => newFilterIdx.value,\n (newFilterIdx) => {\n if (newFilterIdx === undefined) {\n newFilter.value = null;\n } else {\n const filterClone = deepClone(props.filters[newFilterIdx]);\n if (!filterClone.filter) {\n filterClone.filter = {\n value: filterClone.defaultFilter ?? getFilterDefault(filterClone.options[0].value),\n disabled: false,\n open: true,\n };\n }\n newFilter.value = filterClone;\n }\n },\n);\nconst discardFilter = () => {\n newFilterIdx.value = undefined;\n show.value = false;\n};\nconst applyFilter = () => {\n if (newFilterIdx.value !== undefined && newFilter.value) {\n props.setFilter(newFilterIdx.value, newFilter.value);\n }\n discardFilter();\n};\n</script>\n\n<template>\n <PlSlideModal v-model=\"show\" :close-on-outside-click=\"false\">\n <template #title>Add Filter</template>\n <div class=\"d-flex flex-column gap-24\">\n <PlDropdown\n v-model=\"newFilterIdx\"\n :options=\"filterOptions\"\n label=\"Column\"\n placeholder=\"Choose...\"\n />\n <div\n v-if=\"newFilterIdx === undefined\"\n class=\"text-subtitle-m\"\n style=\"color: var(--txt-mask)\"\n >\n Choose a column to view and adjust its options\n </div>\n <PlTableFilterEntryV2\n v-if=\"newFilter\"\n v-model=\"newFilter\"\n />\n </div>\n <template #actions>\n <PlBtnPrimary :disabled=\"!newFilter\" @click=\"applyFilter\">Add Filter</PlBtnPrimary>\n <PlBtnGhost :justify-center=\"false\" @click=\"discardFilter\">Cancel</PlBtnGhost>\n </template>\n </PlSlideModal>\n</template>\n"],"names":["show","_useModel","__props","props","filterOptions","computed","s","i","newFilterIdx","ref","newFilter","watch","filterClone","deepClone","getFilterDefault","discardFilter","applyFilter"],"mappings":";;;;;;;;;;;;;;;;;;;;AAwBA,UAAMA,IAAOC,EAAoBC,GAAA,YAAmB,GAC9CC,IAAQD,GAKRE,IAAgBC,EAA+B,MAC5CF,EAAM,QACV,IAAI,CAACG,GAAGC,OACA;AAAA,MACL,OAAOA;AAAA,MACP,MAAMD,EAAE;AAAA,IAAA,EAEX,EACA,OAAO,CAAC,MAAMH,EAAM,QAAQ,EAAE,KAAK,EAAE,WAAW,IAAI,CACxD,GAEKK,IAAeC,EAAA,GACfC,IAAYD,EAA2C,IAAI;AACjE,IAAAE;AAAA,MACE,MAAMH,EAAa;AAAA,MACnB,CAACA,MAAiB;AAChB,YAAIA,MAAiB;AACnB,UAAAE,EAAU,QAAQ;AAAA,aACb;AACL,gBAAME,IAAcC,EAAUV,EAAM,QAAQK,CAAY,CAAC;AACzD,UAAKI,EAAY,WACfA,EAAY,SAAS;AAAA,YACnB,OAAOA,EAAY,iBAAiBE,EAAiBF,EAAY,QAAQ,CAAC,EAAE,KAAK;AAAA,YACjF,UAAU;AAAA,YACV,MAAM;AAAA,UAAA,IAGVF,EAAU,QAAQE;AAAA,QACpB;AAAA,MACF;AAAA,IAAA;AAEF,UAAMG,IAAgB,MAAM;AAC1B,MAAAP,EAAa,QAAQ,QACrBR,EAAK,QAAQ;AAAA,IACf,GACMgB,IAAc,MAAM;AACxB,MAAIR,EAAa,UAAU,UAAaE,EAAU,SAChDP,EAAM,UAAUK,EAAa,OAAOE,EAAU,KAAK,GAErDK,EAAA;AAAA,IACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { defineComponent as V, useModel as y, watchEffect as g, createElementBlock as o, createCommentVNode as d, openBlock as r, createVNode as t, createBlock as n, unref as u, Fragment as s, withCtx as U, createTextVNode as k } from "vue";
|
|
2
2
|
import { PlDropdown as v, PlTextField as i, PlToggleSwitch as f, Slider as w, PlBtnGhost as x } from "@milaboratories/uikit";
|
|
3
3
|
import { isJsonEqual as B } from "../../lib/util/helpers/dist/objects.js";
|
|
4
|
-
import "../../lib/util/helpers/dist/test_timeouts.js";
|
|
5
4
|
import { getFilterDefault as E, changeFilter as F, isFilterDiscrete as T, parseNumber as p, parseString as m, parseRegex as c, makeWildcardOptions as q } from "./filters_logic.js";
|
|
6
5
|
const O = {
|
|
7
6
|
key: 0,
|
|
@@ -9,7 +8,7 @@ const O = {
|
|
|
9
8
|
}, N = {
|
|
10
9
|
key: 2,
|
|
11
10
|
class: "d-flex justify-center"
|
|
12
|
-
},
|
|
11
|
+
}, D = /* @__PURE__ */ V({
|
|
13
12
|
__name: "PlTableFilterEntryV2",
|
|
14
13
|
props: {
|
|
15
14
|
modelValue: { required: !0 },
|
|
@@ -138,6 +137,6 @@ const O = {
|
|
|
138
137
|
}
|
|
139
138
|
});
|
|
140
139
|
export {
|
|
141
|
-
|
|
140
|
+
D as default
|
|
142
141
|
};
|
|
143
142
|
//# sourceMappingURL=PlTableFilterEntryV2.vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFilterEntryV2.vue.js","sources":["../../../src/components/PlTableFilters/PlTableFilterEntryV2.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n PlDropdown,\n PlTextField,\n PlToggleSwitch,\n Slider,\n PlBtnGhost,\n} from '@milaboratories/uikit';\nimport { isJsonEqual } from '@milaboratories/helpers';\nimport {\n changeFilter,\n parseNumber,\n parseString,\n parseRegex,\n makeWildcardOptions,\n isFilterDiscrete,\n getFilterDefault,\n} from './filters_logic';\nimport type { PlDataTableFilterStateInternal } from './types';\nimport { watchEffect } from 'vue';\n\nconst entry = defineModel<PlDataTableFilterStateInternal>({ required: true });\nwatchEffect(() => {\n if (!entry.value.filter) {\n entry.value.filter = {\n value: getFilterDefault(entry.value.options[0].value),\n disabled: false,\n open: true,\n };\n }\n});\n</script>\n\n<template>\n <div v-if=\"entry.filter\" class=\"d-flex flex-column gap-24\">\n <PlDropdown\n :model-value=\"entry.filter.value.type\"\n :options=\"entry.options\"\n :disabled=\"entry.filter.disabled\"\n label=\"Predicate\"\n @update:model-value=\"(type) => (entry.filter!.value = changeFilter(entry.filter!.value, type!, entry.discreteOptions))\"\n />\n\n <template v-if=\"entry.discreteOptions.length > 0 && isFilterDiscrete(entry.filter.value)\">\n <PlDropdown\n v-model=\"entry.filter.value.reference\"\n :options=\"entry.discreteOptions\"\n />\n </template>\n <template v-else>\n <template\n v-if=\"\n entry.filter.value.type === 'number_equals' ||\n entry.filter.value.type === 'number_notEquals' ||\n entry.filter.value.type === 'number_lessThan' ||\n entry.filter.value.type === 'number_lessThanOrEqualTo' ||\n entry.filter.value.type === 'number_greaterThan' ||\n entry.filter.value.type === 'number_greaterThanOrEqualTo'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.reference\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): number => parseNumber(entry.spec, value)\"\n label=\"Reference value\"\n />\n </template>\n\n <template\n v-if=\"\n entry.filter.value.type === 'number_between'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.lowerBound\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): number => parseNumber(entry.spec, value)\"\n label=\"Lower bound\"\n />\n <PlToggleSwitch\n v-model=\"entry.filter.value.includeLowerBound\"\n :disabled=\"entry.filter.disabled\"\n label=\"Include lower bound\"\n />\n <PlTextField\n v-model=\"entry.filter.value.upperBound\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): number => parseNumber(entry.spec, value)\"\n label=\"Upper bound\"\n />\n <PlToggleSwitch\n v-model=\"entry.filter.value.includeUpperBound\"\n :disabled=\"entry.filter.disabled\"\n label=\"Include upper bound\"\n />\n </template>\n\n <template\n v-if=\"\n entry.filter.value.type === 'string_equals' ||\n entry.filter.value.type === 'string_notEquals' ||\n entry.filter.value.type === 'string_contains' ||\n entry.filter.value.type === 'string_doesNotContain'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.reference\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): string => parseString(entry.spec, value)\"\n label=\"Reference value\"\n />\n </template>\n\n <template\n v-if=\"\n entry.filter.value.type === 'string_matches' ||\n entry.filter.value.type === 'string_doesNotMatch'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.reference\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"parseRegex\"\n label=\"Reference value\"\n />\n </template>\n\n <template\n v-if=\"\n entry.filter.value.type === 'string_containsFuzzyMatch'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.reference\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): string => parseString(entry.spec, value)\"\n label=\"Reference value\"\n />\n <Slider\n v-model=\"entry.filter.value.maxEdits\"\n :max=\"5\"\n :disabled=\"entry.filter.disabled\"\n breakpoints label=\"Maximum nuber of substitutions and indels\"\n />\n <PlToggleSwitch\n v-model=\"entry.filter.value.substitutionsOnly\"\n :disabled=\"entry.filter.disabled\"\n label=\"Substitutions only\"\n />\n <PlDropdown\n v-model=\"entry.filter.value.wildcard\"\n :disabled=\"entry.filter.disabled\"\n :options=\"makeWildcardOptions(entry.spec, entry.filter.value.reference)\"\n clearable\n label=\"Wildcard symbol\"\n />\n </template>\n </template>\n\n <div v-if=\"entry.defaultFilter\" class=\"d-flex justify-center\">\n <PlBtnGhost\n :disabled=\"entry.filter.disabled || isJsonEqual(entry.filter.value, entry.defaultFilter)\"\n icon=\"reverse\"\n @click=\"entry.filter.value = entry.defaultFilter\"\n >\n Revert Settings to Default\n </PlBtnGhost>\n </div>\n </div>\n</template>\n"],"names":["entry","_useModel","__props","watchEffect","getFilterDefault"],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlTableFilterEntryV2.vue.js","sources":["../../../src/components/PlTableFilters/PlTableFilterEntryV2.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n PlDropdown,\n PlTextField,\n PlToggleSwitch,\n Slider,\n PlBtnGhost,\n} from '@milaboratories/uikit';\nimport { isJsonEqual } from '@milaboratories/helpers';\nimport {\n changeFilter,\n parseNumber,\n parseString,\n parseRegex,\n makeWildcardOptions,\n isFilterDiscrete,\n getFilterDefault,\n} from './filters_logic';\nimport type { PlDataTableFilterStateInternal } from './types';\nimport { watchEffect } from 'vue';\n\nconst entry = defineModel<PlDataTableFilterStateInternal>({ required: true });\nwatchEffect(() => {\n if (!entry.value.filter) {\n entry.value.filter = {\n value: getFilterDefault(entry.value.options[0].value),\n disabled: false,\n open: true,\n };\n }\n});\n</script>\n\n<template>\n <div v-if=\"entry.filter\" class=\"d-flex flex-column gap-24\">\n <PlDropdown\n :model-value=\"entry.filter.value.type\"\n :options=\"entry.options\"\n :disabled=\"entry.filter.disabled\"\n label=\"Predicate\"\n @update:model-value=\"(type) => (entry.filter!.value = changeFilter(entry.filter!.value, type!, entry.discreteOptions))\"\n />\n\n <template v-if=\"entry.discreteOptions.length > 0 && isFilterDiscrete(entry.filter.value)\">\n <PlDropdown\n v-model=\"entry.filter.value.reference\"\n :options=\"entry.discreteOptions\"\n />\n </template>\n <template v-else>\n <template\n v-if=\"\n entry.filter.value.type === 'number_equals' ||\n entry.filter.value.type === 'number_notEquals' ||\n entry.filter.value.type === 'number_lessThan' ||\n entry.filter.value.type === 'number_lessThanOrEqualTo' ||\n entry.filter.value.type === 'number_greaterThan' ||\n entry.filter.value.type === 'number_greaterThanOrEqualTo'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.reference\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): number => parseNumber(entry.spec, value)\"\n label=\"Reference value\"\n />\n </template>\n\n <template\n v-if=\"\n entry.filter.value.type === 'number_between'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.lowerBound\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): number => parseNumber(entry.spec, value)\"\n label=\"Lower bound\"\n />\n <PlToggleSwitch\n v-model=\"entry.filter.value.includeLowerBound\"\n :disabled=\"entry.filter.disabled\"\n label=\"Include lower bound\"\n />\n <PlTextField\n v-model=\"entry.filter.value.upperBound\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): number => parseNumber(entry.spec, value)\"\n label=\"Upper bound\"\n />\n <PlToggleSwitch\n v-model=\"entry.filter.value.includeUpperBound\"\n :disabled=\"entry.filter.disabled\"\n label=\"Include upper bound\"\n />\n </template>\n\n <template\n v-if=\"\n entry.filter.value.type === 'string_equals' ||\n entry.filter.value.type === 'string_notEquals' ||\n entry.filter.value.type === 'string_contains' ||\n entry.filter.value.type === 'string_doesNotContain'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.reference\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): string => parseString(entry.spec, value)\"\n label=\"Reference value\"\n />\n </template>\n\n <template\n v-if=\"\n entry.filter.value.type === 'string_matches' ||\n entry.filter.value.type === 'string_doesNotMatch'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.reference\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"parseRegex\"\n label=\"Reference value\"\n />\n </template>\n\n <template\n v-if=\"\n entry.filter.value.type === 'string_containsFuzzyMatch'\n \"\n >\n <PlTextField\n v-model=\"entry.filter.value.reference\"\n :disabled=\"entry.filter.disabled\"\n :parse=\"(value: string): string => parseString(entry.spec, value)\"\n label=\"Reference value\"\n />\n <Slider\n v-model=\"entry.filter.value.maxEdits\"\n :max=\"5\"\n :disabled=\"entry.filter.disabled\"\n breakpoints label=\"Maximum nuber of substitutions and indels\"\n />\n <PlToggleSwitch\n v-model=\"entry.filter.value.substitutionsOnly\"\n :disabled=\"entry.filter.disabled\"\n label=\"Substitutions only\"\n />\n <PlDropdown\n v-model=\"entry.filter.value.wildcard\"\n :disabled=\"entry.filter.disabled\"\n :options=\"makeWildcardOptions(entry.spec, entry.filter.value.reference)\"\n clearable\n label=\"Wildcard symbol\"\n />\n </template>\n </template>\n\n <div v-if=\"entry.defaultFilter\" class=\"d-flex justify-center\">\n <PlBtnGhost\n :disabled=\"entry.filter.disabled || isJsonEqual(entry.filter.value, entry.defaultFilter)\"\n icon=\"reverse\"\n @click=\"entry.filter.value = entry.defaultFilter\"\n >\n Revert Settings to Default\n </PlBtnGhost>\n </div>\n </div>\n</template>\n"],"names":["entry","_useModel","__props","watchEffect","getFilterDefault"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,UAAMA,IAAQC,EAA2CC,GAAA,YAAmB;AAC5E,WAAAC,EAAY,MAAM;AAChB,MAAKH,EAAM,MAAM,WACfA,EAAM,MAAM,SAAS;AAAA,QACnB,OAAOI,EAAiBJ,EAAM,MAAM,QAAQ,CAAC,EAAE,KAAK;AAAA,QACpD,UAAU;AAAA,QACV,MAAM;AAAA,MAAA;AAAA,IAGZ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -5,8 +5,7 @@ import { useFilters as Y } from "./filters-state.js";
|
|
|
5
5
|
import Z from "./PlTableAddFilterV2.vue.js";
|
|
6
6
|
import _ from "./PlTableFilterEntryV2.vue.js";
|
|
7
7
|
import { isJsonEqual as ee } from "../../lib/util/helpers/dist/objects.js";
|
|
8
|
-
|
|
9
|
-
const le = ["disabled"], te = { key: 1 }, fe = /* @__PURE__ */ D({
|
|
8
|
+
const le = ["disabled"], te = { key: 1 }, ue = /* @__PURE__ */ D({
|
|
10
9
|
__name: "PlTableFiltersV2",
|
|
11
10
|
props: /* @__PURE__ */ S({
|
|
12
11
|
settings: {}
|
|
@@ -149,6 +148,6 @@ const le = ["disabled"], te = { key: 1 }, fe = /* @__PURE__ */ D({
|
|
|
149
148
|
}
|
|
150
149
|
});
|
|
151
150
|
export {
|
|
152
|
-
|
|
151
|
+
ue as default
|
|
153
152
|
};
|
|
154
153
|
//# sourceMappingURL=PlTableFiltersV2.vue2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlTableFiltersV2.vue2.js","sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport {\n type PlDataTableFilterState,\n canonicalizeJson,\n type PTableColumnId,\n} from '@platforma-sdk/model';\nimport type {\n PlDataTableFiltersSettings,\n} from './types';\nimport {\n computed,\n onBeforeUnmount,\n onMounted,\n ref,\n toRefs,\n watch,\n} from 'vue';\nimport {\n PlBtnGhost,\n PlSlideModal,\n PlBtnSecondary,\n PlMaskIcon16,\n PlElementList,\n usePlBlockPageTitleTeleportTarget,\n} from '@milaboratories/uikit';\nimport { useFilters } from './filters-state';\nimport PlTableAddFilterV2 from './PlTableAddFilterV2.vue';\nimport PlTableFilterEntryV2 from './PlTableFilterEntryV2.vue';\nimport { isJsonEqual } from '@milaboratories/helpers';\n\nconst state = defineModel<PlDataTableFilterState[]>({\n default: [],\n});\nconst props = defineProps<{\n settings: Readonly<PlDataTableFiltersSettings>;\n}>();\nconst { settings } = toRefs(props);\n\nconst filters = useFilters(settings, state);\n\nconst filtersOn = computed<boolean>(() => filters.value.some((s) => s.filter && !s.filter.disabled));\n\nconst mounted = ref(false);\nonMounted(() => {\n mounted.value = true;\n});\nconst teleportTarget = usePlBlockPageTitleTeleportTarget('PlTableFiltersV2');\n\nconst showManager = ref(false);\n\nconst scrollIsActive = ref(false);\nconst filterManager = ref<HTMLElement>();\nlet observer: ResizeObserver;\nonMounted(() => {\n observer = new ResizeObserver(() => {\n const parent = filterManager.value?.parentElement;\n if (!parent) return;\n scrollIsActive.value = parent.scrollHeight > parent.clientHeight || parent.scrollWidth > parent.clientWidth;\n });\n if (filterManager.value && filterManager.value.parentElement) {\n observer.observe(filterManager.value!.parentElement);\n }\n});\n\nwatch(filterManager, (newElement, oldElement) => {\n if (oldElement?.parentElement) {\n observer.unobserve(oldElement.parentElement);\n }\n if (newElement?.parentElement) {\n observer.observe(newElement.parentElement);\n }\n});\n\nonBeforeUnmount(() => {\n if (observer !== undefined) {\n observer.disconnect();\n }\n});\n\nconst canAddFilter = computed<boolean>(() => filters.value.some((s) => !s.filter));\nconst showAddFilter = ref(false);\n\nconst canResetToDefaults = computed<boolean>(() => {\n return filters.value\n .some((s) => (!s.defaultFilter && s.filter) || (s.defaultFilter\n && (s.filter?.disabled === true || !isJsonEqual(s.filter?.value, s.defaultFilter))));\n});\nconst resetToDefaults = () => {\n filters.value.forEach((s) => {\n if (s.defaultFilter) {\n s.filter = {\n value: s.defaultFilter,\n disabled: false,\n open: false,\n };\n } else {\n s.filter = null;\n }\n });\n};\n\nconst items = computed(() => filters.value.filter((s) => s.filter !== null));\n</script>\n\n<template>\n <Teleport v-if=\"mounted && teleportTarget\" :to=\"teleportTarget\">\n <PlBtnGhost :icon=\"filtersOn ? 'filter-on' : 'filter'\" @click.stop=\"showManager = true\">\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 ref=\"filterManager\" :class=\"$style['filter-manager']\">\n <PlElementList\n v-model:items=\"items\"\n :on-expand=\"(item) => {\n if (item.filter) {\n item.filter.open = !item.filter.open;\n }\n }\"\n :is-expanded=\"(item) => item.filter?.open ?? false\"\n :on-toggle=\"(item) => {\n if (item.filter) {\n item.filter.disabled = !item.filter.disabled;\n }\n }\"\n :is-toggled=\"(item) => item.filter?.disabled ?? false\"\n :on-remove=\"(item) => {\n if (item.filter) {\n item.filter = null;\n }\n }\"\n :get-item-key=\"(item) => canonicalizeJson<PTableColumnId>(item.id)\"\n disable-dragging\n >\n <template #item-title=\"{ item }\">\n {{ item.label }}\n </template>\n <template #item-content=\"{ index }\">\n <PlTableFilterEntryV2 v-model=\"filters.value[index]\" />\n </template>\n </PlElementList>\n\n <div\n v-if=\"filters.value.length\"\n :class=\"$style['add-action-wrapper']\"\n >\n <button\n :disabled=\"!canAddFilter\"\n :class=\"$style['add-btn']\"\n @click=\"showAddFilter = true\"\n >\n <PlMaskIcon16 name=\"add\" />\n <div :class=\"$style['add-btn-title']\">Add Filter</div>\n </button>\n\n <PlBtnSecondary\n :disabled=\"!canResetToDefaults\"\n @click.stop=\"resetToDefaults\"\n >\n Reset to defaults\n </PlBtnSecondary>\n </div>\n\n <div v-if=\"!filters.value.length\">No filters applicable</div>\n </div>\n </PlSlideModal>\n\n <PlTableAddFilterV2\n v-model=\"showAddFilter\"\n :filters=\"filters.value\"\n :set-filter=\"(idx, filter) => filters.value[idx] = filter\"\n />\n</template>\n\n<style lang=\"scss\" module>\n.filter-manager {\n --expand-icon-rotation: rotate(0deg);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.add-action-wrapper {\n position: sticky;\n bottom: -16px;\n background-color: var(--bg-elevated-01);\n transition: all .15s ease-in-out;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.add-btn {\n height: 40px;\n background-color: var(--bg-elevated-01);\n display: flex;\n align-items: center;\n gap: 8px;\n padding-left: 12px;\n padding-right: 12px;\n border-radius: 6px;\n border: 1px dashed var(--border-color-div-grey);\n line-height: 0;\n cursor: pointer;\n text-align: left;\n}\n\n.add-btn:disabled {\n --icon-color: var(--dis-01);\n cursor: auto;\n}\n\n.add-btn:not([disabled]):hover {\n border-radius: 6px;\n border: 1px dashed var(--border-color-focus, #49CC49);\n background: rgba(99, 224, 36, 0.12);\n}\n\n.add-btn-title {\n flex-grow: 1;\n font-weight: 600;\n}\n\n.expand-icon {\n transition: all .15s ease-in-out;\n transform: var(--expand-icon-rotation);\n line-height: 0;\n cursor: pointer;\n}\n\n.toggle,\n.delete {\n line-height: 0;\n cursor: pointer;\n display: none;\n}\n\n.toggle .mask-24,\n.delete .mask-24 {\n --icon-color: var(--ic-02);\n}\n\n.toggle:hover .mask-24 {\n --icon-color: var(--ic-01);\n}\n\n.delete:hover .mask-24 {\n --icon-color: var(--ic-01);\n}\n\n.filter:hover .toggle,\n.filter:hover .delete {\n display: block;\n}\n\n.filter {\n border-radius: 6px;\n border: 1px solid var(--border-color-div-grey);\n background-color: var(--bg-base-light);\n transition: background-color .15s ease-in-out;\n overflow: auto;\n}\n\n.filter.disabled .expand-icon,\n.filter.disabled .title {\n opacity: 0.3;\n}\n\n.filter:hover {\n background-color: var(--bg-elevated-01);\n}\n\n.filter:global(.open) {\n background-color: var(--bg-elevated-01);\n --expand-icon-rotation: rotate(90deg);\n}\n</style>\n"],"names":["state","_useModel","props","__props","settings","toRefs","filters","useFilters","filtersOn","computed","s","mounted","ref","onMounted","teleportTarget","usePlBlockPageTitleTeleportTarget","showManager","scrollIsActive","filterManager","observer","parent","_a","watch","newElement","oldElement","onBeforeUnmount","canAddFilter","showAddFilter","canResetToDefaults","isJsonEqual","_b","resetToDefaults","items"],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlTableFiltersV2.vue2.js","sources":["../../../src/components/PlTableFilters/PlTableFiltersV2.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport {\n type PlDataTableFilterState,\n canonicalizeJson,\n type PTableColumnId,\n} from '@platforma-sdk/model';\nimport type {\n PlDataTableFiltersSettings,\n} from './types';\nimport {\n computed,\n onBeforeUnmount,\n onMounted,\n ref,\n toRefs,\n watch,\n} from 'vue';\nimport {\n PlBtnGhost,\n PlSlideModal,\n PlBtnSecondary,\n PlMaskIcon16,\n PlElementList,\n usePlBlockPageTitleTeleportTarget,\n} from '@milaboratories/uikit';\nimport { useFilters } from './filters-state';\nimport PlTableAddFilterV2 from './PlTableAddFilterV2.vue';\nimport PlTableFilterEntryV2 from './PlTableFilterEntryV2.vue';\nimport { isJsonEqual } from '@milaboratories/helpers';\n\nconst state = defineModel<PlDataTableFilterState[]>({\n default: [],\n});\nconst props = defineProps<{\n settings: Readonly<PlDataTableFiltersSettings>;\n}>();\nconst { settings } = toRefs(props);\n\nconst filters = useFilters(settings, state);\n\nconst filtersOn = computed<boolean>(() => filters.value.some((s) => s.filter && !s.filter.disabled));\n\nconst mounted = ref(false);\nonMounted(() => {\n mounted.value = true;\n});\nconst teleportTarget = usePlBlockPageTitleTeleportTarget('PlTableFiltersV2');\n\nconst showManager = ref(false);\n\nconst scrollIsActive = ref(false);\nconst filterManager = ref<HTMLElement>();\nlet observer: ResizeObserver;\nonMounted(() => {\n observer = new ResizeObserver(() => {\n const parent = filterManager.value?.parentElement;\n if (!parent) return;\n scrollIsActive.value = parent.scrollHeight > parent.clientHeight || parent.scrollWidth > parent.clientWidth;\n });\n if (filterManager.value && filterManager.value.parentElement) {\n observer.observe(filterManager.value!.parentElement);\n }\n});\n\nwatch(filterManager, (newElement, oldElement) => {\n if (oldElement?.parentElement) {\n observer.unobserve(oldElement.parentElement);\n }\n if (newElement?.parentElement) {\n observer.observe(newElement.parentElement);\n }\n});\n\nonBeforeUnmount(() => {\n if (observer !== undefined) {\n observer.disconnect();\n }\n});\n\nconst canAddFilter = computed<boolean>(() => filters.value.some((s) => !s.filter));\nconst showAddFilter = ref(false);\n\nconst canResetToDefaults = computed<boolean>(() => {\n return filters.value\n .some((s) => (!s.defaultFilter && s.filter) || (s.defaultFilter\n && (s.filter?.disabled === true || !isJsonEqual(s.filter?.value, s.defaultFilter))));\n});\nconst resetToDefaults = () => {\n filters.value.forEach((s) => {\n if (s.defaultFilter) {\n s.filter = {\n value: s.defaultFilter,\n disabled: false,\n open: false,\n };\n } else {\n s.filter = null;\n }\n });\n};\n\nconst items = computed(() => filters.value.filter((s) => s.filter !== null));\n</script>\n\n<template>\n <Teleport v-if=\"mounted && teleportTarget\" :to=\"teleportTarget\">\n <PlBtnGhost :icon=\"filtersOn ? 'filter-on' : 'filter'\" @click.stop=\"showManager = true\">\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 ref=\"filterManager\" :class=\"$style['filter-manager']\">\n <PlElementList\n v-model:items=\"items\"\n :on-expand=\"(item) => {\n if (item.filter) {\n item.filter.open = !item.filter.open;\n }\n }\"\n :is-expanded=\"(item) => item.filter?.open ?? false\"\n :on-toggle=\"(item) => {\n if (item.filter) {\n item.filter.disabled = !item.filter.disabled;\n }\n }\"\n :is-toggled=\"(item) => item.filter?.disabled ?? false\"\n :on-remove=\"(item) => {\n if (item.filter) {\n item.filter = null;\n }\n }\"\n :get-item-key=\"(item) => canonicalizeJson<PTableColumnId>(item.id)\"\n disable-dragging\n >\n <template #item-title=\"{ item }\">\n {{ item.label }}\n </template>\n <template #item-content=\"{ index }\">\n <PlTableFilterEntryV2 v-model=\"filters.value[index]\" />\n </template>\n </PlElementList>\n\n <div\n v-if=\"filters.value.length\"\n :class=\"$style['add-action-wrapper']\"\n >\n <button\n :disabled=\"!canAddFilter\"\n :class=\"$style['add-btn']\"\n @click=\"showAddFilter = true\"\n >\n <PlMaskIcon16 name=\"add\" />\n <div :class=\"$style['add-btn-title']\">Add Filter</div>\n </button>\n\n <PlBtnSecondary\n :disabled=\"!canResetToDefaults\"\n @click.stop=\"resetToDefaults\"\n >\n Reset to defaults\n </PlBtnSecondary>\n </div>\n\n <div v-if=\"!filters.value.length\">No filters applicable</div>\n </div>\n </PlSlideModal>\n\n <PlTableAddFilterV2\n v-model=\"showAddFilter\"\n :filters=\"filters.value\"\n :set-filter=\"(idx, filter) => filters.value[idx] = filter\"\n />\n</template>\n\n<style lang=\"scss\" module>\n.filter-manager {\n --expand-icon-rotation: rotate(0deg);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.add-action-wrapper {\n position: sticky;\n bottom: -16px;\n background-color: var(--bg-elevated-01);\n transition: all .15s ease-in-out;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.add-btn {\n height: 40px;\n background-color: var(--bg-elevated-01);\n display: flex;\n align-items: center;\n gap: 8px;\n padding-left: 12px;\n padding-right: 12px;\n border-radius: 6px;\n border: 1px dashed var(--border-color-div-grey);\n line-height: 0;\n cursor: pointer;\n text-align: left;\n}\n\n.add-btn:disabled {\n --icon-color: var(--dis-01);\n cursor: auto;\n}\n\n.add-btn:not([disabled]):hover {\n border-radius: 6px;\n border: 1px dashed var(--border-color-focus, #49CC49);\n background: rgba(99, 224, 36, 0.12);\n}\n\n.add-btn-title {\n flex-grow: 1;\n font-weight: 600;\n}\n\n.expand-icon {\n transition: all .15s ease-in-out;\n transform: var(--expand-icon-rotation);\n line-height: 0;\n cursor: pointer;\n}\n\n.toggle,\n.delete {\n line-height: 0;\n cursor: pointer;\n display: none;\n}\n\n.toggle .mask-24,\n.delete .mask-24 {\n --icon-color: var(--ic-02);\n}\n\n.toggle:hover .mask-24 {\n --icon-color: var(--ic-01);\n}\n\n.delete:hover .mask-24 {\n --icon-color: var(--ic-01);\n}\n\n.filter:hover .toggle,\n.filter:hover .delete {\n display: block;\n}\n\n.filter {\n border-radius: 6px;\n border: 1px solid var(--border-color-div-grey);\n background-color: var(--bg-base-light);\n transition: background-color .15s ease-in-out;\n overflow: auto;\n}\n\n.filter.disabled .expand-icon,\n.filter.disabled .title {\n opacity: 0.3;\n}\n\n.filter:hover {\n background-color: var(--bg-elevated-01);\n}\n\n.filter:global(.open) {\n background-color: var(--bg-elevated-01);\n --expand-icon-rotation: rotate(90deg);\n}\n</style>\n"],"names":["state","_useModel","props","__props","settings","toRefs","filters","useFilters","filtersOn","computed","s","mounted","ref","onMounted","teleportTarget","usePlBlockPageTitleTeleportTarget","showManager","scrollIsActive","filterManager","observer","parent","_a","watch","newElement","oldElement","onBeforeUnmount","canAddFilter","showAddFilter","canResetToDefaults","isJsonEqual","_b","resetToDefaults","items"],"mappings":";;;;;;;;;;;;;;;;;;;AA8BA,UAAMA,IAAQC,iBAEb,GACKC,IAAQC,GAGR,EAAE,UAAAC,EAAA,IAAaC,EAAOH,CAAK,GAE3BI,IAAUC,EAAWH,GAAUJ,CAAK,GAEpCQ,IAAYC,EAAkB,MAAMH,EAAQ,MAAM,KAAK,CAACI,MAAMA,EAAE,UAAU,CAACA,EAAE,OAAO,QAAQ,CAAC,GAE7FC,IAAUC,EAAI,EAAK;AACzB,IAAAC,EAAU,MAAM;AACd,MAAAF,EAAQ,QAAQ;AAAA,IAClB,CAAC;AACD,UAAMG,IAAiBC,EAAkC,kBAAkB,GAErEC,IAAcJ,EAAI,EAAK,GAEvBK,IAAiBL,EAAI,EAAK,GAC1BM,IAAgBN,EAAA;AACtB,QAAIO;AACJ,IAAAN,EAAU,MAAM;AACd,MAAAM,IAAW,IAAI,eAAe,MAAM;;AAClC,cAAMC,KAASC,IAAAH,EAAc,UAAd,gBAAAG,EAAqB;AACpC,QAAKD,MACLH,EAAe,QAAQG,EAAO,eAAeA,EAAO,gBAAgBA,EAAO,cAAcA,EAAO;AAAA,MAClG,CAAC,GACGF,EAAc,SAASA,EAAc,MAAM,iBAC7CC,EAAS,QAAQD,EAAc,MAAO,aAAa;AAAA,IAEvD,CAAC,GAEDI,EAAMJ,GAAe,CAACK,GAAYC,MAAe;AAC/C,MAAIA,KAAA,QAAAA,EAAY,iBACdL,EAAS,UAAUK,EAAW,aAAa,GAEzCD,KAAA,QAAAA,EAAY,iBACdJ,EAAS,QAAQI,EAAW,aAAa;AAAA,IAE7C,CAAC,GAEDE,EAAgB,MAAM;AACpB,MAAIN,MAAa,UACfA,EAAS,WAAA;AAAA,IAEb,CAAC;AAED,UAAMO,IAAejB,EAAkB,MAAMH,EAAQ,MAAM,KAAK,CAACI,MAAM,CAACA,EAAE,MAAM,CAAC,GAC3EiB,IAAgBf,EAAI,EAAK,GAEzBgB,IAAqBnB,EAAkB,MACpCH,EAAQ,MACZ,KAAK,CAACI;;AAAO,cAACA,EAAE,iBAAiBA,EAAE,UAAYA,EAAE,oBAC5CW,IAAAX,EAAE,WAAF,gBAAAW,EAAU,cAAa,MAAQ,CAACQ,IAAYC,IAAApB,EAAE,WAAF,gBAAAoB,EAAU,OAAOpB,EAAE,aAAa;AAAA,KAAG,CACxF,GACKqB,IAAkB,MAAM;AAC5B,MAAAzB,EAAQ,MAAM,QAAQ,CAACI,MAAM;AAC3B,QAAIA,EAAE,gBACJA,EAAE,SAAS;AAAA,UACT,OAAOA,EAAE;AAAA,UACT,UAAU;AAAA,UACV,MAAM;AAAA,QAAA,IAGRA,EAAE,SAAS;AAAA,MAEf,CAAC;AAAA,IACH,GAEMsB,IAAQvB,EAAS,MAAMH,EAAQ,MAAM,OAAO,CAACI,MAAMA,EAAE,WAAW,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { ref as J, reactive as V, watch as h } from "vue";
|
|
2
2
|
import { getPTableColumnId as k, canonicalizeJson as f } from "@platforma-sdk/model";
|
|
3
3
|
import { isJsonEqual as b } from "../../lib/util/helpers/dist/objects.js";
|
|
4
|
-
import "../../lib/util/helpers/dist/test_timeouts.js";
|
|
5
4
|
import { getFilterOptions as g, makeDiscreteOptions as q, isFilterValid as F, isAlphabetic as x, getColumnName as z } from "./filters_logic.js";
|
|
6
|
-
function
|
|
5
|
+
function K(M, m) {
|
|
7
6
|
const w = J(/* @__PURE__ */ new Map()), o = V({
|
|
8
7
|
value: []
|
|
9
8
|
});
|
|
10
9
|
return h(
|
|
11
10
|
() => M.value,
|
|
12
11
|
({ columns: d, config: n, cachedState: i }) => {
|
|
13
|
-
const
|
|
12
|
+
const c = w.value = new Map(
|
|
14
13
|
d.map((e, t) => {
|
|
15
14
|
try {
|
|
16
15
|
const a = k(e), l = n(e), r = l.options ? g(e).filter((y) => l.options.includes(y.value)) : g(e);
|
|
17
16
|
if (r.length === 0) return null;
|
|
18
|
-
const u = q(e),
|
|
19
|
-
value:
|
|
17
|
+
const u = q(e), p = l.default && F(l.default, r, u) ? l.default : null, S = p ? {
|
|
18
|
+
value: p,
|
|
20
19
|
disabled: !1,
|
|
21
20
|
open: !1
|
|
22
21
|
} : null, C = {
|
|
@@ -26,7 +25,7 @@ function N(M, m) {
|
|
|
26
25
|
alphabetic: x(e),
|
|
27
26
|
options: r,
|
|
28
27
|
discreteOptions: u,
|
|
29
|
-
defaultFilter:
|
|
28
|
+
defaultFilter: p,
|
|
30
29
|
filter: S
|
|
31
30
|
};
|
|
32
31
|
return [f(a), C];
|
|
@@ -35,9 +34,9 @@ function N(M, m) {
|
|
|
35
34
|
}
|
|
36
35
|
}).filter((e) => e !== null)
|
|
37
36
|
), s = new Map(
|
|
38
|
-
i.filter((e) =>
|
|
37
|
+
i.filter((e) => c.has(f(e.id))).map((e) => {
|
|
39
38
|
var l, r;
|
|
40
|
-
const t =
|
|
39
|
+
const t = c.get(f(e.id)), a = {
|
|
41
40
|
...t,
|
|
42
41
|
filter: e.filter && F(e.filter.value, t.options, t.discreteOptions) ? {
|
|
43
42
|
...e.filter,
|
|
@@ -47,7 +46,7 @@ function N(M, m) {
|
|
|
47
46
|
return [f(e.id), a];
|
|
48
47
|
})
|
|
49
48
|
);
|
|
50
|
-
for (const [e, t] of
|
|
49
|
+
for (const [e, t] of c)
|
|
51
50
|
s.has(e) || s.set(e, t);
|
|
52
51
|
const v = [...s.values().filter((e) => e.filter)], O = [...s.values().filter((e) => !e.filter)];
|
|
53
52
|
v.push(...O.sort((e, t) => e.label.localeCompare(t.label))), o.value = v;
|
|
@@ -73,6 +72,6 @@ function N(M, m) {
|
|
|
73
72
|
), o;
|
|
74
73
|
}
|
|
75
74
|
export {
|
|
76
|
-
|
|
75
|
+
K as useFilters
|
|
77
76
|
};
|
|
78
77
|
//# sourceMappingURL=filters-state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filters-state.js","sources":["../../../src/components/PlTableFilters/filters-state.ts"],"sourcesContent":["import type {\n Reactive,\n Ref } from 'vue';\nimport {\n reactive,\n ref,\n watch,\n} from 'vue';\nimport type {\n PlDataTableFiltersSettings,\n PlDataTableFilterStateInternal,\n} from './types';\nimport {\n canonicalizeJson,\n getPTableColumnId,\n type CanonicalizedJson,\n type PTableColumnId,\n type PlDataTableFilterState,\n} from '@platforma-sdk/model';\nimport { isJsonEqual } from '@milaboratories/helpers';\nimport {\n getFilterOptions,\n makeDiscreteOptions,\n isFilterValid,\n getColumnName,\n isAlphabetic,\n} from './filters_logic';\n\nexport function useFilters(\n settings: Ref<PlDataTableFiltersSettings>,\n state: Ref<PlDataTableFilterState[]>,\n): Reactive<{\n value: PlDataTableFilterStateInternal[];\n }> {\n// Watcher instead of computed to preserve open state of filters locally\n const defaultStateMap = ref<Map<CanonicalizedJson<PTableColumnId>, PlDataTableFilterStateInternal>>(new Map());\n const filters = reactive<{\n value: PlDataTableFilterStateInternal[];\n }>({\n value: [],\n });\n watch(\n () => settings.value,\n ({ columns, config: configFn, cachedState }) => {\n // Comptute default states for columns\n const defaultStateMapValue = defaultStateMap.value = new Map(\n columns\n .map((c, i) => {\n try {\n const id = getPTableColumnId(c);\n const config = configFn(c);\n const options = config.options\n ? getFilterOptions(c).filter((o) => config.options!.includes(o.value))\n : getFilterOptions(c);\n if (options.length === 0) return null;\n const discreteOptions = makeDiscreteOptions(c);\n const defaultFilter = config.default && isFilterValid(config.default, options, discreteOptions) ? config.default : null;\n const filter = defaultFilter\n ? {\n value: defaultFilter,\n disabled: false,\n open: false,\n }\n : null;\n const state: PlDataTableFilterStateInternal = {\n id,\n spec: c,\n label: getColumnName(c, i),\n alphabetic: isAlphabetic(c),\n options,\n discreteOptions,\n defaultFilter,\n filter,\n };\n return [canonicalizeJson<PTableColumnId>(id), state] as const;\n } catch (err: unknown) {\n console.error(`Filter creation for column ${c.id} has failed`, err);\n return null;\n }\n })\n .filter((e) => e !== null),\n );\n\n // Go through cached state, filter out states for not present columns, update state to match valid options\n const stateMap = new Map<CanonicalizedJson<PTableColumnId>, PlDataTableFilterStateInternal>(\n cachedState\n .filter((s) => defaultStateMapValue.has(canonicalizeJson<PTableColumnId>(s.id)))\n .map((s) => {\n const defaultState = defaultStateMapValue.get(canonicalizeJson<PTableColumnId>(s.id))!;\n const state = {\n ...defaultState,\n filter: s.filter && isFilterValid(s.filter.value, defaultState.options, defaultState.discreteOptions)\n ? {\n ...s.filter,\n open: filters.value.find((f) => isJsonEqual(f.id, s.id))?.filter?.open ?? false,\n }\n : null,\n } satisfies PlDataTableFilterStateInternal;\n return [canonicalizeJson<PTableColumnId>(s.id), state] as const;\n }),\n );\n\n // Set default states for columns not present in cached state\n for (const [idKey, state] of defaultStateMapValue) {\n if (!stateMap.has(idKey)) {\n stateMap.set(idKey, state);\n }\n }\n\n // States with not null filters should go first, in order they were added, then follow null filters in alphabetic order\n const states = [...stateMap.values().filter((s) => s.filter)];\n const hiddenFilters = [...stateMap.values().filter((s) => !s.filter)];\n states.push(...hiddenFilters.sort((a, b) => a.label.localeCompare(b.label)));\n filters.value = states;\n },\n { immediate: true },\n );\n\n // Persist state on change\n watch(\n () => filters.value,\n (filters) => {\n const cachedState = filters.map((f) => ({\n id: f.id,\n alphabetic: f.alphabetic,\n filter: f.filter\n ? {\n value: f.filter.value,\n disabled: f.filter.disabled,\n }\n : null,\n } satisfies PlDataTableFilterState));\n if (cachedState.length > 0 && !isJsonEqual(cachedState, state.value)) {\n state.value = cachedState;\n }\n },\n {\n immediate: true,\n deep: true,\n },\n );\n\n return filters;\n}\n"],"names":["useFilters","settings","state","defaultStateMap","ref","filters","reactive","watch","columns","configFn","cachedState","defaultStateMapValue","c","i","id","getPTableColumnId","config","options","getFilterOptions","o","discreteOptions","makeDiscreteOptions","defaultFilter","isFilterValid","filter","getColumnName","isAlphabetic","canonicalizeJson","err","stateMap","s","defaultState","_b","_a","f","isJsonEqual","idKey","states","hiddenFilters","a","b"],"mappings":"
|
|
1
|
+
{"version":3,"file":"filters-state.js","sources":["../../../src/components/PlTableFilters/filters-state.ts"],"sourcesContent":["import type {\n Reactive,\n Ref } from 'vue';\nimport {\n reactive,\n ref,\n watch,\n} from 'vue';\nimport type {\n PlDataTableFiltersSettings,\n PlDataTableFilterStateInternal,\n} from './types';\nimport {\n canonicalizeJson,\n getPTableColumnId,\n type CanonicalizedJson,\n type PTableColumnId,\n type PlDataTableFilterState,\n} from '@platforma-sdk/model';\nimport { isJsonEqual } from '@milaboratories/helpers';\nimport {\n getFilterOptions,\n makeDiscreteOptions,\n isFilterValid,\n getColumnName,\n isAlphabetic,\n} from './filters_logic';\n\nexport function useFilters(\n settings: Ref<PlDataTableFiltersSettings>,\n state: Ref<PlDataTableFilterState[]>,\n): Reactive<{\n value: PlDataTableFilterStateInternal[];\n }> {\n// Watcher instead of computed to preserve open state of filters locally\n const defaultStateMap = ref<Map<CanonicalizedJson<PTableColumnId>, PlDataTableFilterStateInternal>>(new Map());\n const filters = reactive<{\n value: PlDataTableFilterStateInternal[];\n }>({\n value: [],\n });\n watch(\n () => settings.value,\n ({ columns, config: configFn, cachedState }) => {\n // Comptute default states for columns\n const defaultStateMapValue = defaultStateMap.value = new Map(\n columns\n .map((c, i) => {\n try {\n const id = getPTableColumnId(c);\n const config = configFn(c);\n const options = config.options\n ? getFilterOptions(c).filter((o) => config.options!.includes(o.value))\n : getFilterOptions(c);\n if (options.length === 0) return null;\n const discreteOptions = makeDiscreteOptions(c);\n const defaultFilter = config.default && isFilterValid(config.default, options, discreteOptions) ? config.default : null;\n const filter = defaultFilter\n ? {\n value: defaultFilter,\n disabled: false,\n open: false,\n }\n : null;\n const state: PlDataTableFilterStateInternal = {\n id,\n spec: c,\n label: getColumnName(c, i),\n alphabetic: isAlphabetic(c),\n options,\n discreteOptions,\n defaultFilter,\n filter,\n };\n return [canonicalizeJson<PTableColumnId>(id), state] as const;\n } catch (err: unknown) {\n console.error(`Filter creation for column ${c.id} has failed`, err);\n return null;\n }\n })\n .filter((e) => e !== null),\n );\n\n // Go through cached state, filter out states for not present columns, update state to match valid options\n const stateMap = new Map<CanonicalizedJson<PTableColumnId>, PlDataTableFilterStateInternal>(\n cachedState\n .filter((s) => defaultStateMapValue.has(canonicalizeJson<PTableColumnId>(s.id)))\n .map((s) => {\n const defaultState = defaultStateMapValue.get(canonicalizeJson<PTableColumnId>(s.id))!;\n const state = {\n ...defaultState,\n filter: s.filter && isFilterValid(s.filter.value, defaultState.options, defaultState.discreteOptions)\n ? {\n ...s.filter,\n open: filters.value.find((f) => isJsonEqual(f.id, s.id))?.filter?.open ?? false,\n }\n : null,\n } satisfies PlDataTableFilterStateInternal;\n return [canonicalizeJson<PTableColumnId>(s.id), state] as const;\n }),\n );\n\n // Set default states for columns not present in cached state\n for (const [idKey, state] of defaultStateMapValue) {\n if (!stateMap.has(idKey)) {\n stateMap.set(idKey, state);\n }\n }\n\n // States with not null filters should go first, in order they were added, then follow null filters in alphabetic order\n const states = [...stateMap.values().filter((s) => s.filter)];\n const hiddenFilters = [...stateMap.values().filter((s) => !s.filter)];\n states.push(...hiddenFilters.sort((a, b) => a.label.localeCompare(b.label)));\n filters.value = states;\n },\n { immediate: true },\n );\n\n // Persist state on change\n watch(\n () => filters.value,\n (filters) => {\n const cachedState = filters.map((f) => ({\n id: f.id,\n alphabetic: f.alphabetic,\n filter: f.filter\n ? {\n value: f.filter.value,\n disabled: f.filter.disabled,\n }\n : null,\n } satisfies PlDataTableFilterState));\n if (cachedState.length > 0 && !isJsonEqual(cachedState, state.value)) {\n state.value = cachedState;\n }\n },\n {\n immediate: true,\n deep: true,\n },\n );\n\n return filters;\n}\n"],"names":["useFilters","settings","state","defaultStateMap","ref","filters","reactive","watch","columns","configFn","cachedState","defaultStateMapValue","c","i","id","getPTableColumnId","config","options","getFilterOptions","o","discreteOptions","makeDiscreteOptions","defaultFilter","isFilterValid","filter","getColumnName","isAlphabetic","canonicalizeJson","err","stateMap","s","defaultState","_b","_a","f","isJsonEqual","idKey","states","hiddenFilters","a","b"],"mappings":"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"}
|
|
@@ -5,7 +5,6 @@ import { getRawPlatformaInstance as m } from "@platforma-sdk/model";
|
|
|
5
5
|
import { LRUCache as d } from "lru-cache";
|
|
6
6
|
import { shallowRef as S, computed as f, getCurrentScope as R, effectScope as C, onScopeDispose as y } from "vue";
|
|
7
7
|
import { Fetcher as u } from "../lib/util/helpers/dist/utils.js";
|
|
8
|
-
import "../lib/util/helpers/dist/test_timeouts.js";
|
|
9
8
|
const p = {
|
|
10
9
|
cacheSize: 15e6
|
|
11
10
|
// 15 Mb
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileContent.js","sources":["../../src/composition/fileContent.ts"],"sourcesContent":["import type { BlobHandleAndSize } from '@platforma-sdk/model';\nimport { getRawPlatformaInstance } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { ComputedRef, ShallowRef, EffectScope } from 'vue';\nimport { computed, shallowRef, getCurrentScope, onScopeDispose, effectScope } from 'vue';\nimport type { ZodSchema, SafeParseReturnType } from 'zod';\nimport { Fetcher } from '@milaboratories/helpers';\n\ntype FileHandle = BlobHandleAndSize['handle'];\n\nexport type ReactiveFileContentOps = {\n /** Maximum size in bytes of file content to cache */\n cacheSize: number;\n lruCache?: LRUCache<FileHandle, FileContentData>;\n fetcher?: Fetcher<FileHandle, FileContentData>;\n};\n\nconst DefaultReactiveFileContentOps: ReactiveFileContentOps = {\n cacheSize: 15_000_000, // 15 Mb\n};\n\nclass FileContentData {\n private _str: string | undefined = undefined;\n private _rawJson: unknown | undefined = undefined;\n private _zodSchema: ZodSchema | undefined = undefined;\n private _validatedJson: SafeParseReturnType<unknown, unknown> | undefined = undefined;\n\n constructor(public readonly bytes: Uint8Array) {}\n\n public get str(): string {\n if (this._str === undefined) this._str = new TextDecoder().decode(this.bytes);\n return this._str;\n }\n\n public get rawJson(): unknown {\n if (this._rawJson === undefined) this._rawJson = JSON.parse(this.str);\n return this._rawJson;\n }\n\n public validatedJson<T>(schema: ZodSchema<T>): T | undefined {\n if (this._zodSchema !== schema) {\n this._validatedJson = schema.safeParse(this.rawJson);\n this._zodSchema = schema;\n }\n return this._validatedJson?.success ? (this._validatedJson.data as T) : undefined;\n }\n}\n\nconst scopes = new WeakMap<EffectScope, Map<FileHandle, ShallowRef<FileContentData | undefined>>>();\n\nfunction addScope(scope: EffectScope) {\n scopes.set(scope, new Map<FileHandle, ShallowRef<FileContentData | undefined>>());\n}\n\nconst globalCache = new LRUCache<FileHandle, FileContentData>({\n maxSize: DefaultReactiveFileContentOps.cacheSize,\n sizeCalculation: (value) => value.bytes.length,\n});\n\nconst globalFetcher = new Fetcher<FileHandle, FileContentData>();\n\nexport class ReactiveFileContent {\n private readonly fileDataCache: LRUCache<FileHandle, FileContentData>;\n private readonly fetcher: Fetcher<FileHandle, FileContentData>;\n private ns = new Map<string, Set<FileHandle>>();\n private currentKey: string | undefined;\n\n private constructor(private currentScope: EffectScope, _ops?: Partial<ReactiveFileContentOps>) {\n const ops: ReactiveFileContentOps = { ...DefaultReactiveFileContentOps, ...(_ops ?? {}) };\n this.fileDataCache = ops.lruCache ?? new LRUCache<FileHandle, FileContentData>({\n maxSize: ops.cacheSize,\n sizeCalculation: (value) => value.bytes.length,\n });\n this.fetcher = ops.fetcher ?? new Fetcher<FileHandle, FileContentData>();\n }\n\n /**\n * Experimental method to invalidate the refs map cache for a given key.\n */\n public withInvalidate<T>(key: string, cb: () => T) {\n const previous = this.ns.get(key);\n this.ns.set(key, new Set());\n this.currentKey = key;\n try {\n const res = cb();\n this.invalidate(key, previous);\n return res;\n } finally {\n this.currentKey = undefined;\n }\n }\n\n public stopScope() {\n scopes.delete(this.currentScope);\n this.currentScope.stop();\n }\n\n private async doFetch(handle: FileHandle) {\n if (!this.fileDataCache.has(handle)) {\n const fileContentData = await this.fetcher.fetch(handle, async () => new FileContentData(await getRawPlatformaInstance().blobDriver.getContent(handle)));\n this.fileDataCache.set(handle, fileContentData);\n }\n\n return this.fileDataCache.get(handle)!;\n }\n\n private getSize() {\n const refsMap = this.getRefsMap();\n return refsMap ? refsMap.size : 0;\n }\n\n private getRefsMap() {\n return scopes.get(this.currentScope);\n }\n\n private invalidate(key: string, previous: Set<FileHandle> | undefined) {\n if (!previous) {\n return;\n }\n\n const actual = this.ns.get(key)!;\n\n for (const handle of actual) {\n previous.delete(handle);\n }\n\n const map = this.getRefsMap();\n\n for (const handle of previous) {\n map?.delete(handle);\n }\n }\n\n private withHandle(handle: FileHandle) {\n if (this.currentKey) {\n this.ns.get(this.currentKey)?.add(handle);\n }\n }\n\n private getDataRef(handle: FileHandle): ShallowRef<FileContentData | undefined> {\n const refsMap = this.getRefsMap();\n\n if (!refsMap) {\n throw new Error('ReactiveFileContent must be used within a Vue component or effect scope.');\n }\n\n this.withHandle(handle);\n\n const refFromMap = refsMap.get(handle);\n\n if (refFromMap !== undefined) {\n return refFromMap;\n }\n\n const newRef = shallowRef<FileContentData>();\n refsMap.set(handle, newRef);\n\n // Initiating actual fetch from the cache, that will in turn initiate upload\n (async () => {\n const maxRetries = 8;\n const retryDelay = 1000; // 1 second\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n const data = await this.doFetch(handle);\n newRef.value = data;\n return;\n } catch (err: unknown) {\n console.error(`File download attempt ${attempt + 1}/${maxRetries} failed:`, err);\n\n if (attempt < maxRetries - 1) {\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n } else {\n console.error(`Failed to download file after ${maxRetries} attempts`);\n }\n }\n }\n })();\n\n return newRef;\n }\n\n public getContentBytes(handle: FileHandle): ComputedRef<Uint8Array | undefined>;\n public getContentBytes(handle: FileHandle | undefined): ComputedRef<Uint8Array | undefined> | undefined;\n public getContentBytes(handle: FileHandle | undefined): ComputedRef<Uint8Array | undefined> | undefined {\n if (handle === undefined) return undefined;\n const dataRef = this.getDataRef(handle);\n return computed(() => dataRef.value?.bytes);\n }\n\n public getContentString(handle: FileHandle): ComputedRef<string | undefined>;\n public getContentString(handle: FileHandle | undefined): ComputedRef<string | undefined> | undefined;\n public getContentString(handle: FileHandle | undefined): ComputedRef<string | undefined> | undefined {\n if (handle === undefined) return undefined;\n const dataRef = this.getDataRef(handle);\n return computed(() => dataRef.value?.str);\n }\n\n public getContentJson<T>(handle: FileHandle, schema: ZodSchema<T>): ComputedRef<T | undefined>;\n public getContentJson<T>(handle: FileHandle | undefined, schema: ZodSchema<T>): ComputedRef<T | undefined> | undefined;\n public getContentJson<T = unknown>(handle: FileHandle): ComputedRef<T | undefined>;\n public getContentJson<T = unknown>(handle: FileHandle | undefined): ComputedRef<T | undefined> | undefined;\n public getContentJson<T>(handle: FileHandle | undefined, schema?: ZodSchema<T>): ComputedRef<T | undefined> | undefined;\n public getContentJson<T>(handle: FileHandle | undefined, schema?: ZodSchema<T>): ComputedRef<T | undefined> | undefined {\n if (handle === undefined) return undefined;\n const dataRef = this.getDataRef(handle);\n return computed(() => (schema === undefined ? dataRef.value?.rawJson : dataRef.value?.validatedJson(schema)) as T);\n }\n\n private static initScope(_scope: EffectScope | undefined) {\n let scope = getCurrentScope() ?? _scope;\n\n if (!scope) {\n console.warn('Current scope not found, using new detached scope...');\n scope = effectScope(true);\n }\n\n addScope(scope);\n\n onScopeDispose(() => {\n scopes.delete(scope);\n });\n\n return scope;\n }\n\n /**\n * Creates a ReactiveFileContent instance with isolated cache and fetcher.\n * Use this when you need component-specific caching.\n *\n * @example\n * ```ts\n * import { ReactiveFileContent } from '@platforma-sdk/ui-vue';\n * import { computed } from 'vue';\n *\n * const fileContent = ReactiveFileContent.use();\n *\n * const processedData = computed(() => {\n * const content = fileContent.getContentString(fileHandle).value;\n * return content?.split('\\n').length ?? 0;\n * });\n * ```\n */\n public static use(_ops?: Partial<ReactiveFileContentOps>, _scope?: EffectScope) {\n const scope = this.initScope(_scope);\n\n return new ReactiveFileContent(scope, { ..._ops });\n }\n\n /**\n * Creates a ReactiveFileContent instance with globally shared cache and fetcher.\n * Use this to share file content cache across multiple components.\n *\n * @example\n * ```ts\n * import { ReactiveFileContent } from '@platforma-sdk/ui-vue';\n * import { computed } from 'vue';\n *\n * const fileContent = ReactiveFileContent.useGlobal();\n *\n * const combinedData = computed(() => {\n * const data1 = fileContent.getContentJson(handle1).value;\n * const data2 = fileContent.getContentJson(handle2).value;\n * return { data1, data2 };\n * });\n * ```\n */\n public static useGlobal(_ops?: Partial<ReactiveFileContentOps>, _scope?: EffectScope) {\n const scope = this.initScope(_scope);\n\n return new ReactiveFileContent(scope, { ..._ops, lruCache: globalCache, fetcher: globalFetcher });\n }\n}\n"],"names":["DefaultReactiveFileContentOps","FileContentData","bytes","__publicField","schema","_a","scopes","addScope","scope","globalCache","LRUCache","value","globalFetcher","Fetcher","ReactiveFileContent","currentScope","_ops","ops","key","cb","previous","res","handle","fileContentData","getRawPlatformaInstance","refsMap","actual","map","refFromMap","newRef","shallowRef","attempt","data","err","resolve","dataRef","computed","_b","_scope","getCurrentScope","effectScope","onScopeDispose"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fileContent.js","sources":["../../src/composition/fileContent.ts"],"sourcesContent":["import type { BlobHandleAndSize } from '@platforma-sdk/model';\nimport { getRawPlatformaInstance } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { ComputedRef, ShallowRef, EffectScope } from 'vue';\nimport { computed, shallowRef, getCurrentScope, onScopeDispose, effectScope } from 'vue';\nimport type { ZodSchema, SafeParseReturnType } from 'zod';\nimport { Fetcher } from '@milaboratories/helpers';\n\ntype FileHandle = BlobHandleAndSize['handle'];\n\nexport type ReactiveFileContentOps = {\n /** Maximum size in bytes of file content to cache */\n cacheSize: number;\n lruCache?: LRUCache<FileHandle, FileContentData>;\n fetcher?: Fetcher<FileHandle, FileContentData>;\n};\n\nconst DefaultReactiveFileContentOps: ReactiveFileContentOps = {\n cacheSize: 15_000_000, // 15 Mb\n};\n\nclass FileContentData {\n private _str: string | undefined = undefined;\n private _rawJson: unknown | undefined = undefined;\n private _zodSchema: ZodSchema | undefined = undefined;\n private _validatedJson: SafeParseReturnType<unknown, unknown> | undefined = undefined;\n\n constructor(public readonly bytes: Uint8Array) {}\n\n public get str(): string {\n if (this._str === undefined) this._str = new TextDecoder().decode(this.bytes);\n return this._str;\n }\n\n public get rawJson(): unknown {\n if (this._rawJson === undefined) this._rawJson = JSON.parse(this.str);\n return this._rawJson;\n }\n\n public validatedJson<T>(schema: ZodSchema<T>): T | undefined {\n if (this._zodSchema !== schema) {\n this._validatedJson = schema.safeParse(this.rawJson);\n this._zodSchema = schema;\n }\n return this._validatedJson?.success ? (this._validatedJson.data as T) : undefined;\n }\n}\n\nconst scopes = new WeakMap<EffectScope, Map<FileHandle, ShallowRef<FileContentData | undefined>>>();\n\nfunction addScope(scope: EffectScope) {\n scopes.set(scope, new Map<FileHandle, ShallowRef<FileContentData | undefined>>());\n}\n\nconst globalCache = new LRUCache<FileHandle, FileContentData>({\n maxSize: DefaultReactiveFileContentOps.cacheSize,\n sizeCalculation: (value) => value.bytes.length,\n});\n\nconst globalFetcher = new Fetcher<FileHandle, FileContentData>();\n\nexport class ReactiveFileContent {\n private readonly fileDataCache: LRUCache<FileHandle, FileContentData>;\n private readonly fetcher: Fetcher<FileHandle, FileContentData>;\n private ns = new Map<string, Set<FileHandle>>();\n private currentKey: string | undefined;\n\n private constructor(private currentScope: EffectScope, _ops?: Partial<ReactiveFileContentOps>) {\n const ops: ReactiveFileContentOps = { ...DefaultReactiveFileContentOps, ...(_ops ?? {}) };\n this.fileDataCache = ops.lruCache ?? new LRUCache<FileHandle, FileContentData>({\n maxSize: ops.cacheSize,\n sizeCalculation: (value) => value.bytes.length,\n });\n this.fetcher = ops.fetcher ?? new Fetcher<FileHandle, FileContentData>();\n }\n\n /**\n * Experimental method to invalidate the refs map cache for a given key.\n */\n public withInvalidate<T>(key: string, cb: () => T) {\n const previous = this.ns.get(key);\n this.ns.set(key, new Set());\n this.currentKey = key;\n try {\n const res = cb();\n this.invalidate(key, previous);\n return res;\n } finally {\n this.currentKey = undefined;\n }\n }\n\n public stopScope() {\n scopes.delete(this.currentScope);\n this.currentScope.stop();\n }\n\n private async doFetch(handle: FileHandle) {\n if (!this.fileDataCache.has(handle)) {\n const fileContentData = await this.fetcher.fetch(handle, async () => new FileContentData(await getRawPlatformaInstance().blobDriver.getContent(handle)));\n this.fileDataCache.set(handle, fileContentData);\n }\n\n return this.fileDataCache.get(handle)!;\n }\n\n private getSize() {\n const refsMap = this.getRefsMap();\n return refsMap ? refsMap.size : 0;\n }\n\n private getRefsMap() {\n return scopes.get(this.currentScope);\n }\n\n private invalidate(key: string, previous: Set<FileHandle> | undefined) {\n if (!previous) {\n return;\n }\n\n const actual = this.ns.get(key)!;\n\n for (const handle of actual) {\n previous.delete(handle);\n }\n\n const map = this.getRefsMap();\n\n for (const handle of previous) {\n map?.delete(handle);\n }\n }\n\n private withHandle(handle: FileHandle) {\n if (this.currentKey) {\n this.ns.get(this.currentKey)?.add(handle);\n }\n }\n\n private getDataRef(handle: FileHandle): ShallowRef<FileContentData | undefined> {\n const refsMap = this.getRefsMap();\n\n if (!refsMap) {\n throw new Error('ReactiveFileContent must be used within a Vue component or effect scope.');\n }\n\n this.withHandle(handle);\n\n const refFromMap = refsMap.get(handle);\n\n if (refFromMap !== undefined) {\n return refFromMap;\n }\n\n const newRef = shallowRef<FileContentData>();\n refsMap.set(handle, newRef);\n\n // Initiating actual fetch from the cache, that will in turn initiate upload\n (async () => {\n const maxRetries = 8;\n const retryDelay = 1000; // 1 second\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n const data = await this.doFetch(handle);\n newRef.value = data;\n return;\n } catch (err: unknown) {\n console.error(`File download attempt ${attempt + 1}/${maxRetries} failed:`, err);\n\n if (attempt < maxRetries - 1) {\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n } else {\n console.error(`Failed to download file after ${maxRetries} attempts`);\n }\n }\n }\n })();\n\n return newRef;\n }\n\n public getContentBytes(handle: FileHandle): ComputedRef<Uint8Array | undefined>;\n public getContentBytes(handle: FileHandle | undefined): ComputedRef<Uint8Array | undefined> | undefined;\n public getContentBytes(handle: FileHandle | undefined): ComputedRef<Uint8Array | undefined> | undefined {\n if (handle === undefined) return undefined;\n const dataRef = this.getDataRef(handle);\n return computed(() => dataRef.value?.bytes);\n }\n\n public getContentString(handle: FileHandle): ComputedRef<string | undefined>;\n public getContentString(handle: FileHandle | undefined): ComputedRef<string | undefined> | undefined;\n public getContentString(handle: FileHandle | undefined): ComputedRef<string | undefined> | undefined {\n if (handle === undefined) return undefined;\n const dataRef = this.getDataRef(handle);\n return computed(() => dataRef.value?.str);\n }\n\n public getContentJson<T>(handle: FileHandle, schema: ZodSchema<T>): ComputedRef<T | undefined>;\n public getContentJson<T>(handle: FileHandle | undefined, schema: ZodSchema<T>): ComputedRef<T | undefined> | undefined;\n public getContentJson<T = unknown>(handle: FileHandle): ComputedRef<T | undefined>;\n public getContentJson<T = unknown>(handle: FileHandle | undefined): ComputedRef<T | undefined> | undefined;\n public getContentJson<T>(handle: FileHandle | undefined, schema?: ZodSchema<T>): ComputedRef<T | undefined> | undefined;\n public getContentJson<T>(handle: FileHandle | undefined, schema?: ZodSchema<T>): ComputedRef<T | undefined> | undefined {\n if (handle === undefined) return undefined;\n const dataRef = this.getDataRef(handle);\n return computed(() => (schema === undefined ? dataRef.value?.rawJson : dataRef.value?.validatedJson(schema)) as T);\n }\n\n private static initScope(_scope: EffectScope | undefined) {\n let scope = getCurrentScope() ?? _scope;\n\n if (!scope) {\n console.warn('Current scope not found, using new detached scope...');\n scope = effectScope(true);\n }\n\n addScope(scope);\n\n onScopeDispose(() => {\n scopes.delete(scope);\n });\n\n return scope;\n }\n\n /**\n * Creates a ReactiveFileContent instance with isolated cache and fetcher.\n * Use this when you need component-specific caching.\n *\n * @example\n * ```ts\n * import { ReactiveFileContent } from '@platforma-sdk/ui-vue';\n * import { computed } from 'vue';\n *\n * const fileContent = ReactiveFileContent.use();\n *\n * const processedData = computed(() => {\n * const content = fileContent.getContentString(fileHandle).value;\n * return content?.split('\\n').length ?? 0;\n * });\n * ```\n */\n public static use(_ops?: Partial<ReactiveFileContentOps>, _scope?: EffectScope) {\n const scope = this.initScope(_scope);\n\n return new ReactiveFileContent(scope, { ..._ops });\n }\n\n /**\n * Creates a ReactiveFileContent instance with globally shared cache and fetcher.\n * Use this to share file content cache across multiple components.\n *\n * @example\n * ```ts\n * import { ReactiveFileContent } from '@platforma-sdk/ui-vue';\n * import { computed } from 'vue';\n *\n * const fileContent = ReactiveFileContent.useGlobal();\n *\n * const combinedData = computed(() => {\n * const data1 = fileContent.getContentJson(handle1).value;\n * const data2 = fileContent.getContentJson(handle2).value;\n * return { data1, data2 };\n * });\n * ```\n */\n public static useGlobal(_ops?: Partial<ReactiveFileContentOps>, _scope?: EffectScope) {\n const scope = this.initScope(_scope);\n\n return new ReactiveFileContent(scope, { ..._ops, lruCache: globalCache, fetcher: globalFetcher });\n }\n}\n"],"names":["DefaultReactiveFileContentOps","FileContentData","bytes","__publicField","schema","_a","scopes","addScope","scope","globalCache","LRUCache","value","globalFetcher","Fetcher","ReactiveFileContent","currentScope","_ops","ops","key","cb","previous","res","handle","fileContentData","getRawPlatformaInstance","refsMap","actual","map","refFromMap","newRef","shallowRef","attempt","data","err","resolve","dataRef","computed","_b","_scope","getCurrentScope","effectScope","onScopeDispose"],"mappings":"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"}
|
package/dist/createModel.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { ref as v, watch as i, computed as l, unref as y, reactive as C } from "vue";
|
|
2
2
|
import { isJsonEqual as Z, deepClone as m } from "./lib/util/helpers/dist/objects.js";
|
|
3
|
-
import "./lib/util/helpers/dist/test_timeouts.js";
|
|
4
3
|
import { identity as q, isZodError as w, ensureError as x, formatZodError as J } from "./utils.js";
|
|
5
|
-
function
|
|
4
|
+
function j(o) {
|
|
6
5
|
const u = o.validate ?? q, { autoSave: f } = o, r = v(), a = v(), c = (e) => {
|
|
7
6
|
a.value = {
|
|
8
7
|
model: m(e)
|
|
@@ -57,6 +56,6 @@ function k(o) {
|
|
|
57
56
|
});
|
|
58
57
|
}
|
|
59
58
|
export {
|
|
60
|
-
|
|
59
|
+
j as createModel
|
|
61
60
|
};
|
|
62
61
|
//# sourceMappingURL=createModel.js.map
|