datastake-daf 0.6.249 → 0.6.250

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/.env ADDED
@@ -0,0 +1,8 @@
1
+ REACT_APP_API_KEY=
2
+ REACT_APP_AUTH_DOMAIN=
3
+ REACT_APP_PROJECT_ID=
4
+ REACT_APP_STORAGE_BUCKED=
5
+ REACT_APP_SENDER_ID=
6
+ REACT_APP_APP_ID=
7
+ REACT_APP_MEASUREMENT_ID=
8
+ REACT_APP_VAPID_KEY=
@@ -0,0 +1,13 @@
1
+ {
2
+ "cSpell.words": ["cukura"],
3
+ "files.autoSave": "afterDelay",
4
+ "editor.wordWrap": "on",
5
+ "editor.autoClosingBrackets": "always",
6
+ "editor.autoClosingComments": "always",
7
+ "editor.autoClosingQuotes": "always",
8
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
9
+ "editor.formatOnPaste": true,
10
+ "editor.formatOnSave": true,
11
+ "notebook.defaultFormatter": "esbenp.prettier-vscode",
12
+ "javascript.format.semicolons": "insert"
13
+ }
@@ -12655,7 +12655,7 @@ const {
12655
12655
  Paragraph: Paragraph$1
12656
12656
  } = antd.Typography;
