@okf/ootils 1.27.0 → 1.28.1

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.
@@ -1020,6 +1020,51 @@ declare const _self_managed_buildAnnoHierarchyConfig: ({ annotationTagsCount, }:
1020
1020
  };
1021
1021
  } | null;
1022
1022
 
1023
+ /**
1024
+ * Builds a consolidated docHierarchyType config for self-managed tenants.
1025
+ *
1026
+ * Produces a single filter config that contains:
1027
+ * - commonFilters: filters present in ALL selected templates
1028
+ * - sharedAcrossMultiple: groups of filters shared by 2+ (but not all) templates
1029
+ * - perDataset: each template's complete filter list + rollup configs
1030
+ * - commonDocumentFilters: Author, Published Date, etc.
1031
+ *
1032
+ * This is consumed by DocHierarchyFilter on the frontend to render the
1033
+ * drilldown-based document filter UI.
1034
+ */
1035
+ declare const _self_managed_buildDocHierarchyConfig: ({ combinedDocumentBlocks, docRollupBlocks, selectedTpls, allTpls, commonDocumentFilters, flatDocFilters, }: {
1036
+ combinedDocumentBlocks: any[];
1037
+ docRollupBlocks: any[];
1038
+ selectedTpls: any[];
1039
+ allTpls: any[];
1040
+ commonDocumentFilters: any[];
1041
+ flatDocFilters?: boolean;
1042
+ }) => {
1043
+ filterId: string;
1044
+ display: string;
1045
+ filterKey: string;
1046
+ source: {
1047
+ filterType: string;
1048
+ flatDocFilters: boolean;
1049
+ commonFilters: any[];
1050
+ sharedAcrossMultiple: {
1051
+ contentTypes: any;
1052
+ display: any;
1053
+ filters: any[];
1054
+ }[];
1055
+ commonDocumentFilters: any[];
1056
+ perDataset: {
1057
+ contentType: any;
1058
+ display: any;
1059
+ filters: any[];
1060
+ rollups: any[];
1061
+ }[];
1062
+ };
1063
+ target: {
1064
+ filterType: string;
1065
+ };
1066
+ } | null;
1067
+
1023
1068
  /**
1024
1069
  * TEMP_removeDuplicateFilters - Removes duplicate rollup and tag-type filters
1025
1070
  *
@@ -1114,6 +1159,37 @@ declare const autoGenFilterConfigsFromTpl: ({ selectedTpls, allTpls, filterScope
1114
1159
  sectionId: string;
1115
1160
  configs: any[];
1116
1161
  }[];
1162
+ } | {
1163
+ sectionId: string;
1164
+ configs: {
1165
+ sectionId: string;
1166
+ configs: {
1167
+ filterId: string;
1168
+ display: string;
1169
+ filterKey: string;
1170
+ source: {
1171
+ filterType: string;
1172
+ flatDocFilters: boolean;
1173
+ commonFilters: any[];
1174
+ sharedAcrossMultiple: {
1175
+ contentTypes: any;
1176
+ display: any;
1177
+ filters: any[];
1178
+ }[];
1179
+ commonDocumentFilters: any[];
1180
+ perDataset: {
1181
+ contentType: any;
1182
+ display: any;
1183
+ filters: any[];
1184
+ rollups: any[];
1185
+ }[];
1186
+ };
1187
+ target: {
1188
+ filterType: string;
1189
+ };
1190
+ }[];
1191
+ }[];
1192
+ sectionTitle?: undefined;
1117
1193
  } | {
1118
1194
  sectionId: string;
1119
1195
  sectionTitle: string;
@@ -1184,11 +1260,30 @@ declare const UI_CONTENT: {
1184
1260
  };
1185
1261
  };
1186
1262
 
1187
- declare const genCleanCamelCaseId: (id: string) => string;
1263
+ interface GenCleanCamelCaseIdOptions {
1264
+ /** Strip all non-alphanumeric chars (A-Z, a-z, 0-9 only). Default: false */
1265
+ stripNonAlphanumeric?: boolean;
1266
+ /** Truncate result to this max length. Default: no limit */
1267
+ maxLength?: number;
1268
+ }
1269
+ declare const genCleanCamelCaseId: (id: string, options?: GenCleanCamelCaseIdOptions) => string;
1270
+
1271
+ /**
1272
+ * Generates a clean, deterministic contentType ID from text.
1273
+ * Wraps genCleanCamelCaseId with stripNonAlphanumeric + maxLength 40.
1274
+ *
1275
+ * Idempotent: running twice produces the same output.
1276
+ *
1277
+ * @example
1278
+ * genCleanContentTypeId("My Articles!") => "myArticles"
1279
+ * genCleanContentTypeId("myArticles") => "myArticles" (idempotent)
1280
+ * genCleanContentTypeId("123 Test") => "a123Test"
1281
+ */
1282
+ declare const genCleanContentTypeId: (text: string) => string;
1188
1283
 
