@platforma-sdk/ui-vue 1.82.0 → 1.82.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 +10 -10
- package/.turbo/turbo-formatter$colon$check.log +2 -2
- package/.turbo/turbo-linter$colon$check.log +2 -2
- package/.turbo/turbo-types$colon$check.log +1 -1
- package/CHANGELOG.md +31 -0
- package/dist/components/PlAgDataTable/PlAgDataTableV2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.style.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +92 -82
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.d.ts +10 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.js +2 -2
- package/dist/components/PlAgDataTable/sources/table-state-v2.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.test.d.ts +2 -0
- package/dist/components/PlAgDataTable/sources/table-state-v2.test.d.ts.map +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js.map +1 -1
- package/package.json +5 -5
- package/src/components/PlAgDataTable/PlAgDataTableV2.vue +43 -4
- package/src/components/PlAgDataTable/sources/table-state-v2.test.ts +37 -0
- package/src/components/PlAgDataTable/sources/table-state-v2.ts +17 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-state-v2.js","names":[],"sources":["../../../../src/components/PlAgDataTable/sources/table-state-v2.ts"],"sourcesContent":["import {\n createDefaultPTableParams,\n parseJson,\n upgradePlDataTableStateV2,\n type FilterSpec,\n type FilterSpecLeaf,\n type PTableColumnId,\n type PTableColumnSpec,\n type PlDataTableGridStateCore,\n type PlDataTableSheetState,\n type PlDataTableStateV2,\n type PlDataTableStateV2CacheEntry,\n type PlDataTableStateV2Normalized,\n type PTableParamsV2,\n type PTableSorting,\n type PlDataTableFilterSpecLeaf,\n type PlDataTableFilterMeta,\n type PlDataTableFilters,\n distillFilterSpec,\n PlDataTableFiltersWithMeta,\n getPTableColumnId,\n} from \"@platforma-sdk/model\";\nimport { computed, type Ref, type WritableComputedRef } from \"vue\";\nimport type { PlDataTableSettingsV2 } from \"../types\";\nimport { isJsonEqual, randomInt, getField, Nil } from \"@milaboratories/helpers\";\nimport { computedCached } from \"@milaboratories/uikit\";\nimport { isStringValueType, isNumericValueType } from \"../../PlAdvancedFilter/utils\";\nimport { debounce, isNil } from \"es-toolkit\";\n\nexport function useTableState(\n tableStateDenormalized: Ref<PlDataTableStateV2>,\n settings: Ref<PlDataTableSettingsV2>,\n columns: Ref<PTableColumnSpec[]>,\n defaultFilters: Ref<Nil | PlDataTableFilters>,\n): {\n gridState: WritableComputedRef<PlDataTableGridStateCore>;\n sheetsState: WritableComputedRef<PlDataTableSheetState[]>;\n\n searchString: WritableComputedRef<string>;\n filtersState: Ref<PlDataTableFiltersWithMeta>;\n defaultFiltersState: Ref<null | PlDataTableFiltersWithMeta>;\n resetDefaultFilters: () => void;\n} {\n const tableStateNormalized = computedCached<PlDataTableStateV2Normalized>({\n get: () => upgradePlDataTableStateV2(tableStateDenormalized.value),\n set: debounce((newState) => (tableStateDenormalized.value = newState), 300),\n writeThrough: true,\n });\n\n const tableState = computed<PlDataTableStateV2CacheEntryNullable>({\n get: () => {\n const defaultState = makeDefaultState();\n\n const sourceId = settings.value.sourceId;\n const undefinedSourceId = \"error\" in settings.value && settings.value.error == null;\n if (!sourceId && undefinedSourceId) return defaultState;\n\n const suitableSourceId = sourceId ?? tableStateNormalized.value.stateCache.at(-1)?.sourceId;\n if (!suitableSourceId) return defaultState;\n\n const cachedState = tableStateNormalized.value.stateCache.find(\n (entry) => entry.sourceId === suitableSourceId,\n );\n if (!cachedState) return { ...defaultState, sourceId: suitableSourceId };\n\n return cachedState;\n },\n set: (state) => {\n const newState: PlDataTableStateV2Normalized = {\n ...tableStateNormalized.value,\n pTableParams: createDefaultPTableParams(),\n };\n\n if (state.sourceId) {\n newState.pTableParams = createPTableParams(state, columns.value);\n\n const stateIdx = newState.stateCache.findIndex(\n (entry) => entry.sourceId === state.sourceId,\n );\n if (stateIdx !== -1) {\n newState.stateCache.splice(stateIdx, 1);\n }\n const CacheDepth = 5;\n newState.stateCache.push(state);\n newState.stateCache = newState.stateCache.slice(-CacheDepth);\n }\n\n if (!isJsonEqual(tableStateNormalized.value, newState)) {\n tableStateNormalized.value = newState;\n }\n },\n });\n\n const gridState = computed<PlDataTableGridStateCore>({\n get: () => tableState.value.gridState,\n set: (gridState) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n gridState,\n };\n }\n },\n });\n\n const sheetsState = computed<PlDataTableSheetState[]>({\n get: () => tableState.value.sheetsState,\n set: (sheetsState) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n sheetsState,\n };\n }\n },\n });\n\n // --- User filters (editable by user) ---\n const filtersState = computed<PlDataTableFiltersWithMeta>({\n get: () => {\n const raw = tableState.value.filtersState;\n return isNil(raw) ? getEmptyGroupWithMeta() : normalizeFiltersState(raw);\n },\n set: (filtersState: PlDataTableFiltersWithMeta) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n filtersState,\n };\n }\n },\n });\n\n // --- Default filters (from model, separate list) ---\n const defaultFiltersState = computed<null | PlDataTableFiltersWithMeta>({\n get: () => {\n const raw = tableState.value.defaultFiltersState;\n if (!isNil(raw)) {\n return normalizeFiltersState(raw);\n }\n if (!isNil(defaultFilters.value)) {\n return annotateFiltersWithIds(normalizeFiltersState(defaultFilters.value));\n }\n return null;\n },\n set: (defaultFiltersState: null | PlDataTableFiltersWithMeta) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n defaultFiltersState,\n };\n }\n },\n });\n\n function resetDefaultFilters(): void {\n defaultFiltersState.value = isNil(defaultFilters.value)\n ? null\n : annotateFiltersWithIds(normalizeFiltersState(defaultFilters.value));\n }\n\n const searchString = computed<string>({\n get: () => tableState.value.searchString ?? \"\",\n set: (searchString: string) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n searchString,\n };\n }\n },\n });\n\n return {\n gridState,\n sheetsState,\n searchString,\n filtersState,\n defaultFiltersState,\n resetDefaultFilters,\n };\n}\n\n// --- Types ---\n\ntype PlDataTableStateV2CacheEntryNullable =\n | PlDataTableStateV2CacheEntry\n | {\n sourceId: null;\n gridState: Record<string, never>;\n sheetsState: [];\n filtersState: null;\n defaultFiltersState: null;\n searchString?: string;\n };\n\ntype FilterNode = FilterSpec<PlDataTableFilterSpecLeaf>;\ntype AnnotatedFilterSpec = FilterSpec<PlDataTableFilterSpecLeaf, PlDataTableFilterMeta>;\n\n// --- Core ---\n\nfunction createPTableParams(\n state: PlDataTableStateV2CacheEntry,\n filterableColumns: PTableColumnSpec[],\n): PTableParamsV2 {\n // User filters: sheets + user filter state + search\n const searchNode = createSearchFilterNode(filterableColumns, state.searchString);\n const unsuppressedUserFilters = isNil(state.filtersState)\n ? null\n : stripSuppressedFilters(state.filtersState);\n const userParts = [\n ...convertPartitionFiltersToFilterSpec(state.sheetsState),\n ...(isNil(unsuppressedUserFilters) ? [] : [unsuppressedUserFilters]),\n ...(isNil(searchNode) ? [] : [searchNode]),\n ];\n const filters: null | PlDataTableFilters = distillFilterSpec(\n userParts.length === 0\n ? null\n : userParts.length === 1\n ? userParts[0]\n : { type: \"and\", filters: userParts },\n );\n const unsuppressedDefaultFilters = isNil(state.defaultFiltersState)\n ? null\n : stripSuppressedFilters(state.defaultFiltersState);\n const defaultFilters: null | PlDataTableFilters = isNil(unsuppressedDefaultFilters)\n ? null\n : // If all filters are suppressed, we should pass an empty filter group instead of null to prevent fallback to defaults in the model\n (distillFilterSpec(unsuppressedDefaultFilters) ?? getEmptyGroup());\n\n return {\n sourceId: state.sourceId,\n hiddenColIds: getHiddenColIds(state.gridState.columnVisibility),\n sorting: convertAgSortingToPTableSorting(state.gridState.sort),\n filters,\n defaultFilters,\n };\n}\n\n/**\n * Normalizes raw filter state into a valid root filter structure.\n * Valid structure is Root(Group, Group, ...) — double nesting required:\n * root is and/or group, each child is also and/or group containing leaf filters.\n * - null/undefined/invalid → empty root\n * - Leaf node → Root(Group(leaf))\n * - Group with leaf children → Root(Group(leaves...))\n * - Group with group children → as-is\n */\nfunction normalizeFiltersState(raw: FilterNode) {\n // Leaf node → wrap in double nesting: Root(Group(leaf))\n if (raw.type !== \"and\" && raw.type !== \"or\" && raw.type !== \"not\") {\n if (\"type\" in raw && !isNil(raw.type)) {\n return {\n id: randomInt(),\n type: \"and\" as const,\n isExpanded: true,\n filters: [\n {\n id: randomInt(),\n type: \"and\" as const,\n isExpanded: true,\n filters: [raw as AnnotatedFilterSpec],\n } as AnnotatedFilterSpec,\n ],\n };\n }\n return getEmptyGroupWithMeta();\n }\n\n // Already a group — ensure children are also groups (double nesting)\n if ((raw.type === \"and\" || raw.type === \"or\") && \"filters\" in raw && Array.isArray(raw.filters)) {\n const allChildrenAreGroups = raw.filters.every(\n (f: FilterNode) => f.type === \"and\" || f.type === \"or\" || f.type === \"not\",\n );\n if (allChildrenAreGroups) {\n return raw as PlDataTableFiltersWithMeta;\n }\n // Children are leaves — wrap them in a single group\n return {\n id: randomInt(),\n type: raw.type as \"and\" | \"or\",\n isExpanded: true,\n filters: [\n {\n id: randomInt(),\n type: raw.type as \"and\" | \"or\",\n isExpanded: true,\n filters: raw.filters as AnnotatedFilterSpec[],\n } as AnnotatedFilterSpec,\n ],\n };\n }\n\n return getEmptyGroupWithMeta();\n}\n\nfunction getEmptyGroup(): PlDataTableFilters {\n return {\n type: \"and\" as const,\n filters: [],\n };\n}\nfunction getEmptyGroupWithMeta(): PlDataTableFiltersWithMeta {\n return {\n ...getEmptyGroup(),\n id: randomInt(),\n isExpanded: true,\n } as PlDataTableFiltersWithMeta;\n}\n\n/**\n * Recursively removes nodes where isSuppressed === true from a PlDataTableFiltersWithMeta tree.\n */\nfunction stripSuppressedFilters(node: PlDataTableFiltersWithMeta): PlDataTableFiltersWithMeta {\n return {\n ...node,\n filters: node.filters\n .filter((child) => !(\"isSuppressed\" in child && child.isSuppressed === true))\n .map((child) =>\n \"filters\" in child && (child.type === \"and\" || child.type === \"or\")\n ? stripSuppressedFilters(child as PlDataTableFiltersWithMeta)\n : child,\n ),\n };\n}\n\nfunction createSearchFilterNode(\n columns: PTableColumnSpec[],\n search: null | undefined | string,\n): null | FilterSpec<FilterSpecLeaf<PTableColumnId>> {\n const trimmed = search?.trim();\n if (isNil(trimmed) || trimmed.length === 0) return null;\n\n const parts: FilterSpec<FilterSpecLeaf<PTableColumnId>>[] = [];\n const numericValue = Number(trimmed);\n const isValidNumber = trimmed.length > 0 && !isNaN(numericValue) && isFinite(numericValue);\n\n for (const col of columns) {\n const column = getPTableColumnId(col);\n const spec = col.spec;\n\n if (isStringValueType(spec)) {\n parts.push({ type: \"patternEquals\", column, value: trimmed });\n }\n\n if (isNumericValueType(spec) && isValidNumber) {\n parts.push({ type: \"equal\", column, x: numericValue });\n }\n }\n\n if (parts.length === 0) return null;\n\n return { type: \"or\", filters: parts };\n}\n\n// --- Helpers ---\n\n/**\n * Recursively ensures every node in a filter tree has an `id` field.\n * Does not set `source` meta — defaults are now a separate list.\n */\nfunction annotateFiltersWithIds(\n filters: PlDataTableFilters | PlDataTableFiltersWithMeta,\n): PlDataTableFiltersWithMeta {\n return annotateNodeWithIds(filters) as PlDataTableFiltersWithMeta;\n}\n\nfunction annotateNodeWithIds(\n node: FilterNode | PlDataTableFilters | PlDataTableFiltersWithMeta,\n): AnnotatedFilterSpec {\n switch (node.type) {\n case \"and\":\n return {\n id: getField(node, \"id\") ?? randomInt(),\n isExpanded: getField(node, \"isExpanded\") ?? true,\n type: \"and\" as const,\n filters: node.filters.map((child) => annotateNodeWithIds(child)),\n };\n case \"or\":\n return {\n id: getField(node, \"id\") ?? randomInt(),\n isExpanded: getField(node, \"isExpanded\") ?? true,\n type: \"or\" as const,\n filters: node.filters.map((child) => annotateNodeWithIds(child)),\n };\n case \"not\":\n return {\n id: randomInt(),\n isExpanded: true,\n type: \"not\" as const,\n filter: annotateNodeWithIds(node.filter),\n };\n default:\n return { ...node, id: getField(node, \"id\") ?? randomInt() } as AnnotatedFilterSpec;\n }\n}\n\n// --- Utilities ---\n\nfunction convertPartitionFiltersToFilterSpec(\n sheetsState: PlDataTableSheetState[],\n): FilterSpec<FilterSpecLeaf<PTableColumnId>>[] {\n return sheetsState.map((s) => {\n const column: PTableColumnId = { type: \"axis\", id: s.axisId };\n return typeof s.value === \"number\"\n ? { type: \"equal\" as const, column, x: s.value }\n : { type: \"patternEquals\" as const, column, value: s.value };\n });\n}\n\nfunction convertAgSortingToPTableSorting(state: PlDataTableGridStateCore[\"sort\"]): PTableSorting[] {\n return (\n state?.sortModel.map((item) => ({\n column: parseJson<PTableColumnId>(item.colId),\n ascending: item.sort === \"asc\",\n naAndAbsentAreLeastValues: item.sort === \"asc\",\n })) ?? []\n );\n}\n\nfunction getHiddenColIds(\n state: PlDataTableGridStateCore[\"columnVisibility\"],\n): PTableColumnId[] | null {\n return state?.hiddenColIds?.map((json) => parseJson<PTableColumnId>(json)) ?? null;\n}\n\nfunction makeDefaultState(): PlDataTableStateV2CacheEntryNullable {\n return {\n sourceId: null,\n gridState: {},\n sheetsState: [],\n filtersState: null,\n defaultFiltersState: null,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table-state-v2.js","names":[],"sources":["../../../../src/components/PlAgDataTable/sources/table-state-v2.ts"],"sourcesContent":["import {\n createDefaultPTableParams,\n parseJson,\n upgradePlDataTableStateV2,\n type FilterSpec,\n type FilterSpecLeaf,\n type PTableColumnId,\n type PTableColumnSpec,\n type PlDataTableGridStateCore,\n type PlDataTableSheetState,\n type PlDataTableStateV2,\n type PlDataTableStateV2CacheEntry,\n type PlDataTableStateV2Normalized,\n type PTableParamsV2,\n type PTableSorting,\n type PlDataTableFilterSpecLeaf,\n type PlDataTableFilterMeta,\n type PlDataTableFilters,\n distillFilterSpec,\n PlDataTableFiltersWithMeta,\n getPTableColumnId,\n} from \"@platforma-sdk/model\";\nimport { computed, type Ref, type WritableComputedRef } from \"vue\";\nimport type { PlDataTableSettingsV2 } from \"../types\";\nimport { isJsonEqual, randomInt, getField, Nil } from \"@milaboratories/helpers\";\nimport { computedCached } from \"@milaboratories/uikit\";\nimport { isStringValueType, isNumericValueType } from \"../../PlAdvancedFilter/utils\";\nimport { debounce, isNil } from \"es-toolkit\";\n\nexport function useTableState(\n tableStateDenormalized: Ref<PlDataTableStateV2>,\n settings: Ref<PlDataTableSettingsV2>,\n columns: Ref<PTableColumnSpec[]>,\n defaultFilters: Ref<Nil | PlDataTableFilters>,\n): {\n gridState: WritableComputedRef<PlDataTableGridStateCore>;\n sheetsState: WritableComputedRef<PlDataTableSheetState[]>;\n\n searchString: WritableComputedRef<string>;\n filtersState: Ref<PlDataTableFiltersWithMeta>;\n defaultFiltersState: Ref<null | PlDataTableFiltersWithMeta>;\n resetDefaultFilters: () => void;\n} {\n const tableStateNormalized = computedCached<PlDataTableStateV2Normalized>({\n get: () => upgradePlDataTableStateV2(tableStateDenormalized.value),\n set: debounce((newState) => (tableStateDenormalized.value = newState), 300),\n writeThrough: true,\n });\n\n const tableState = computed<PlDataTableStateV2CacheEntryNullable>({\n get: () => {\n const defaultState = makeDefaultState();\n\n const sourceId = settings.value.sourceId;\n const undefinedSourceId = \"error\" in settings.value && settings.value.error == null;\n if (!sourceId && undefinedSourceId) return defaultState;\n\n const suitableSourceId = sourceId ?? tableStateNormalized.value.stateCache.at(-1)?.sourceId;\n if (!suitableSourceId) return defaultState;\n\n const cachedState = tableStateNormalized.value.stateCache.find(\n (entry) => entry.sourceId === suitableSourceId,\n );\n if (!cachedState) return { ...defaultState, sourceId: suitableSourceId };\n\n return cachedState;\n },\n set: (state) => {\n const newState: PlDataTableStateV2Normalized = {\n ...tableStateNormalized.value,\n pTableParams: createDefaultPTableParams(),\n };\n\n if (state.sourceId) {\n newState.pTableParams = createPTableParams(state, columns.value);\n\n const stateIdx = newState.stateCache.findIndex(\n (entry) => entry.sourceId === state.sourceId,\n );\n if (stateIdx !== -1) {\n newState.stateCache.splice(stateIdx, 1);\n }\n const CacheDepth = 5;\n newState.stateCache.push(state);\n newState.stateCache = newState.stateCache.slice(-CacheDepth);\n }\n\n if (!isJsonEqual(tableStateNormalized.value, newState)) {\n tableStateNormalized.value = newState;\n }\n },\n });\n\n const gridState = computed<PlDataTableGridStateCore>({\n get: () => tableState.value.gridState,\n set: (gridState) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n gridState,\n };\n }\n },\n });\n\n const sheetsState = computed<PlDataTableSheetState[]>({\n get: () => tableState.value.sheetsState,\n set: (sheetsState) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n sheetsState,\n };\n }\n },\n });\n\n // --- User filters (editable by user) ---\n const filtersState = computed<PlDataTableFiltersWithMeta>({\n get: () => {\n const raw = tableState.value.filtersState;\n return isNil(raw) ? getEmptyGroupWithMeta() : normalizeFiltersState(raw);\n },\n set: (filtersState: PlDataTableFiltersWithMeta) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n filtersState,\n };\n }\n },\n });\n\n // --- Default filters (from model, separate list) ---\n const defaultFiltersState = computed<null | PlDataTableFiltersWithMeta>({\n get: () => {\n const raw = tableState.value.defaultFiltersState;\n if (!isNil(raw)) {\n return normalizeFiltersState(raw);\n }\n if (!isNil(defaultFilters.value)) {\n return annotateFiltersWithIds(normalizeFiltersState(defaultFilters.value));\n }\n return null;\n },\n set: (defaultFiltersState: null | PlDataTableFiltersWithMeta) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n defaultFiltersState,\n };\n }\n },\n });\n\n function resetDefaultFilters(): void {\n defaultFiltersState.value = isNil(defaultFilters.value)\n ? null\n : annotateFiltersWithIds(normalizeFiltersState(defaultFilters.value));\n }\n\n const searchString = computed<string>({\n get: () => tableState.value.searchString ?? \"\",\n set: (searchString: string) => {\n const oldState = tableState.value;\n if (oldState.sourceId) {\n tableState.value = {\n ...oldState,\n searchString,\n };\n }\n },\n });\n\n return {\n gridState,\n sheetsState,\n searchString,\n filtersState,\n defaultFiltersState,\n resetDefaultFilters,\n };\n}\n\n// --- Types ---\n\ntype PlDataTableStateV2CacheEntryNullable =\n | PlDataTableStateV2CacheEntry\n | {\n sourceId: null;\n gridState: Record<string, never>;\n sheetsState: [];\n filtersState: null;\n defaultFiltersState: null;\n searchString?: string;\n };\n\ntype FilterNode = FilterSpec<PlDataTableFilterSpecLeaf>;\ntype AnnotatedFilterSpec = FilterSpec<PlDataTableFilterSpecLeaf, PlDataTableFilterMeta>;\n\n// --- Core ---\n\nfunction createPTableParams(\n state: PlDataTableStateV2CacheEntry,\n filterableColumns: PTableColumnSpec[],\n): PTableParamsV2 {\n // User filters: sheets + user filter state + search\n const searchNode = createSearchFilterNode(filterableColumns, state.searchString);\n const unsuppressedUserFilters = isNil(state.filtersState)\n ? null\n : stripSuppressedFilters(state.filtersState);\n const userParts = [\n ...convertPartitionFiltersToFilterSpec(state.sheetsState),\n ...(isNil(unsuppressedUserFilters) ? [] : [unsuppressedUserFilters]),\n ...(isNil(searchNode) ? [] : [searchNode]),\n ];\n const filters: null | PlDataTableFilters = distillFilterSpec(\n userParts.length === 0\n ? null\n : userParts.length === 1\n ? userParts[0]\n : { type: \"and\", filters: userParts },\n );\n const unsuppressedDefaultFilters = isNil(state.defaultFiltersState)\n ? null\n : stripSuppressedFilters(state.defaultFiltersState);\n const defaultFilters: null | PlDataTableFilters = isNil(unsuppressedDefaultFilters)\n ? null\n : // If all filters are suppressed, we should pass an empty filter group instead of null to prevent fallback to defaults in the model\n (distillFilterSpec(unsuppressedDefaultFilters) ?? getEmptyGroup());\n\n return {\n sourceId: state.sourceId,\n hiddenColIds: getHiddenColIds(state.gridState.columnVisibility),\n sorting: convertAgSortingToPTableSorting(state.gridState.sort),\n filters,\n defaultFilters,\n };\n}\n\n/**\n * Normalizes raw filter state into a valid root filter structure.\n * Valid structure is Root(Group, Group, ...) — double nesting required:\n * root is and/or group, each child is also and/or group containing leaf filters.\n * - null/undefined/invalid → empty root\n * - Leaf node → Root(Group(leaf))\n * - Group with leaf children → Root(Group(leaves...))\n * - Group with group children → as-is\n */\nfunction normalizeFiltersState(raw: FilterNode) {\n // Leaf node → wrap in double nesting: Root(Group(leaf))\n if (raw.type !== \"and\" && raw.type !== \"or\" && raw.type !== \"not\") {\n if (\"type\" in raw && !isNil(raw.type)) {\n return {\n id: randomInt(),\n type: \"and\" as const,\n isExpanded: true,\n filters: [\n {\n id: randomInt(),\n type: \"and\" as const,\n isExpanded: true,\n filters: [raw as AnnotatedFilterSpec],\n } as AnnotatedFilterSpec,\n ],\n };\n }\n return getEmptyGroupWithMeta();\n }\n\n // Already a group — ensure children are also groups (double nesting)\n if ((raw.type === \"and\" || raw.type === \"or\") && \"filters\" in raw && Array.isArray(raw.filters)) {\n const allChildrenAreGroups = raw.filters.every(\n (f: FilterNode) => f.type === \"and\" || f.type === \"or\" || f.type === \"not\",\n );\n if (allChildrenAreGroups) {\n return raw as PlDataTableFiltersWithMeta;\n }\n // Children are leaves — wrap them in a single group\n return {\n id: randomInt(),\n type: raw.type as \"and\" | \"or\",\n isExpanded: true,\n filters: [\n {\n id: randomInt(),\n type: raw.type as \"and\" | \"or\",\n isExpanded: true,\n filters: raw.filters as AnnotatedFilterSpec[],\n } as AnnotatedFilterSpec,\n ],\n };\n }\n\n return getEmptyGroupWithMeta();\n}\n\nfunction getEmptyGroup(): PlDataTableFilters {\n return {\n type: \"and\" as const,\n filters: [],\n };\n}\nfunction getEmptyGroupWithMeta(): PlDataTableFiltersWithMeta {\n return {\n ...getEmptyGroup(),\n id: randomInt(),\n isExpanded: true,\n } as PlDataTableFiltersWithMeta;\n}\n\n/**\n * Recursively removes nodes where isSuppressed === true from a PlDataTableFiltersWithMeta tree.\n */\nfunction stripSuppressedFilters(node: PlDataTableFiltersWithMeta): PlDataTableFiltersWithMeta {\n return {\n ...node,\n filters: node.filters\n .filter((child) => !(\"isSuppressed\" in child && child.isSuppressed === true))\n .map((child) =>\n \"filters\" in child && (child.type === \"and\" || child.type === \"or\")\n ? stripSuppressedFilters(child as PlDataTableFiltersWithMeta)\n : child,\n ),\n };\n}\n\nfunction createSearchFilterNode(\n columns: PTableColumnSpec[],\n search: null | undefined | string,\n): null | FilterSpec<FilterSpecLeaf<PTableColumnId>> {\n const trimmed = search?.trim();\n if (isNil(trimmed) || trimmed.length === 0) return null;\n\n const parts: FilterSpec<FilterSpecLeaf<PTableColumnId>>[] = [];\n const numericValue = Number(trimmed);\n const isValidNumber = trimmed.length > 0 && !isNaN(numericValue) && isFinite(numericValue);\n\n for (const col of columns) {\n const column = getPTableColumnId(col);\n const spec = col.spec;\n\n if (isStringValueType(spec)) {\n parts.push({ type: \"patternEquals\", column, value: trimmed });\n }\n\n if (isNumericValueType(spec) && isValidNumber) {\n parts.push({ type: \"equal\", column, x: numericValue });\n }\n }\n\n if (parts.length === 0) return null;\n\n return { type: \"or\", filters: parts };\n}\n\n// --- Helpers ---\n\n/**\n * Recursively ensures every node in a filter tree has an `id` field.\n * Does not set `source` meta — defaults are now a separate list.\n */\nfunction annotateFiltersWithIds(\n filters: PlDataTableFilters | PlDataTableFiltersWithMeta,\n): PlDataTableFiltersWithMeta {\n return annotateNodeWithIds(filters) as PlDataTableFiltersWithMeta;\n}\n\nfunction annotateNodeWithIds(\n node: FilterNode | PlDataTableFilters | PlDataTableFiltersWithMeta,\n): AnnotatedFilterSpec {\n switch (node.type) {\n case \"and\":\n return {\n id: getField(node, \"id\") ?? randomInt(),\n isExpanded: getField(node, \"isExpanded\") ?? true,\n type: \"and\" as const,\n filters: node.filters.map((child) => annotateNodeWithIds(child)),\n };\n case \"or\":\n return {\n id: getField(node, \"id\") ?? randomInt(),\n isExpanded: getField(node, \"isExpanded\") ?? true,\n type: \"or\" as const,\n filters: node.filters.map((child) => annotateNodeWithIds(child)),\n };\n case \"not\":\n return {\n id: randomInt(),\n isExpanded: true,\n type: \"not\" as const,\n filter: annotateNodeWithIds(node.filter),\n };\n default:\n return { ...node, id: getField(node, \"id\") ?? randomInt() } as AnnotatedFilterSpec;\n }\n}\n\n// --- Utilities ---\n\nfunction convertPartitionFiltersToFilterSpec(\n sheetsState: PlDataTableSheetState[],\n): FilterSpec<FilterSpecLeaf<PTableColumnId>>[] {\n return sheetsState.map((s) => {\n const column: PTableColumnId = { type: \"axis\", id: s.axisId };\n return typeof s.value === \"number\"\n ? { type: \"equal\" as const, column, x: s.value }\n : { type: \"patternEquals\" as const, column, value: s.value };\n });\n}\n\n/**\n * AG Grid omits `sort` from its state while nothing is sorted, so the absent\n * state must stay distinguishable from an explicitly emptied sort model: the\n * model falls back to the block's default sorting on `null` only, and treats\n * `[]` as \"user cleared the sorting\" (see `resolveSorting` in\n * `createPlDataTableV3`). `normalizeSort` in `PlAgDataTableV2.vue` turns the\n * absent state into `{ sortModel: [] }` once an explicit one has been seen.\n */\nexport function convertAgSortingToPTableSorting(\n state: PlDataTableGridStateCore[\"sort\"],\n): PTableSorting[] | null {\n if (isNil(state)) return null;\n return state.sortModel.map((item) => ({\n column: parseJson<PTableColumnId>(item.colId),\n ascending: item.sort === \"asc\",\n naAndAbsentAreLeastValues: item.sort === \"asc\",\n }));\n}\n\nfunction getHiddenColIds(\n state: PlDataTableGridStateCore[\"columnVisibility\"],\n): PTableColumnId[] | null {\n return state?.hiddenColIds?.map((json) => parseJson<PTableColumnId>(json)) ?? null;\n}\n\nfunction makeDefaultState(): PlDataTableStateV2CacheEntryNullable {\n return {\n sourceId: null,\n gridState: {},\n sheetsState: [],\n filtersState: null,\n defaultFiltersState: null,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-state-v2.test.d.ts","sourceRoot":"","sources":["../../../../src/components/PlAgDataTable/sources/table-state-v2.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,
|
|
1
|
+
{"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,QAUb,CARM,EAAA,SAAA,GAAA,EADR,EASE,GAAA;;IAPC,MAAM,EAAA;IACN,kBAAgB;IAChB,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,SAAS,EAAM;IACf,uBAAqB,EAAM;IAC3B,oBAAoB,EAAM;IAC1B,6BAA6B,EAAM"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/ui-vue",
|
|
3
|
-
"version": "1.82.
|
|
3
|
+
"version": "1.82.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"vue": "3.5.24",
|
|
28
28
|
"zod": "~3.25.76",
|
|
29
29
|
"@milaboratories/columns-collection-driver": "0.2.4",
|
|
30
|
-
"@milaboratories/pf-spec-driver": "1.5.1",
|
|
31
30
|
"@milaboratories/pl-model-common": "1.48.0",
|
|
31
|
+
"@milaboratories/uikit": "2.15.25",
|
|
32
32
|
"@platforma-sdk/model": "1.82.0",
|
|
33
|
-
"@milaboratories/
|
|
33
|
+
"@milaboratories/pf-spec-driver": "1.5.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@faker-js/faker": "^9.2.0",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"typescript": "~5.9.3",
|
|
47
47
|
"vite": "^8.0.6",
|
|
48
48
|
"vitest": "^4.1.3",
|
|
49
|
-
"@milaboratories/build-configs": "2.0.0",
|
|
50
49
|
"@milaboratories/helpers": "1.14.5",
|
|
50
|
+
"@milaboratories/ts-configs": "1.4.0",
|
|
51
51
|
"@milaboratories/ts-builder": "1.7.0",
|
|
52
|
-
"@milaboratories/
|
|
52
|
+
"@milaboratories/build-configs": "2.0.0"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"dev": "ts-builder serve --target browser-lib",
|
|
@@ -129,7 +129,7 @@ const { gridApi, gridOptions } = useGrid({
|
|
|
129
129
|
let isReloading = false;
|
|
130
130
|
gridOptions.value.onGridPreDestroyed = (event) => {
|
|
131
131
|
if (!isReloading) {
|
|
132
|
-
gridOptions.value.initialState = gridState.value =
|
|
132
|
+
gridOptions.value.initialState = gridState.value = normalizeGridState(
|
|
133
133
|
makePartialState(event.api.getState()),
|
|
134
134
|
gridState.value,
|
|
135
135
|
event.api,
|
|
@@ -142,7 +142,7 @@ gridOptions.value.onRowDoubleClicked = (event) => {
|
|
|
142
142
|
if (event.data && event.data.axesKey) emit("rowDoubleClicked", event.data.axesKey);
|
|
143
143
|
};
|
|
144
144
|
gridOptions.value.onStateUpdated = (event) => {
|
|
145
|
-
const partialState =
|
|
145
|
+
const partialState = normalizeGridState(
|
|
146
146
|
makePartialState(event.state),
|
|
147
147
|
gridState.value,
|
|
148
148
|
event.api,
|
|
@@ -213,6 +213,42 @@ function makePartialState(state: GridState): PlDataTableGridStateCore {
|
|
|
213
213
|
};
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
// AG Grid omits parts of its state that carry no information — columnVisibility
|
|
217
|
+
// when every column is visible, sort when nothing is sorted. The model needs
|
|
218
|
+
// "no state yet" (fall back to the block's defaults) to stay distinguishable
|
|
219
|
+
// from "user explicitly cleared it" (store []), so both are normalized against
|
|
220
|
+
// the previous state before the state is persisted.
|
|
221
|
+
function normalizeGridState(
|
|
222
|
+
partialState: PlDataTableGridStateCore,
|
|
223
|
+
prevState: PlDataTableGridStateCore,
|
|
224
|
+
api: GridApi<PlAgDataTableV2Row>,
|
|
225
|
+
columnsMeta: PlDataTableColumnsMeta | undefined,
|
|
226
|
+
): PlDataTableGridStateCore {
|
|
227
|
+
return normalizeSort(
|
|
228
|
+
normalizeColumnVisibility(partialState, prevState, api, columnsMeta),
|
|
229
|
+
prevState,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// AG Grid returns sort: undefined when no column is sorted. Left as-is that
|
|
234
|
+
// erases the block's default sorting the moment any unrelated grid state is
|
|
235
|
+
// persisted, so the undefined is only turned into an explicit empty sort model
|
|
236
|
+
// once the user has actually sorted something before.
|
|
237
|
+
function normalizeSort(
|
|
238
|
+
partialState: PlDataTableGridStateCore,
|
|
239
|
+
prevState: PlDataTableGridStateCore,
|
|
240
|
+
): PlDataTableGridStateCore {
|
|
241
|
+
if (partialState.sort !== undefined) return partialState;
|
|
242
|
+
|
|
243
|
+
if (prevState.sort !== undefined) {
|
|
244
|
+
// Had an explicit sort model before → user cleared the sorting → store [].
|
|
245
|
+
return { ...partialState, sort: { sortModel: [] } };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Never sorted → leave undefined so the model applies its default sorting.
|
|
249
|
+
return partialState;
|
|
250
|
+
}
|
|
251
|
+
|
|
216
252
|
// AG Grid returns columnVisibility: undefined when all columns are visible.
|
|
217
253
|
// We need to distinguish "no state yet" (use isColumnOptional defaults) from
|
|
218
254
|
// "user explicitly showed all columns" (store []). This function normalizes
|
|
@@ -264,11 +300,14 @@ function getDefaultHiddenColIds(
|
|
|
264
300
|
.map((col) => col.getColId() as PlTableColumnIdJson);
|
|
265
301
|
}
|
|
266
302
|
|
|
267
|
-
// Normalize
|
|
303
|
+
// Normalize for comparison: an absent and an empty columnVisibility / sort mean
|
|
304
|
+
// the same thing to AG Grid, and must not count as a state change to reload on.
|
|
268
305
|
function stateForReloadCompare(state: PlDataTableGridStateCore): PlDataTableGridStateCore {
|
|
269
306
|
const cv = state.columnVisibility;
|
|
270
307
|
const normalizedCv = !cv || cv.hiddenColIds.length === 0 ? undefined : state.columnVisibility;
|
|
271
|
-
|
|
308
|
+
const sort = state.sort;
|
|
309
|
+
const normalizedSort = !sort || sort.sortModel.length === 0 ? undefined : sort;
|
|
310
|
+
return { ...state, columnVisibility: normalizedCv, sort: normalizedSort };
|
|
272
311
|
}
|
|
273
312
|
|
|
274
313
|
// Reload AgGrid when new state arrives from server
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
|
|
5
|
+
// The module pulls in uikit for `computedCached`; stub it so the test does not
|
|
6
|
+
// drag the whole component library (and its DOM-time side effects) in.
|
|
7
|
+
vi.mock("@milaboratories/uikit", () => ({
|
|
8
|
+
computedCached: computed,
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const { convertAgSortingToPTableSorting } = await import("./table-state-v2");
|
|
12
|
+
|
|
13
|
+
describe("convertAgSortingToPTableSorting", () => {
|
|
14
|
+
it("reports an absent sort state as untouched, so the model keeps its default sorting", () => {
|
|
15
|
+
expect(convertAgSortingToPTableSorting(undefined)).toBeNull();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("reports an empty sort model as explicitly cleared, which suppresses the default", () => {
|
|
19
|
+
expect(convertAgSortingToPTableSorting({ sortModel: [] })).toEqual([]);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("converts a sort model, taking NA/absent as least values only when ascending", () => {
|
|
23
|
+
const column = { type: "column", id: "colId" };
|
|
24
|
+
const colId = JSON.stringify(column) as never;
|
|
25
|
+
expect(
|
|
26
|
+
convertAgSortingToPTableSorting({
|
|
27
|
+
sortModel: [
|
|
28
|
+
{ colId, sort: "asc" },
|
|
29
|
+
{ colId, sort: "desc" },
|
|
30
|
+
],
|
|
31
|
+
}),
|
|
32
|
+
).toEqual([
|
|
33
|
+
{ column, ascending: true, naAndAbsentAreLeastValues: true },
|
|
34
|
+
{ column, ascending: false, naAndAbsentAreLeastValues: false },
|
|
35
|
+
]);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -413,14 +413,23 @@ function convertPartitionFiltersToFilterSpec(
|
|
|
413
413
|
});
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
416
|
+
/**
|
|
417
|
+
* AG Grid omits `sort` from its state while nothing is sorted, so the absent
|
|
418
|
+
* state must stay distinguishable from an explicitly emptied sort model: the
|
|
419
|
+
* model falls back to the block's default sorting on `null` only, and treats
|
|
420
|
+
* `[]` as "user cleared the sorting" (see `resolveSorting` in
|
|
421
|
+
* `createPlDataTableV3`). `normalizeSort` in `PlAgDataTableV2.vue` turns the
|
|
422
|
+
* absent state into `{ sortModel: [] }` once an explicit one has been seen.
|
|
423
|
+
*/
|
|
424
|
+
export function convertAgSortingToPTableSorting(
|
|
425
|
+
state: PlDataTableGridStateCore["sort"],
|
|
426
|
+
): PTableSorting[] | null {
|
|
427
|
+
if (isNil(state)) return null;
|
|
428
|
+
return state.sortModel.map((item) => ({
|
|
429
|
+
column: parseJson<PTableColumnId>(item.colId),
|
|
430
|
+
ascending: item.sort === "asc",
|
|
431
|
+
naAndAbsentAreLeastValues: item.sort === "asc",
|
|
432
|
+
}));
|
|
424
433
|
}
|
|
425
434
|
|
|
426
435
|
function getHiddenColIds(
|