12657
12657
  const checkHasActiveFilterValues = filtersConfig => {
12658
- if (!(filtersConfig !== null && filtersConfig !== void 0 && filtersConfig.filtersConfig) || !(filtersConfig !== null && filtersConfig !== void 0 && filtersConfig.selectedFilters)) return false;
12658
+ if (!filtersConfig?.filtersConfig || !filtersConfig?.selectedFilters) return false;
12659
12659
  const filterConfigKeys = Object.keys(filtersConfig.filtersConfig);
12660
12660
  const selectedFilters = filtersConfig.selectedFilters;
12661
12661
  return filterConfigKeys.some(key => {
@@ -12663,28 +12663,27 @@ const checkHasActiveFilterValues = filtersConfig => {
12663
12663
  return value !== undefined && value !== null && value !== '';
12664
12664
  });
12665
12665
  };
12666
- const useHeader = _ref => {
12667
- let {
12668
- title = '',
12669
- tooltip = '',
12670
- supportText = '',
12671
- tags = [],
12672
- actionButtons: _actionButtons = [],
12673
- titleTooltip,
12674
- className,
12675
- addedHeader = null,
12676
- addedHeaderFirst,
12677
- extraButtons: _extraButtons = [],
12678
- onDownload,
12679
- downloadDisabled,
12680
- goBackTo,
12681
- loading,
12682
- renderExtraComponents,
12683
- app = '',
12684
- isViewMode = false,
12685
- filtersConfig = {}
12686
- } = _ref;
12687
- const hasActiveFilterValues = React.useMemo(() => checkHasActiveFilterValues(filtersConfig), [filtersConfig === null || filtersConfig === void 0 ? void 0 : filtersConfig.filtersConfig, filtersConfig === null || filtersConfig === void 0 ? void 0 : filtersConfig.selectedFilters]);
12666
+ const useHeader = ({
12667
+ title = '',
12668
+ tooltip = '',
12669
+ supportText = '',
12670
+ tags = [],
12671
+ actionButtons: _actionButtons = [],
12672
+ titleTooltip,
12673
+ className,
12674
+ addedHeader = null,
12675
+ addedHeaderFirst,
12676
+ extraButtons: _extraButtons = [],
12677
+ onDownload,
12678
+ downloadDisabled,
12679
+ goBackTo,
12680
+ loading,
12681
+ renderExtraComponents,
12682
+ app = '',
12683
+ isViewMode = false,
12684
+ filtersConfig = {}
12685
+ }) => {
12686
+ const hasActiveFilterValues = React.useMemo(() => checkHasActiveFilterValues(filtersConfig), [filtersConfig?.filtersConfig, filtersConfig?.selectedFilters]);
12688
12687
  const [showFilters, setShowFilters] = React.useState(() => checkHasActiveFilterValues(filtersConfig));
12689
12688
  const hasFilters = filtersConfig && Object.keys(filtersConfig).length > 0;
12690
12689
  React.useEffect(() => {
@@ -12726,9 +12725,9 @@ const useHeader = _ref => {
12726
12725
  const buttonCont = React.useRef();
12727
12726
  const [mainContWidth, setMainContWidth] = React.useState(600);
12728
12727
  const [buttonContWidth, setButtonContWidth] = React.useState(0);
12729
- const hasSupportText = !!(supportText !== null && supportText !== void 0 && supportText.length);
12730
- const hasTags = !!(tags !== null && tags !== void 0 && tags.length);
12731
- const hasButtons = !!(actionButtons !== null && actionButtons !== void 0 && actionButtons.length || extraButtons !== null && extraButtons !== void 0 && extraButtons.length);
12728
+ const hasSupportText = !!supportText?.length;
12729
+ const hasTags = !!tags?.length;
12730
+ const hasButtons = !!(actionButtons?.length || extraButtons?.length);
12732
12731
  React.useEffect(() => {
12733
12732
  const mainContObserver = new ResizeObserver(entries => {
12734
12733
  const _mainEntry = entries[0];
@@ -15422,226 +15421,6 @@ const PdfForm = _ref3 => {
15422
15421
  return organizedSections;
15423
15422
  };
15424
15423
  const organizedForm = React.useMemo(() => organizeFormByHeaders(form), [form]);
15425
-
15426
- // Constants for height calculations (same as PdfView)
15427
- const PAGE_HEIGHT = 1587;
15428
- const FOOTER_HEIGHT = 70;
15429
- const HEADER_HEIGHT = 100;
15430
-
15431
- // Helper function to estimate tree node height based on content and type
15432
- const estimateTreeNodeHeight = function (key, config, value) {
15433
- let level = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
15434
- const baseHeight = 28; // Base height per tree node
15435
- const indentHeight = level * 2; // Additional height per level
15436
- let totalHeight = baseHeight + indentHeight;
15437
-
15438
- // Adjust height based on node type
15439
- if ((config === null || config === void 0 ? void 0 : config.type) === 'header') {
15440
- totalHeight += 15; // Headers need more space
15441
- } else if ((config === null || config === void 0 ? void 0 : config.type) === 'textarea') {
15442
- totalHeight += 40; // Textareas are taller
15443
- } else if ((config === null || config === void 0 ? void 0 : config.type) === 'dataLink' || (config === null || config === void 0 ? void 0 : config.type) === 'dataLinkGroup') {
15444
- totalHeight += 20; // Data links often have more content
15445
- }
15446
-
15447
- // Add height for value content if it exists
15448
- if (value && typeof value === 'string' && value.length > 50) {
15449
- totalHeight += Math.ceil(value.length / 50) * 15; // Multi-line content
15450
- }
15451
-
15452
- // Add height for children recursively
15453
- if (config !== null && config !== void 0 && config.inputs) {
15454
- const childKeys = Object.keys(config.inputs).filter(childKey => {
15455
- const childConfig = config.inputs[childKey];
15456
- // Check showIf condition
15457
- if (childConfig !== null && childConfig !== void 0 && childConfig.showIf && !evaluateShowIfCondition(childConfig.showIf, data)) {
15458
- return false;
15459
- }
15460
- return true;
15461
- }).sort((a, b) => {
15462
- var _config$inputs$a3, _config$inputs$b3;
15463
- const positionA = ((_config$inputs$a3 = config.inputs[a]) === null || _config$inputs$a3 === void 0 ? void 0 : _config$inputs$a3.position) || 0;
15464
- const positionB = ((_config$inputs$b3 = config.inputs[b]) === null || _config$inputs$b3 === void 0 ? void 0 : _config$inputs$b3.position) || 0;
15465
- return positionA - positionB;
15466
- });
15467
- childKeys.forEach(childKey => {
15468
- const childConfig = config.inputs[childKey];
15469
- const childValue = (value === null || value === void 0 ? void 0 : value[childKey]) || (data === null || data === void 0 ? void 0 : data[childKey]);
15470
- totalHeight += estimateTreeNodeHeight(childKey, childConfig, childValue, level + 1);
15471
- });
15472
- }
15473
-
15474
- // Handle array/repeated content
15475
- if (Array.isArray(value)) {
15476
- value.forEach(itemValue => {
15477
- totalHeight += estimateTreeNodeHeight(key, config, itemValue, level);
15478
- });
15479
- }
15480
- return totalHeight;
15481
- };
15482
-
15483
- // Helper function to split section based on height constraints (goes deep if needed)
15484
- const createHeightConstrainedSections = (sectionKey, section) => {
15485
- const MAX_SECTION_HEIGHT = PAGE_HEIGHT - HEADER_HEIGHT - FOOTER_HEIGHT - 150; // Conservative buffer
15486
- const subSections = [];
15487
-
15488
- // Get all top-level items in the section with detailed analysis
15489
- const topLevelItems = Object.keys(section).filter(key => !(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle')).map(key => {
15490
- var _section$key;
15491
- return {
15492
- key,
15493
- config: section[key],
15494
- estimatedHeight: estimateTreeNodeHeight(key, section[key], data === null || data === void 0 ? void 0 : data[key]),
15495
- canSplit: ((_section$key = section[key]) === null || _section$key === void 0 ? void 0 : _section$key.inputs) && Object.keys(section[key].inputs).length > 1 // Can this item be further split?
15496
- };
15497
- }).sort((a, b) => {
15498
- var _a$config, _b$config;
15499
- return (((_a$config = a.config) === null || _a$config === void 0 ? void 0 : _a$config.position) || 0) - (((_b$config = b.config) === null || _b$config === void 0 ? void 0 : _b$config.position) || 0);
15500
- });
15501
- let currentSubSection = _objectSpread2({}, section);
15502
-
15503
- // Remove all items from the base section structure
15504
- Object.keys(section).forEach(key => {
15505
- if (!(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle')) {
15506
- delete currentSubSection[key];
15507
- }
15508
- });
15509
- let currentHeight = 80; // Base height for section header
15510
- let subSectionIndex = 0;
15511
- topLevelItems.forEach((item, index) => {
15512
- const {
15513
- key,
15514
- config,
15515
- estimatedHeight,
15516
- canSplit
15517
- } = item;
15518
-
15519
- // If a single item is too large and can be split, split it at the child level
15520
- if (estimatedHeight > MAX_SECTION_HEIGHT * 0.8 && canSplit) {
15521
- // Split this large item into smaller parts
15522
- const childSplits = splitLargeItem(key, config, data === null || data === void 0 ? void 0 : data[key], MAX_SECTION_HEIGHT * 0.6);
15523
- childSplits.forEach((splitItem, splitIndex) => {
15524
- // Check if current subsection has room
15525
- if (currentHeight + splitItem.estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
15526
- // Save current sub-section
15527
- subSections.push({
15528
- key: "".concat(sectionKey, "_part_").concat(subSectionIndex),
15529
- section: _objectSpread2({}, currentSubSection),
15530
- title: section.label
15531
- });
15532
-
15533
- // Start new sub-section
15534
- currentSubSection = {
15535
- id: section.id,
15536
- label: section.label,
15537
- position: section.position + subSectionIndex + 1,
15538
- subTitle: section.subTitle
15539
- };
15540
- currentHeight = 80;
15541
- subSectionIndex++;
15542
- }
15543
-
15544
- // Add split item to current sub-section
15545
- currentSubSection[splitItem.key] = splitItem.config;
15546
- currentHeight += splitItem.estimatedHeight;
15547
- });
15548
- } else {
15549
- // Regular processing for items that fit or can't be split
15550
- // Check if adding this item would exceed height limit
15551
- if (currentHeight + estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
15552
- // Save current sub-section
15553
- subSections.push({
15554
- key: "".concat(sectionKey, "_part_").concat(subSectionIndex),
15555
- section: _objectSpread2({}, currentSubSection),
15556
- title: section.label
15557
- });
15558
-
15559
- // Start new sub-section
15560
- currentSubSection = {
15561
- id: section.id,
15562
- label: section.label,
15563
- position: section.position + subSectionIndex + 1,
15564
- subTitle: section.subTitle
15565
- };
15566
- currentHeight = 80;
15567
- subSectionIndex++;
15568
- }
15569
-
15570
- // Add item to current sub-section
15571
- currentSubSection[key] = config;
15572
- currentHeight += estimatedHeight;
15573
- }
15574
- });
15575
-
15576
- // Add the final sub-section if it has content
15577
- if (Object.keys(currentSubSection).length > 4) {
15578
- subSections.push({
15579
- key: subSectionIndex === 0 ? sectionKey : "".concat(sectionKey, "_part_").concat(subSectionIndex),
15580
- section: currentSubSection,
15581
- title: section.label
15582
- });
15583
- }
15584
- return subSections.length > 0 ? subSections : [{
15585
- key: sectionKey,
15586
- section: section,
15587
- title: section.label
15588
- }];
15589
- };
15590
-
15591
- // Helper function to split large items at the child level
15592
- const splitLargeItem = (parentKey, parentConfig, parentValue, maxHeight) => {
15593
- if (!(parentConfig !== null && parentConfig !== void 0 && parentConfig.inputs)) {
15594
- return [{
15595
- key: parentKey,
15596
- config: parentConfig,
15597
- estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue)
15598
- }];
15599
- }
15600
- const childItems = Object.keys(parentConfig.inputs).filter(childKey => {
15601
- const childConfig = parentConfig.inputs[childKey];
15602
- return !(childConfig !== null && childConfig !== void 0 && childConfig.showIf) || evaluateShowIfCondition(childConfig.showIf, data);
15603
- }).map(childKey => ({
15604
- key: childKey,
15605
- config: parentConfig.inputs[childKey],
15606
- estimatedHeight: estimateTreeNodeHeight(childKey, parentConfig.inputs[childKey], parentValue === null || parentValue === void 0 ? void 0 : parentValue[childKey])
15607
- })).sort((a, b) => {
15608
- var _a$config2, _b$config2;
15609
- return (((_a$config2 = a.config) === null || _a$config2 === void 0 ? void 0 : _a$config2.position) || 0) - (((_b$config2 = b.config) === null || _b$config2 === void 0 ? void 0 : _b$config2.position) || 0);
15610
- });
15611
- const splits = [];
15612
- let currentSplit = {
15613
- key: "".concat(parentKey, "_part_0"),
15614
- config: _objectSpread2(_objectSpread2({}, parentConfig), {}, {
15615
- inputs: {}
15616
- }),
15617
- estimatedHeight: 40 // Base height for parent structure
15618
- };
15619
- let splitIndex = 0;
15620
- childItems.forEach(child => {
15621
- if (currentSplit.estimatedHeight + child.estimatedHeight > maxHeight && Object.keys(currentSplit.config.inputs).length > 0) {
15622
- splits.push(currentSplit);
15623
- splitIndex++;
15624
- currentSplit = {
15625
- key: "".concat(parentKey, "_part_").concat(splitIndex),
15626
- config: _objectSpread2(_objectSpread2({}, parentConfig), {}, {
15627
- label: parentConfig.label,
15628
- inputs: {}
15629
- }),
15630
- estimatedHeight: 40
15631
- };
15632
- }
15633
- currentSplit.config.inputs[child.key] = child.config;
15634
- currentSplit.estimatedHeight += child.estimatedHeight;
15635
- });
15636
- if (Object.keys(currentSplit.config.inputs).length > 0) {
15637
- splits.push(currentSplit);
15638
- }
15639
- return splits.length > 0 ? splits : [{
15640
- key: parentKey,
15641
- config: parentConfig,
15642
- estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue)
15643
- }];
15644
- };
15645
15424
  const pdfConfig = React.useMemo(() => {
15646
15425
  const sections = [];
15647
15426
  Object.keys(organizedForm).forEach(sectionKey => {
@@ -15649,40 +15428,28 @@ const PdfForm = _ref3 => {
15649
15428
  if (typeof section !== 'object' || !section.label) {
15650
15429
  return;
15651
15430
  }
15652
-
15653
- // Create height-constrained sub-sections
15654
- const subSections = createHeightConstrainedSections(sectionKey, section);
15655
- subSections.forEach(_ref4 => {
15656
- let {
15657
- key,
15658
- section: subSection,
15659
- title
15660
- } = _ref4;
15661
- sections.push({
15662
- render: () => /*#__PURE__*/jsxRuntime.jsx("div", {
15663
- className: "pdf-form-section",
15664
- children: /*#__PURE__*/jsxRuntime.jsx(PdfFormContent, {
15665
- form: {
15666
- [key]: _objectSpread2(_objectSpread2({}, subSection), {}, {
15667
- label: title
15668
- })
15669
- },
15670
- data: data,
15671
- t: t,
15672
- user: user,
15673
- title: formName,
15674
- source: source,
15675
- version: version,
15676
- getApiBaseUrl: getApiBaseUrl,
15677
- getAppHeader: getAppHeader,
15678
- app: app
15679
- })
15680
- }, key),
15681
- style: {
15682
- marginBottom: '20px',
15683
- padding: '0 20px'
15684
- }
15685
- });
15431
+ sections.push({
15432
+ render: () => /*#__PURE__*/jsxRuntime.jsx("div", {
15433
+ className: "pdf-form-section",
15434
+ children: /*#__PURE__*/jsxRuntime.jsx(PdfFormContent, {
15435
+ form: {
15436
+ [sectionKey]: section
15437
+ },
15438
+ data: data,
15439
+ t: t,
15440
+ user: user,
15441
+ title: formName,
15442
+ source: source,
15443
+ version: version,
15444
+ getApiBaseUrl: getApiBaseUrl,
15445
+ getAppHeader: getAppHeader,
15446
+ app: app
15447
+ })
15448
+ }, sectionKey),
15449
+ style: {
15450
+ marginBottom: '20px',
15451
+ padding: '0 20px'
15452
+ }
15686
15453
  });
15687
15454
  });
15688
15455
  return sections;
@@ -20776,13 +20543,16 @@ function DashboardLayout(_ref) {
20776
20543
  let {
20777
20544
  children,
20778
20545
  header,
20779
- footer
20546
+ footer,
20547
+ isCollapsed
20780
20548
  } = _ref;
20781
20549
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
20782
20550
  className: "daf-analysis",
20783
- style: {
20551
+ style: _objectSpread2({
20784
20552
  backgroundColor: "#F9FAFB"
20785
- },
20553
+ }, isCollapsed === undefined ? {} : {
20554
+ maxWidth: isCollapsed ? "calc(100vw - 70px)" : "calc(100vw - 250px)"
20555
+ }),
20786
20556
  children: [header, /*#__PURE__*/jsxRuntime.jsx("div", {
20787
20557
  className: "content",
20788
20558
  children: /*#__PURE__*/jsxRuntime.jsx("div", {
@@ -21324,7 +21094,7 @@ function SdgList({
21324
21094
  }) {
21325
21095
  return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
21326
21096
  children: [/*#__PURE__*/jsxRuntime.jsx(Label, {
21327
- children: "SDGs:"
21097
+ children: "SDGs"
21328
21098
  }), /*#__PURE__*/jsxRuntime.jsx(SDGIcons, {
21329
21099
  sdgList: sdgList,
21330
21100
  t: t
@@ -21407,7 +21177,8 @@ function ProjectWidget(_ref) {
21407
21177
  }), !hideSDGList && /*#__PURE__*/jsxRuntime.jsx("div", {
21408
21178
  style: {
21409
21179
  borderTop: "1px solid var(--base-gray-30)",
21410
- paddingTop: "10px"
21180
+ paddingTop: "10px",
21181
+ minHeight: "61px"
21411
21182
  },
21412
21183
  children: /*#__PURE__*/jsxRuntime.jsx(SdgList, {
21413
21184
  sdgList: sdgList,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.249",
3
+ "version": "0.6.250",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -5,12 +5,17 @@
5
5
  *
6
6
  * Every Widget inside the component (children) must be wrapped by a section tag, because i say so and if you dont like it you can change the code in the entire codebase, included but not limited to the following projects: nashiriki, tazama, kustawi, sbg, cukura, kota, mmt, and wherever the daf library is used.
7
7
  */
8
- export default function DashboardLayout({ children, header, footer }) {
8
+ export default function DashboardLayout({ children, header, footer, isCollapsed }) {
9
9
  return (
10
10
  <div
11
11
  className="daf-analysis"
12
12
  style={{
13
13
  backgroundColor: `#F9FAFB`,
14
+ ...(isCollapsed === undefined
15
+ ? {}
16
+ : {
17
+ maxWidth: isCollapsed ? `calc(100vw - 70px)` : `calc(100vw - 250px)`,
18
+ }),
14
19
  }}
15
20
  >
16
21
  {header}
@@ -1,10 +1,10 @@
1
1
  import { Label } from "../style";
2
2
  import SDGIcons from "../../../../UI/SDGIcon/index.jsx";
3
3
  export default function SdgList({ sdgList = [], t }) {
4
- return (
5
- <>
6
- <Label>SDGs:</Label>
7
- <SDGIcons sdgList={sdgList} t={t} />
8
- </>
9
- );
4
+ return (
5
+ <>
6
+ <Label>SDGs</Label>
7
+ <SDGIcons sdgList={sdgList} t={t} />
8
+ </>
9
+ );
10
10
  }
@@ -83,6 +83,7 @@ export default function ProjectWidget({
83
83
  style={{
84
84
  borderTop: "1px solid var(--base-gray-30)",
85
85
  paddingTop: "10px",
86
+ minHeight: "61px",
86
87
  }}
87
88
  >
88
89
  <SdgList sdgList={sdgList} t={t} />
@@ -525,227 +525,6 @@ const PdfForm = ({
525
525
 
526
526
  const organizedForm = useMemo(() => organizeFormByHeaders(form), [form]);
527
527
 
528
- // Constants for height calculations (same as PdfView)
529
- const PAGE_HEIGHT = 1587;
530
- const FOOTER_HEIGHT = 70;
531
- const HEADER_HEIGHT = 100;
532
-
533
- // Helper function to estimate tree node height based on content and type
534
- const estimateTreeNodeHeight = (key, config, value, level = 0) => {
535
- const baseHeight = 28; // Base height per tree node
536
- const indentHeight = level * 2; // Additional height per level
537
- let totalHeight = baseHeight + indentHeight;
538
-
539
- // Adjust height based on node type
540
- if (config?.type === 'header') {
541
- totalHeight += 15; // Headers need more space
542
- } else if (config?.type === 'textarea') {
543
- totalHeight += 40; // Textareas are taller
544
- } else if (config?.type === 'dataLink' || config?.type === 'dataLinkGroup') {
545
- totalHeight += 20; // Data links often have more content
546
- }
547
-
548
- // Add height for value content if it exists
549
- if (value && typeof value === 'string' && value.length > 50) {
550
- totalHeight += Math.ceil(value.length / 50) * 15; // Multi-line content
551
- }
552
-
553
- // Add height for children recursively
554
- if (config?.inputs) {
555
- const childKeys = Object.keys(config.inputs)
556
- .filter(childKey => {
557
- const childConfig = config.inputs[childKey];
558
- // Check showIf condition
559
- if (childConfig?.showIf && !evaluateShowIfCondition(childConfig.showIf, data)) {
560
- return false;
561
- }
562
- return true;
563
- })
564
- .sort((a, b) => {
565
- const positionA = config.inputs[a]?.position || 0;
566
- const positionB = config.inputs[b]?.position || 0;
567
- return positionA - positionB;
568
- });
569
-
570
- childKeys.forEach(childKey => {
571
- const childConfig = config.inputs[childKey];
572
- const childValue = value?.[childKey] || data?.[childKey];
573
- totalHeight += estimateTreeNodeHeight(childKey, childConfig, childValue, level + 1);
574
- });
575
- }
576
-
577
- // Handle array/repeated content
578
- if (Array.isArray(value)) {
579
- value.forEach(itemValue => {
580
- totalHeight += estimateTreeNodeHeight(key, config, itemValue, level);
581
- });
582
- }
583
-
584
- return totalHeight;
585
- };
586
-
587
- // Helper function to split section based on height constraints (goes deep if needed)
588
- const createHeightConstrainedSections = (sectionKey, section) => {
589
- const MAX_SECTION_HEIGHT = PAGE_HEIGHT - HEADER_HEIGHT - FOOTER_HEIGHT - 150; // Conservative buffer
590
- const subSections = [];
591
-
592
- // Get all top-level items in the section with detailed analysis
593
- const topLevelItems = Object.keys(section)
594
- .filter(key => !(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle'))
595
- .map(key => ({
596
- key,
597
- config: section[key],
598
- estimatedHeight: estimateTreeNodeHeight(key, section[key], data?.[key]),
599
- canSplit: section[key]?.inputs && Object.keys(section[key].inputs).length > 1 // Can this item be further split?
600
- }))
601
- .sort((a, b) => (a.config?.position || 0) - (b.config?.position || 0));
602
-
603
- let currentSubSection = {
604
- ...section,
605
- };
606
-
607
- // Remove all items from the base section structure
608
- Object.keys(section).forEach(key => {
609
- if (!(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle')) {
610
- delete currentSubSection[key];
611
- }
612
- });
613
-
614
- let currentHeight = 80; // Base height for section header
615
- let subSectionIndex = 0;
616
-
617
- topLevelItems.forEach((item, index) => {
618
- const { key, config, estimatedHeight, canSplit } = item;
619
-
620
- // If a single item is too large and can be split, split it at the child level
621
- if (estimatedHeight > MAX_SECTION_HEIGHT * 0.8 && canSplit) {
622
- // Split this large item into smaller parts
623
- const childSplits = splitLargeItem(key, config, data?.[key], MAX_SECTION_HEIGHT * 0.6);
624
-
625
- childSplits.forEach((splitItem, splitIndex) => {
626
- // Check if current subsection has room
627
- if (currentHeight + splitItem.estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
628
- // Save current sub-section
629
- subSections.push({
630
- key: `${sectionKey}_part_${subSectionIndex}`,
631
- section: { ...currentSubSection },
632
- title: section.label
633
- });
634
-
635
- // Start new sub-section
636
- currentSubSection = {
637
- id: section.id,
638
- label: section.label,
639
- position: section.position + subSectionIndex + 1,
640
- subTitle: section.subTitle
641
- };
642
- currentHeight = 80;
643
- subSectionIndex++;
644
- }
645
-
646
- // Add split item to current sub-section
647
- currentSubSection[splitItem.key] = splitItem.config;
648
- currentHeight += splitItem.estimatedHeight;
649
- });
650
- } else {
651
- // Regular processing for items that fit or can't be split
652
- // Check if adding this item would exceed height limit
653
- if (currentHeight + estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
654
- // Save current sub-section
655
- subSections.push({
656
- key: `${sectionKey}_part_${subSectionIndex}`,
657
- section: { ...currentSubSection },
658
- title: section.label
659
- });
660
-
661
- // Start new sub-section
662
- currentSubSection = {
663
- id: section.id,
664
- label: section.label,
665
- position: section.position + subSectionIndex + 1,
666
- subTitle: section.subTitle
667
- };
668
- currentHeight = 80;
669
- subSectionIndex++;
670
- }
671
-
672
- // Add item to current sub-section
673
- currentSubSection[key] = config;
674
- currentHeight += estimatedHeight;
675
- }
676
- });
677
-
678
- // Add the final sub-section if it has content
679
- if (Object.keys(currentSubSection).length > 4) {
680
- subSections.push({
681
- key: subSectionIndex === 0 ? sectionKey : `${sectionKey}_part_${subSectionIndex}`,
682
- section: currentSubSection,
683
- title: section.label
684
- });
685
- }
686
-
687
- return subSections.length > 0 ? subSections : [{
688
- key: sectionKey,
689
- section: section,
690
- title: section.label
691
- }];
692
- };
693
-
694
- // Helper function to split large items at the child level
695
- const splitLargeItem = (parentKey, parentConfig, parentValue, maxHeight) => {
696
- if (!parentConfig?.inputs) {
697
- return [{ key: parentKey, config: parentConfig, estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue) }];
698
- }
699
-
700
- const childItems = Object.keys(parentConfig.inputs)
701
- .filter(childKey => {
702
- const childConfig = parentConfig.inputs[childKey];
703
- return !childConfig?.showIf || evaluateShowIfCondition(childConfig.showIf, data);
704
- })
705
- .map(childKey => ({
706
- key: childKey,
707
- config: parentConfig.inputs[childKey],
708
- estimatedHeight: estimateTreeNodeHeight(childKey, parentConfig.inputs[childKey], parentValue?.[childKey])
709
- }))
710
- .sort((a, b) => (a.config?.position || 0) - (b.config?.position || 0));
711
-
712
- const splits = [];
713
- let currentSplit = {
714
- key: `${parentKey}_part_0`,
715
- config: {
716
- ...parentConfig,
717
- inputs: {}
718
- },
719
- estimatedHeight: 40 // Base height for parent structure
720
- };
721
- let splitIndex = 0;
722
-
723
- childItems.forEach(child => {
724
- if (currentSplit.estimatedHeight + child.estimatedHeight > maxHeight && Object.keys(currentSplit.config.inputs).length > 0) {
725
- splits.push(currentSplit);
726
- splitIndex++;
727
- currentSplit = {
728
- key: `${parentKey}_part_${splitIndex}`,
729
- config: {
730
- ...parentConfig,
731
- label: parentConfig.label,
732
- inputs: {}
733
- },
734
- estimatedHeight: 40
735
- };
736
- }
737
-
738
- currentSplit.config.inputs[child.key] = child.config;
739
- currentSplit.estimatedHeight += child.estimatedHeight;
740
- });
741
-
742
- if (Object.keys(currentSplit.config.inputs).length > 0) {
743
- splits.push(currentSplit);
744
- }
745
-
746
- return splits.length > 0 ? splits : [{ key: parentKey, config: parentConfig, estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue) }];
747
- };
748
-
749
528
  const pdfConfig = useMemo(() => {
750
529
  const sections = [];
751
530
 
@@ -756,32 +535,27 @@ const PdfForm = ({
756
535
  return;
757
536
  }
758
537
 
759
- // Create height-constrained sub-sections
760
- const subSections = createHeightConstrainedSections(sectionKey, section);
761
-
762
- subSections.forEach(({ key, section: subSection, title }) => {
763
- sections.push({
764
- render: () => (
765
- <div key={key} className="pdf-form-section">
766
- <PdfFormContent
767
- form={{ [key]: { ...subSection, label: title } }}
768
- data={data}
769
- t={t}
770
- user={user}
771
- title={formName}
772
- source={source}
773
- version={version}
774
- getApiBaseUrl={getApiBaseUrl}
775
- getAppHeader={getAppHeader}
776
- app={app}
777
- />
778
- </div>
779
- ),
780
- style: {
781
- marginBottom: '20px',
782
- padding: '0 20px'
783
- }
784
- });
538
+ sections.push({
539
+ render: () => (
540
+ <div key={sectionKey} className="pdf-form-section">
541
+ <PdfFormContent
542
+ form={{ [sectionKey]: section }}
543
+ data={data}
544
+ t={t}
545
+ user={user}
546
+ title={formName}
547
+ source={source}
548
+ version={version}
549
+ getApiBaseUrl={getApiBaseUrl}
550
+ getAppHeader={getAppHeader}
551
+ app={app}
552
+ />
553
+ </div>
554
+ ),
555
+ style: {
556
+ marginBottom: '20px',
557
+ padding: '0 20px'
558
+ }
785
559
  });
786
560
  });
787
561