1189
1284
  /**
1190
1285
  * Generates a clean, short, unique ID from text input.
1191
- * Used for both contentType IDs and block valuePaths.
1286
+ * Used for block valuePaths in templates.
1192
1287
  *
1193
1288
  * 1. Strips all characters except A-Z, a-z, 0-9
1194
1289
  * 2. Lowercases the result
@@ -1196,15 +1291,18 @@ declare const genCleanCamelCaseId: (id: string) => string;
1196
1291
  * 4. Truncates to maxLength (default 10)
1197
1292
  * 5. Appends _{random id} (default 4 chars)
1198
1293
  *
1294
+ * Idempotent: if input already matches the output pattern
1295
+ * (lowercase alphanumeric + _hash suffix), returns as-is.
1296
+ *
1199
1297
  * @param text - The input text to convert
1200
- * @param maxLength - Max characters before the random suffix (default 10, use 20 for contentType)
1298
+ * @param maxLength - Max characters before the random suffix (default 10)
1201
1299
  * @param shortIdLength - Length of the random suffix (default 4)
1202
1300
  *
1203
1301
  * @example
1204
- * genCleanIdForContentTypeAndValuePaths("Author Name") => "authorname_x7k2"
1205
- * genCleanIdForContentTypeAndValuePaths("My Articles!", 20) => "myarticles_m3p1"
1206
- * genCleanIdForContentTypeAndValuePaths("123 Test") => "a123test_ab4d"
1302
+ * genCleanValuePath("Author Name") => "authorname_x7k2"
1303
+ * genCleanValuePath("authorname_x7k2") => "authorname_x7k2" (idempotent)
1304
+ * genCleanValuePath("123 Test") => "a123test_ab4d"
1207
1305
  */
1208
- declare const genCleanIdForContentTypeAndValuePaths: (text: string, maxLength?: number, shortIdLength?: number) => string;
1306
+ declare const genCleanValuePath: (text: string) => string;
1209
1307
 
1210
- export { BASE_BULLMQ_CONFIG, FILTER_IDS, TEMP_removeDuplicateFilters, UI_CONTENT, _self_managed_buildAnnoHierarchyConfig, _self_managed_getFixedAnnoRollupBlocks, _self_managed_getFixedAnnoTagBlock, autoGenFilterConfigsFromTpl, buildFilterConfigurations, compareAndGroupBlocks, deleteVal, extractAllBlocksFromTpl, extractAndOrganizeBlocks, genCleanCamelCaseId, genCleanIdForContentTypeAndValuePaths, genTagId, generateFilterKey, getFilterKeyForBlock, getPlatformContextContent, getRollupPossibilities, getRoutePathToEditContent, getRoutePathToModerateContent, getRoutePathToPublishedContent, getVal, mergeAnnoDataIntoAnnotationsTags, parseSpecialConfigSyntax, processAuthorAndCommonFilters, _recursExtractBlocks as recursivelyExtractBlocks, segrigateDocs, setVal, toArray };
1308
+ export { BASE_BULLMQ_CONFIG, FILTER_IDS, TEMP_removeDuplicateFilters, UI_CONTENT, _self_managed_buildAnnoHierarchyConfig, _self_managed_buildDocHierarchyConfig, _self_managed_getFixedAnnoRollupBlocks, _self_managed_getFixedAnnoTagBlock, autoGenFilterConfigsFromTpl, buildFilterConfigurations, compareAndGroupBlocks, deleteVal, extractAllBlocksFromTpl, extractAndOrganizeBlocks, genCleanCamelCaseId, genCleanContentTypeId, genCleanValuePath, genTagId, generateFilterKey, getFilterKeyForBlock, getPlatformContextContent, getRollupPossibilities, getRoutePathToEditContent, getRoutePathToModerateContent, getRoutePathToPublishedContent, getVal, mergeAnnoDataIntoAnnotationsTags, parseSpecialConfigSyntax, processAuthorAndCommonFilters, _recursExtractBlocks as recursivelyExtractBlocks, segrigateDocs, setVal, toArray };
package/dist/universal.js CHANGED
@@ -25,6 +25,7 @@ __export(universal_exports, {
25
25
  TEMP_removeDuplicateFilters: () => TEMP_removeDuplicateFilters,
26
26
  UI_CONTENT: () => UI_CONTENT,
27
27
  _self_managed_buildAnnoHierarchyConfig: () => _self_managed_buildAnnoHierarchyConfig,
28
+ _self_managed_buildDocHierarchyConfig: () => _self_managed_buildDocHierarchyConfig,
28
29
  _self_managed_getFixedAnnoRollupBlocks: () => _self_managed_getFixedAnnoRollupBlocks,
29
30
  _self_managed_getFixedAnnoTagBlock: () => _self_managed_getFixedAnnoTagBlock,
30
31
  autoGenFilterConfigsFromTpl: () => autoGenFilterConfigsFromTpl,
@@ -34,7 +35,8 @@ __export(universal_exports, {
34
35
  extractAllBlocksFromTpl: () => extractAllBlocksFromTpl,
35
36
  extractAndOrganizeBlocks: () => extractAndOrganizeBlocks,
36
37
  genCleanCamelCaseId: () => genCleanCamelCaseId,
37
- genCleanIdForContentTypeAndValuePaths: () => genCleanIdForContentTypeAndValuePaths,
38
+ genCleanContentTypeId: () => genCleanContentTypeId,
39
+ genCleanValuePath: () => genCleanValuePath,
38
40
  genTagId: () => genTagId,
39
41
  generateFilterKey: () => generateFilterKey,
40
42
  getFilterKeyForBlock: () => getFilterKeyForBlock,
@@ -1070,6 +1072,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1070
1072
  filterKey,
1071
1073
  contentType: element.contentType,
1072
1074
  path: element.valuePath,
1075
+ ...element.comp && { comp: element.comp },
1073
1076
  source: {
1074
1077
  filterType: "tplType",
1075
1078
  contentType: element.contentType,
@@ -1095,6 +1098,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1095
1098
  filterKey: valuePathFilterKey,
1096
1099
  contentType: element.contentType,
1097
1100
  path: element.valuePath,
1101
+ ...element.comp && { comp: element.comp },
1098
1102
  source: {
1099
1103
  filterType: "tplType",
1100
1104
  contentType: element.contentType,
@@ -1120,6 +1124,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1120
1124
  filterKey: dateFilterKey,
1121
1125
  contentType: element.contentType,
1122
1126
  path: element.valuePath,
1127
+ ...element.comp && { comp: element.comp },
1123
1128
  source: { filterType: "dateRangeType" },
1124
1129
  target: { filterType: "dateRangeType", valuePath: element.valuePath }
1125
1130
  };
@@ -1137,6 +1142,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1137
1142
  filterKey: numberFilterKey,
1138
1143
  contentType: element.contentType,
1139
1144
  path: element.valuePath,
1145
+ ...element.comp && { comp: element.comp },
1140
1146
  source: { filterType: "numberRangeType", valuePath: element.valuePath },
1141
1147
  target: { filterType: "numberRangeType", valuePath: element.valuePath }
1142
1148
  };
@@ -1257,6 +1263,7 @@ var buildFilterConfigurations = ({ groups, type, selectedTpls, allTpls, isRollup
1257
1263
  filterKey: tagFilterKey,
1258
1264
  contentType: element.tagType,
1259
1265
  path: `tags.${element.tagType}`,
1266
+ ...element.comp && { comp: element.comp },
1260
1267
  source: allProfileTpls.some(
1261
1268
  (tpl) => tpl.kp_content_type === element.tagType
1262
1269
  ) ? {
@@ -1398,6 +1405,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1398
1405
  contentType: tpl.kp_content_type,
1399
1406
  blocks: allBlocks.filter((block) => block.valuePath.startsWith("tags.")).map((block) => ({
1400
1407
  tagType: block.props.tagType,
1408
+ comp: block.comp,
1401
1409
  filterType: "tagType"
1402
1410
  }))
1403
1411
  };
@@ -1425,6 +1433,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1425
1433
  value: block.valuePath,
1426
1434
  saveValueAsString: block.props?.saveValueAsString,
1427
1435
  contentType: tpl.kp_content_type,
1436
+ comp: block.comp,
1428
1437
  filterType: "valuePathType"
1429
1438
  }))
1430
1439
  };
@@ -1439,6 +1448,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1439
1448
  value: block.valuePath,
1440
1449
  saveValueAsString: block.props?.saveValueAsString,
1441
1450
  contentType: tpl.kp_content_type,
1451
+ comp: block.comp,
1442
1452
  block,
1443
1453
  filterType: "split_valuePathType"
1444
1454
  }))
@@ -1453,6 +1463,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1453
1463
  display: block.props?.shortLabel || block.props?.label || block.valuePath,
1454
1464
  value: block.valuePath,
1455
1465
  contentType: tpl.kp_content_type,
1466
+ comp: block.comp,
1456
1467
  filterType: "dateRangeType"
1457
1468
  }))
1458
1469
  };
@@ -1466,6 +1477,7 @@ var extractAndOrganizeBlocks = (selectedTpls, allTpls) => {
1466
1477
  display: block.props?.shortLabel || block.props?.label || block.valuePath,
1467
1478
  value: block.valuePath,
1468
1479
  contentType: tpl.kp_content_type,
1480
+ comp: block.comp,
1469
1481
  filterType: "numberRangeType"
1470
1482
  }))
1471
1483
  };
@@ -1712,6 +1724,240 @@ var _self_managed_buildAnnoHierarchyConfig = ({
1712
1724
  };
1713
1725
  };
1714
1726
 
1727
+ // src/utils/autoGenFilterConfigsFromTpl/utils/buildTagTypeParentMap.ts
1728
+ var buildTagTypeParentMap = (tagTypesInGroup, allTpls) => {
1729
+ const tagTypeSet = new Set(tagTypesInGroup);
1730
+ const parentMap = /* @__PURE__ */ new Map();
1731
+ for (const tagType of tagTypesInGroup) {
1732
+ const tpl = allTpls.find((t) => t.kp_content_type === tagType);
1733
+ if (!tpl) continue;
1734
+ const blocks = extractAllBlocksFromTpl({ tpl });
1735
+ const tagBlocks = blocks.filter(
1736
+ (block) => block.valuePath?.startsWith("tags.") && block.props?.tagType
1737
+ );
1738
+ for (const block of tagBlocks) {
1739
+ const referencedTagType = block.props.tagType;
1740
+ if (tagTypeSet.has(referencedTagType) && referencedTagType !== tagType) {
1741
+ parentMap.set(tagType, referencedTagType);
1742
+ break;
1743
+ }
1744
+ }
1745
+ }
1746
+ for (const child of parentMap.keys()) {
1747
+ const visited = /* @__PURE__ */ new Set();
1748
+ let current = child;
1749
+ while (current && parentMap.has(current)) {
1750
+ if (visited.has(current)) {
1751
+ parentMap.delete(current);
1752
+ break;
1753
+ }
1754
+ visited.add(current);
1755
+ current = parentMap.get(current);
1756
+ }
1757
+ }
1758
+ return parentMap;
1759
+ };
1760
+ var attachParentFields = (filters, allTpls) => {
1761
+ const tagTypeFilters = filters.filter(
1762
+ (f) => f.source?.filterType === "tagType" && f.source?.tagType
1763
+ );
1764
+ if (tagTypeFilters.length === 0) return filters;
1765
+ const tagTypesInGroup = tagTypeFilters.map((f) => f.source.tagType);
1766
+ const parentMap = buildTagTypeParentMap(tagTypesInGroup, allTpls);
1767
+ if (parentMap.size === 0) return filters;
1768
+ const tagTypeToFilterId = /* @__PURE__ */ new Map();
1769
+ for (const f of tagTypeFilters) {
1770
+ tagTypeToFilterId.set(f.source.tagType, f.filterId);
1771
+ }
1772
+ return filters.map((f) => {
1773
+ if (f.source?.filterType !== "tagType" || !f.source?.tagType) return f;
1774
+ const parentTagType = parentMap.get(f.source.tagType);
1775
+ if (!parentTagType) return f;
1776
+ const parentFilterId = tagTypeToFilterId.get(parentTagType);
1777
+ if (!parentFilterId) return f;
1778
+ return { ...f, parentFilterId };
1779
+ });
1780
+ };
1781
+ var sortFiltersHierarchically = (filters) => {
1782
+ if (filters.length <= 1) return filters;
1783
+ const hasHierarchy = filters.some((f) => f.parentFilterId);
1784
+ if (!hasHierarchy) return filters;
1785
+ const childrenOf = /* @__PURE__ */ new Map();
1786
+ const roots = [];
1787
+ for (const f of filters) {
1788
+ if (!f.parentFilterId) {
1789
+ roots.push(f);
1790
+ } else {
1791
+ const siblings = childrenOf.get(f.parentFilterId) || [];
1792
+ siblings.push(f);
1793
+ childrenOf.set(f.parentFilterId, siblings);
1794
+ }
1795
+ }
1796
+ const sorted = [];
1797
+ const visited = /* @__PURE__ */ new Set();
1798
+ const visit = (filter) => {
1799
+ if (visited.has(filter.filterId)) return;
1800
+ visited.add(filter.filterId);
1801
+ sorted.push(filter);
1802
+ const children = childrenOf.get(filter.filterId) || [];
1803
+ for (const child of children) {
1804
+ visit(child);
1805
+ }
1806
+ };
1807
+ for (const root of roots) {
1808
+ visit(root);
1809
+ }
1810
+ for (const f of filters) {
1811
+ if (!visited.has(f.filterId)) {
1812
+ sorted.push(f);
1813
+ }
1814
+ }
1815
+ return sorted;
1816
+ };
1817
+
1818
+ // src/utils/autoGenFilterConfigsFromTpl/utils/_self_managed_buildDocHierarchyConfig.ts
1819
+ var _self_managed_buildDocHierarchyConfig = ({
1820
+ combinedDocumentBlocks,
1821
+ docRollupBlocks,
1822
+ selectedTpls,
1823
+ allTpls,
1824
+ commonDocumentFilters,
1825
+ flatDocFilters = false
1826
+ }) => {
1827
+ const allGroups = compareAndGroupBlocks(combinedDocumentBlocks);
1828
+ const commonGroup = allGroups.find(
1829
+ (g) => g.contentTypes.length === selectedTpls.length
1830
+ );
1831
+ const commonFilterConfigs = commonGroup ? sortFiltersHierarchically(
1832
+ attachParentFields(
1833
+ buildFilterConfigurations({
1834
+ groups: [commonGroup],
1835
+ type: "tags",
1836
+ selectedTpls,
1837
+ allTpls,
1838
+ isRollup: false,
1839
+ isAnno: false
1840
+ }).flatMap((s) => s.configs),
1841
+ allTpls
1842
+ )
1843
+ ) : [];
1844
+ const multiDatasetGroups = selectedTpls.length >= 2 ? allGroups.filter(
1845
+ (g) => g.contentTypes.length > 1 && g.contentTypes.length < selectedTpls.length
1846
+ ) : [];
1847
+ const sharedAcrossMultiple = multiDatasetGroups.map((group) => {
1848
+ const groupFilterConfigs = sortFiltersHierarchically(
1849
+ attachParentFields(
1850
+ buildFilterConfigurations({
1851
+ groups: [group],
1852
+ type: "tags",
1853
+ selectedTpls,
1854
+ allTpls,
1855
+ isRollup: false,
1856
+ isAnno: false
1857
+ }).flatMap((s) => s.configs),
1858
+ allTpls
1859
+ )
1860
+ );
1861
+ const display = group.contentTypes.map((ct) => {
1862
+ const tplData = allTpls.find(
1863
+ (t) => t.kp_content_type === ct
1864
+ );
1865
+ return tplData?.general?.content?.title || ct;
1866
+ }).join(" + ");
1867
+ return {
1868
+ contentTypes: group.contentTypes,
1869
+ display,
1870
+ filters: groupFilterConfigs
1871
+ };
1872
+ }).filter((g) => g.filters.length > 0);
1873
+ const commonFilterIds = new Set(commonFilterConfigs.map((f) => f.filterId));
1874
+ const perDataset = selectedTpls.map((tpl) => {
1875
+ const tplBlocks = combinedDocumentBlocks.find(
1876
+ (b) => b.contentType === tpl.kp_content_type
1877
+ );
1878
+ const singleTplGroup = [
1879
+ {
1880
+ contentTypes: [tpl.kp_content_type],
1881
+ elements: tplBlocks?.blocks || []
1882
+ }
1883
+ ];
1884
+ const filters = buildFilterConfigurations({
1885
+ groups: singleTplGroup,
1886
+ type: "tags",
1887
+ selectedTpls: [tpl],
1888
+ allTpls,
1889
+ isRollup: false,
1890
+ isAnno: false
1891
+ }).flatMap((s) => s.configs);
1892
+ const filtersWithCommonFlag = filters.map((f) => ({
1893
+ ...f,
1894
+ isSharedFilter: commonFilterIds.has(f.filterId)
1895
+ }));
1896
+ const rollupData = docRollupBlocks?.find(
1897
+ (b) => b.contentType === tpl.kp_content_type
1898
+ );
1899
+ const rollupGroups = rollupData?.blocks?.length ? compareAndGroupBlocks([rollupData]) : [];
1900
+ const rollupConfigs = rollupGroups.length ? buildFilterConfigurations({
1901
+ groups: rollupGroups,
1902
+ type: "tags",
1903
+ selectedTpls: [tpl],
1904
+ allTpls,
1905
+ isRollup: true,
1906
+ isAnno: false
1907
+ }).flatMap((s) => s.configs) : [];
1908
+ const tplData = allTpls.find(
1909
+ (t) => t.kp_content_type === tpl.kp_content_type
1910
+ );
1911
+ const rollupSourceKeys = new Set(
1912
+ rollupConfigs.map((r) => JSON.stringify(r.source))
1913
+ );
1914
+ const dedupedFilters = filtersWithCommonFlag.filter(
1915
+ (f) => !rollupSourceKeys.has(JSON.stringify(f.source))
1916
+ );
1917
+ const combined = [...dedupedFilters, ...rollupConfigs];
1918
+ const combinedWithParents = sortFiltersHierarchically(
1919
+ attachParentFields(combined, allTpls)
1920
+ );
1921
+ const rollupFilterIds = new Set(rollupConfigs.map((r) => r.filterId));
1922
+ const filtersWithParents = combinedWithParents.filter(
1923
+ (f) => !rollupFilterIds.has(f.filterId)
1924
+ );
1925
+ const rollupsWithParents = combinedWithParents.filter(
1926
+ (f) => rollupFilterIds.has(f.filterId)
1927
+ );
1928
+ return {
1929
+ contentType: tpl.kp_content_type,
1930
+ display: tplData?.general?.content?.title || tpl.kp_content_type,
1931
+ filters: filtersWithParents,
1932
+ rollups: rollupsWithParents
1933
+ };
1934
+ });
1935
+ const filteredPerDataset = perDataset.filter(
1936
+ (d) => d.filters.length > 0 || d.rollups.length > 0
1937
+ );
1938
+ if (commonFilterConfigs.length === 0 && sharedAcrossMultiple.length === 0 && filteredPerDataset.every((d) => d.filters.length === 0)) {
1939
+ return null;
1940
+ }
1941
+ const flatCommonDocFilters = commonDocumentFilters.flatMap(
1942
+ (s) => s.configs || [s]
1943
+ );
1944
+ const shouldFlatten = flatDocFilters && selectedTpls.length === 1;
1945
+ return {
1946
+ filterId: "docHierarchy_document_filters",
1947
+ display: "Combined Content Filters",
1948
+ filterKey: "docHierarchyType::doc",
1949
+ source: {
1950
+ filterType: "docHierarchyType",
1951
+ flatDocFilters: shouldFlatten,
1952
+ commonFilters: commonFilterConfigs,
1953
+ sharedAcrossMultiple,
1954
+ commonDocumentFilters: flatCommonDocFilters,
1955
+ perDataset: filteredPerDataset
1956
+ },
1957
+ target: { filterType: "docHierarchyType" }
1958
+ };
1959
+ };
1960
+
1715
1961
  // src/utils/autoGenFilterConfigsFromTpl/utils/TEMP_removeDuplicateFilters.ts
1716
1962
  var TEMP_removeDuplicateFilters = (filterGroups) => {
1717
1963
  return filterGroups.map((group) => {
@@ -1848,7 +2094,25 @@ var autoGenFilterConfigsFromTpl = ({
1848
2094
  ...annotationRollupSections
1849
2095
  ].filter((section) => Array.isArray(section.configs) ? section.configs.length > 0 : true)
1850
2096
  };
1851
- const final_documentTagsFilterConfigs = {
2097
+ const isSMTDocFilterUI = isSelfManagedTenant && filterScopes.includes("doc");
2098
+ const final_documentTagsFilterConfigs = isSMTDocFilterUI ? (() => {
2099
+ const docHierarchyConfig = _self_managed_buildDocHierarchyConfig({
2100
+ combinedDocumentBlocks: extractedBlocks.combinedDocumentBlocks,
2101
+ docRollupBlocks: extractedBlocks.docRollupBlocks,
2102
+ selectedTpls,
2103
+ allTpls,
2104
+ commonDocumentFilters
2105
+ });
2106
+ if (!docHierarchyConfig) return { sectionId: "documentTagsSection", sectionTitle: "Document Filters", configs: [] };
2107
+ return {
2108
+ sectionId: "documentTagsSection",
2109
+ // sectionTitle: 'Document Filters',
2110
+ configs: [{
2111
+ sectionId: "self_managed_consolidated_doc_filters",
2112
+ configs: [docHierarchyConfig]
2113
+ }]
2114
+ };
2115
+ })() : {
1852
2116
  sectionId: "documentTagsSection",
1853
2117
  sectionTitle: "Document Filters",
1854
2118
  configs: [
@@ -1864,20 +2128,33 @@ var autoGenFilterConfigsFromTpl = ({
1864
2128
  };
1865
2129
 
1866
2130
  // src/utils/genCleanCamelCaseId.ts
1867
- var genCleanCamelCaseId = (id) => {
2131
+ var genCleanCamelCaseId = (id, options) => {
1868
2132
  if (!id || typeof id !== "string") return id;
1869
- const isAlreadyClean = /^\p{Ll}[\p{L}\p{N}]*$/u.test(id) || /^a\d[\p{L}\p{N}]*$/u.test(id);
1870
- if (isAlreadyClean) return id;
2133
+ const { stripNonAlphanumeric = false, maxLength } = options || {};
2134
+ const baseClean = /^\p{Ll}[\p{L}\p{N}]*$/u.test(id) || /^a\d[\p{L}\p{N}]*$/u.test(id);
2135
+ const withinMaxLength = maxLength ? id.length <= maxLength : true;
2136
+ const hasNoNonAlpha = stripNonAlphanumeric ? /^[a-zA-Z0-9]+$/.test(id) : true;
2137
+ if (baseClean && withinMaxLength && hasNoNonAlpha) return id;
1871
2138
  const words = id.split(/[^\p{L}\p{N}]+/u).filter(Boolean);
1872
2139
  if (words.length === 0) return "a";
1873
- const result = words.map((word, i) => {
2140
+ let result = words.map((word, i) => {
1874
2141
  const lower = word.toLowerCase();
1875
2142
  return i === 0 ? lower : lower.charAt(0).toUpperCase() + lower.slice(1);
1876
2143
  }).join("");
1877
- return /^\d/.test(result) ? "a" + result : result;
2144
+ if (/^\d/.test(result)) result = "a" + result;
2145
+ if (stripNonAlphanumeric) {
2146
+ result = result.replace(/[^a-zA-Z0-9]/g, "");
2147
+ }
2148
+ if (maxLength) {
2149
+ result = result.slice(0, maxLength);
2150
+ }
2151
+ return result;
1878
2152
  };
1879
2153
 
1880
- // src/utils/genCleanIdForContentTypeAndValuePaths.ts
2154
+ // src/utils/genCleanContentTypeId.ts
2155
+ var genCleanContentTypeId = (text) => genCleanCamelCaseId(text, { stripNonAlphanumeric: true, maxLength: 40 });
2156
+
2157
+ // src/utils/genCleanValuePath.ts
1881
2158
  var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
1882
2159
  function genShortId(length = 4) {
1883
2160
  let result = "";
@@ -1886,11 +2163,15 @@ function genShortId(length = 4) {
1886
2163
  }
1887
2164
  return result;
1888
2165
  }
1889
- var genCleanIdForContentTypeAndValuePaths = (text, maxLength = 10, shortIdLength = 4) => {
2166
+ var genCleanValuePath = (text) => {
2167
+ const maxLength = 10;
2168
+ const shortIdLength = 4;
1890
2169
  if (!text || typeof text !== "string") return text;
2170
+ const idempotencyPattern = new RegExp(`^[a-z][a-z0-9]*_[a-z0-9]{${shortIdLength}}$`);
2171
+ if (idempotencyPattern.test(text)) return text;
1891
2172
  let cleaned = text.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
1892
2173
  if (!cleaned) {
1893
- throw new Error(`[genCleanIdForContentTypeAndValuePaths] Input "${text}" contains no alphanumeric characters`);
2174
+ throw new Error(`[genCleanValuePath] Input "${text}" contains no alphanumeric characters`);
1894
2175
  }
1895
2176
  if (/^\d/.test(cleaned)) cleaned = "a" + cleaned;
1896
2177
  const truncated = cleaned.slice(0, maxLength);
@@ -1903,6 +2184,7 @@ var genCleanIdForContentTypeAndValuePaths = (text, maxLength = 10, shortIdLength
1903
2184
  TEMP_removeDuplicateFilters,
1904
2185
  UI_CONTENT,
1905
2186
  _self_managed_buildAnnoHierarchyConfig,
2187
+ _self_managed_buildDocHierarchyConfig,
1906
2188
  _self_managed_getFixedAnnoRollupBlocks,
1907
2189
  _self_managed_getFixedAnnoTagBlock,
1908
2190
  autoGenFilterConfigsFromTpl,
@@ -1912,7 +2194,8 @@ var genCleanIdForContentTypeAndValuePaths = (text, maxLength = 10, shortIdLength
1912
2194
  extractAllBlocksFromTpl,
1913
2195
  extractAndOrganizeBlocks,
1914
2196
  genCleanCamelCaseId,
1915
- genCleanIdForContentTypeAndValuePaths,
2197
+ genCleanContentTypeId,
2198
+ genCleanValuePath,
1916
2199
  genTagId,
1917
2200
  generateFilterKey,
1918
2201
  getFilterKeyForBlock,