datastake-daf 0.6.415 → 0.6.417

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.
@@ -13276,9 +13276,15 @@ DAFFooter.propTypes = {
13276
13276
  };
13277
13277
 
13278
13278
  const PAGE_HEIGHT = 1587;
13279
- // margin-top: 20, bottom: 20;
13280
13279
  const FOOTER_HEIGHT = 70;
13281
13280
  const HEADER_HEIGHT = 100;
13281
+ const SECTION_SPACING = 24;
13282
+ const TOP_PADDING = 30;
13283
+ const BOTTOM_PADDING = 30;
13284
+
13285
+ // Calculate usable height per page
13286
+ const USABLE_HEIGHT = PAGE_HEIGHT - HEADER_HEIGHT - FOOTER_HEIGHT - TOP_PADDING - BOTTOM_PADDING;
13287
+ const SPLIT_THRESHOLD = USABLE_HEIGHT * 0.80;
13282
13288
  const Row = _ref => {
13283
13289
  let {
13284
13290
  widgets,
@@ -13303,7 +13309,7 @@ const Row = _ref => {
13303
13309
  ref
13304
13310
  });
13305
13311
  }
13306
- }, [height]);
13312
+ }, [height, i, onChangeHeight]);
13307
13313
  return /*#__PURE__*/jsxRuntime.jsx("section", {
13308
13314
  ref: ref,
13309
13315
  style: widgets.style,
@@ -13325,51 +13331,92 @@ function PdfView(_ref2) {
13325
13331
  const [pages, setPages] = React.useState([1]);
13326
13332
  const doSizing = React.useCallback(() => {
13327
13333
  const keys = Object.keys(sectionsConfig);
13334
+ if (keys.length !== config.length) return;
13335
+
13336
+ // Check if all refs are ready
13337
+ const allRefsReady = keys.every(k => {
13338
+ const {
13339
+ ref
13340
+ } = sectionsConfig[k];
13341
+ return ref && ref.current;
13342
+ });
13343
+ if (!allRefsReady) return;
13328
13344
  let _pages = [1];
13329
- let _page = 1;
13330
- if (keys.length === config.length) {
13331
- let incrHeight = 0;
13332
- keys.forEach(k => {
13333
- const {
13334
- ref
13335
- } = sectionsConfig[k];
13345
+ let currentPage = 1;
13346
+ let remainingHeight = USABLE_HEIGHT;
13347
+
13348
+ // Reset all margins first
13349
+ keys.forEach(k => {
13350
+ const {
13351
+ ref
13352
+ } = sectionsConfig[k];
13353
+ if (ref.current) {
13354
+ ref.current.style.marginTop = '0px';
13336
13355
  ref.current.style.marginBottom = '0px';
13337
- // ref.current.style.marginTop = '15px';
13338
- });
13339
- keys.forEach((k, i) => {
13340
- const {
13341
- height,
13342
- ref
13343
- } = sectionsConfig[k];
13344
- if (i === 0) {
13345
- ref.current.style.marginTop = "".concat(HEADER_HEIGHT, "px");
13346
- incrHeight += HEADER_HEIGHT;
13347
- }
13348
- const newHeight = incrHeight + height;
13349
- if (i === keys.length - 1) {
13350
- ref.current.style.paddingBottom = '30px';
13351
- }
13352
- if (newHeight > PAGE_HEIGHT - 30 - FOOTER_HEIGHT - HEADER_HEIGHT) {
13353
- const dif = Math.abs(PAGE_HEIGHT - incrHeight);
13354
- ref.current.style.marginTop = '30px';
13355
- _page += 1;
13356
- _pages.push(_page);
13357
- if (sectionsConfig[keys[i - 1]]) {
13358
- const {
13359
- ref: topRef
13360
- } = sectionsConfig[keys[i - 1]];
13361
- topRef.current.style.marginBottom = "".concat(dif + HEADER_HEIGHT - 24, "px");
13362
- incrHeight = height + 24 + HEADER_HEIGHT;
13363
- // console.log('margin', dif);
13356
+ ref.current.style.paddingBottom = '0px';
13357
+ }
13358
+ });
13359
+ keys.forEach((k, i) => {
13360
+ const {
13361
+ height,
13362
+ ref
13363
+ } = sectionsConfig[k];
13364
+ if (!ref || !ref.current) return;
13365
+ const isFirst = i === 0;
13366
+ const isLast = i === keys.length - 1;
13367
+ const startOfPageMargin = HEADER_HEIGHT + TOP_PADDING;
13368
+
13369
+ // First section of first page gets header spacing
13370
+ if (isFirst) {
13371
+ ref.current.style.marginTop = "".concat(startOfPageMargin, "px");
13372
+ remainingHeight = USABLE_HEIGHT;
13373
+ }
13374
+
13375
+ // Calculate space needed for this section (including spacing if not first on page)
13376
+ const sectionTotalHeight = height + (isFirst || remainingHeight === USABLE_HEIGHT ? 0 : SECTION_SPACING);
13377
+
13378
+ // Check if adding this section would exceed the remaining height
13379
+ const wouldExceedPage = sectionTotalHeight > remainingHeight;
13380
+
13381
+ // Check if the accumulated height on current page + this section exceeds 65% threshold
13382
+ const currentPageUsed = USABLE_HEIGHT - remainingHeight;
13383
+ const totalWithThisSection = currentPageUsed + sectionTotalHeight;
13384
+ const wouldExceedThreshold = totalWithThisSection > SPLIT_THRESHOLD;
13385
+ if (!isFirst && (wouldExceedPage || wouldExceedThreshold)) {
13386
+ // Move to next page
13387
+ const previousKey = keys[i - 1];
13388
+ if (sectionsConfig[previousKey]) {
13389
+ const {
13390
+ ref: prevRef
13391
+ } = sectionsConfig[previousKey];
13392
+ if (prevRef && prevRef.current) {
13393
+ // Add margin to push to next page
13394
+ prevRef.current.style.marginBottom = "".concat(remainingHeight * 0.4 + HEADER_HEIGHT, "px");
13364
13395
  }
13396
+ }
13397
+
13398
+ // Start new page - position after header and top padding
13399
+ currentPage += 1;
13400
+ _pages.push(currentPage);
13401
+ ref.current.style.marginTop = "".concat(startOfPageMargin, "px");
13402
+ remainingHeight = USABLE_HEIGHT - height;
13403
+ } else {
13404
+ // Section fits on current page
13405
+ if (!isFirst && remainingHeight !== USABLE_HEIGHT) {
13406
+ ref.current.style.marginTop = "".concat(SECTION_SPACING, "px");
13407
+ remainingHeight -= height + SECTION_SPACING;
13365
13408
  } else {
13366
- incrHeight = newHeight + 24;
13409
+ remainingHeight -= height;
13367
13410
  }
13368
- // console.groupEnd();
13369
- });
13370
- setPages(_pages);
13371
- }
13372
- }, [sectionsConfig]);
13411
+ }
13412
+
13413
+ // Add padding to last section
13414
+ if (isLast) {
13415
+ ref.current.style.paddingBottom = "".concat(BOTTOM_PADDING, "px");
13416
+ }
13417
+ });
13418
+ setPages(_pages);
13419
+ }, [sectionsConfig, config.length]);
13373
13420
  React.useEffect(() => {
13374
13421
  doSizing();
13375
13422
  }, [doSizing]);
@@ -13390,27 +13437,17 @@ function PdfView(_ref2) {
13390
13437
  widgets: widgets,
13391
13438
  i: i,
13392
13439
  onChangeHeight: onChangeHeight
13393
- }, "dashboard-sections=".concat(i + 1)))
13440
+ }, "dashboard-sections-".concat(i + 1)))
13394
13441
  })
13395
13442
  })
13396
13443
  });
13397
13444
  }, [config, onChangeHeight]);
13398
-
13399
- // <div className="daf-analysis">
13400
- // <Header title={t('Dashboard Title')} />
13401
-
13402
- // <div className="content">
13403
- // <div className="view-content">
13404
- // <div className="daf-analysis-layout">
13405
- // <div className='sections-cont w-pt'>
13406
- // <section>
13407
-
13408
13445
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
13409
13446
  className: contClassName,
13410
13447
  style: {
13411
13448
  position: 'relative'
13412
13449
  },
13413
- children: [renderDashboard(), pages.map(page => /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
13450
+ children: [renderDashboard(), pages.map(page => /*#__PURE__*/jsxRuntime.jsxs("div", {
13414
13451
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
13415
13452
  style: {
13416
13453
  top: (page - 1) * PAGE_HEIGHT,
@@ -13433,7 +13470,7 @@ function PdfView(_ref2) {
13433
13470
  alt: "logo"
13434
13471
  })
13435
13472
  })]
13436
- }, "headers-".concat(page)), /*#__PURE__*/jsxRuntime.jsxs("div", {
13473
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
13437
13474
  style: {
13438
13475
  top: page * PAGE_HEIGHT - FOOTER_HEIGHT,
13439
13476
  width: '100%',
@@ -13476,8 +13513,8 @@ function PdfView(_ref2) {
13476
13513
  children: page
13477
13514
  })
13478
13515
  })]
13479
- }, "footers-".concat(page))]
13480
- }))]
13516
+ })]
13517
+ }, "page-".concat(page)))]
13481
13518
  });
13482
13519
  }
13483
13520
  PdfView.propTypes = {
@@ -13487,7 +13524,8 @@ PdfView.propTypes = {
13487
13524
  imgSrc: PropTypes__default["default"].string,
13488
13525
  userId: PropTypes__default["default"].string,
13489
13526
  accountId: PropTypes__default["default"].string,
13490
- documentId: PropTypes__default["default"].string
13527
+ documentId: PropTypes__default["default"].string,
13528
+ downloadId: PropTypes__default["default"].string
13491
13529
  };
13492
13530
 
13493
13531
  const ajaxSelectFieldData = async (value, config, getApiBaseUrl = () => {}, getAppHeader = () => {}, app, formValues = {}) => {
@@ -22123,34 +22161,7 @@ const WidgetCard = _ref => {
22123
22161
  children: /*#__PURE__*/jsxRuntime.jsx("a", {
22124
22162
  className: formatClassname(["widget-card-logo-icon", (buttonConfig === null || buttonConfig === void 0 ? void 0 : buttonConfig.disabled) && "disabled-anchor"]),
22125
22163
  href: buttonConfig !== null && buttonConfig !== void 0 && buttonConfig.disabled ? undefined : link,
22126
- onClick: e => {
22127
- if (buttonConfig !== null && buttonConfig !== void 0 && buttonConfig.disabled) {
22128
- e.preventDefault();
22129
- } else if (buttonConfig !== null && buttonConfig !== void 0 && buttonConfig.onClick) {
22130
- e.preventDefault();
22131
- buttonConfig.onClick();
22132
- } else if (buttonConfig !== null && buttonConfig !== void 0 && buttonConfig.action) {
22133
- e.preventDefault();
22134
- // Handle different action types
22135
- switch (buttonConfig.action.type) {
22136
- case 'modal':
22137
- if (buttonConfig.action.onOpen) {
22138
- buttonConfig.action.onOpen();
22139
- }
22140
- break;
22141
- case 'navigate':
22142
- if (buttonConfig.action.url) {
22143
- window.location.href = buttonConfig.action.url;
22144
- }
22145
- break;
22146
- case 'custom':
22147
- if (buttonConfig.action.handler) {
22148
- buttonConfig.action.handler();
22149
- }
22150
- break;
22151
- }
22152
- }
22153
- },
22164
+ onClick: buttonConfig !== null && buttonConfig !== void 0 && buttonConfig.disabled ? e => e.preventDefault() : undefined,
22154
22165
  children: /*#__PURE__*/jsxRuntime.jsx(CustomIcon, {
22155
22166
  name: buttonIcon,
22156
22167
  size: 16,
@@ -3792,6 +3792,15 @@ const splitStringInMultipleLines = (s, limit = 20) => {
3792
3792
  if (line) result += line;
3793
3793
  return result;
3794
3794
  };
3795
+ const safeJsonParse = (value, fallback = value) => {
3796
+ if (typeof value !== 'string') return value;
3797
+ try {
3798
+ return JSON.parse(value);
3799
+ } catch {
3800
+ console.warn('Failed to parse JSON:', value);
3801
+ return fallback;
3802
+ }
3803
+ };
3795
3804
 
3796
3805
  function _checkValue$1(wantedValue, match, fieldValue) {
3797
3806
  match = match ? match.trim() : null;
@@ -11398,6 +11407,7 @@ exports.renderTemplateString = renderTemplateString;
11398
11407
  exports.renderTemplateStringInObject = renderTemplateStringInObject;
11399
11408
  exports.renderTooltip = renderTooltip;
11400
11409
  exports.renderTooltipJsx = renderTooltipJsx;
11410
+ exports.safeJsonParse = safeJsonParse;
11401
11411
  exports.showHideInput = showHideInput;
11402
11412
  exports.snakeCaseToTitleCase = snakeCaseToTitleCase;
11403
11413
  exports.splitStringInMultipleLines = splitStringInMultipleLines;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.415",
3
+ "version": "0.6.417",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -4,9 +4,15 @@ import { useCallback, useEffect, useRef, useState } from "react";
4
4
  import { formatClassname } from "../../../../../helpers/ClassesHelper";
5
5
 
6
6
  const PAGE_HEIGHT = 1587;
7
- // margin-top: 20, bottom: 20;
8
7
  const FOOTER_HEIGHT = 70;
9
8
  const HEADER_HEIGHT = 100;
9
+ const SECTION_SPACING = 24;
10
+ const TOP_PADDING = 30;
11
+ const BOTTOM_PADDING = 30;
12
+
13
+ // Calculate usable height per page
14
+ const USABLE_HEIGHT = PAGE_HEIGHT - HEADER_HEIGHT - FOOTER_HEIGHT - TOP_PADDING - BOTTOM_PADDING;
15
+ const SPLIT_THRESHOLD = USABLE_HEIGHT * 0.80;
10
16
 
11
17
  const Row = ({ widgets, i, onChangeHeight = () => { } }) => {
12
18
  const ref = useRef();
@@ -28,7 +34,7 @@ const Row = ({ widgets, i, onChangeHeight = () => { } }) => {
28
34
  if (height) {
29
35
  onChangeHeight(i, { height, ref });
30
36
  }
31
- }, [height])
37
+ }, [height, i, onChangeHeight])
32
38
 
33
39
  return (
34
40
  <section ref={ref} style={widgets.style}>
@@ -52,52 +58,90 @@ export default function PdfView({
52
58
 
53
59
  const doSizing = useCallback(() => {
54
60
  const keys = Object.keys(sectionsConfig);
55
- let _pages = [1];
56
- let _page = 1;
57
-
58
- if (keys.length === config.length) {
59
- let incrHeight = 0;
61
+
62
+ if (keys.length !== config.length) return;
60
63
 
61
- keys.forEach(k => {
62
- const { ref } = sectionsConfig[k];
63
- ref.current.style.marginBottom = '0px';
64
- // ref.current.style.marginTop = '15px';
65
- })
64
+ // Check if all refs are ready
65
+ const allRefsReady = keys.every(k => {
66
+ const { ref } = sectionsConfig[k];
67
+ return ref && ref.current;
68
+ });
66
69
 
67
- keys.forEach((k, i) => {
68
- const { height, ref } = sectionsConfig[k];
70
+ if (!allRefsReady) return;
69
71
 
70
- if (i === 0) {
71
- ref.current.style.marginTop = `${HEADER_HEIGHT}px`;
72
- incrHeight += HEADER_HEIGHT;
73
- }
72
+ let _pages = [1];
73
+ let currentPage = 1;
74
+ let remainingHeight = USABLE_HEIGHT;
75
+
76
+ // Reset all margins first
77
+ keys.forEach(k => {
78
+ const { ref } = sectionsConfig[k];
79
+ if (ref.current) {
80
+ ref.current.style.marginTop = '0px';
81
+ ref.current.style.marginBottom = '0px';
82
+ ref.current.style.paddingBottom = '0px';
83
+ }
84
+ });
74
85
 
75
- const newHeight = incrHeight + height;
86
+ keys.forEach((k, i) => {
87
+ const { height, ref } = sectionsConfig[k];
88
+ if (!ref || !ref.current) return;
89
+
90
+ const isFirst = i === 0;
91
+ const isLast = i === keys.length - 1;
92
+ const startOfPageMargin = HEADER_HEIGHT + TOP_PADDING;
93
+
94
+ // First section of first page gets header spacing
95
+ if (isFirst) {
96
+ ref.current.style.marginTop = `${startOfPageMargin}px`;
97
+ remainingHeight = USABLE_HEIGHT;
98
+ }
76
99
 
77
- if (i === keys.length - 1) {
78
- ref.current.style.paddingBottom = '30px';
100
+ // Calculate space needed for this section (including spacing if not first on page)
101
+ const sectionTotalHeight = height + (isFirst || remainingHeight === USABLE_HEIGHT ? 0 : SECTION_SPACING);
102
+
103
+ // Check if adding this section would exceed the remaining height
104
+ const wouldExceedPage = sectionTotalHeight > remainingHeight;
105
+
106
+ // Check if the accumulated height on current page + this section exceeds 65% threshold
107
+ const currentPageUsed = USABLE_HEIGHT - remainingHeight;
108
+ const totalWithThisSection = currentPageUsed + sectionTotalHeight;
109
+ const wouldExceedThreshold = totalWithThisSection > SPLIT_THRESHOLD;
110
+
111
+ if (!isFirst && (wouldExceedPage || wouldExceedThreshold)) {
112
+ // Move to next page
113
+ const previousKey = keys[i - 1];
114
+ if (sectionsConfig[previousKey]) {
115
+ const { ref: prevRef } = sectionsConfig[previousKey];
116
+ if (prevRef && prevRef.current) {
117
+ // Add margin to push to next page
118
+ prevRef.current.style.marginBottom = `${(remainingHeight * 0.4) + HEADER_HEIGHT}px`;
119
+ }
79
120
  }
80
121
 
81
- if (newHeight > PAGE_HEIGHT - 30 - FOOTER_HEIGHT - HEADER_HEIGHT) {
82
- const dif = Math.abs(PAGE_HEIGHT - incrHeight);
83
- ref.current.style.marginTop = '30px';
84
- _page += 1;
85
- _pages.push(_page);
86
-
87
- if (sectionsConfig[keys[i - 1]]) {
88
- const { ref: topRef } = sectionsConfig[keys[i - 1]];
89
- topRef.current.style.marginBottom = `${dif + HEADER_HEIGHT - 24}px`;
90
- incrHeight = height + 24 + HEADER_HEIGHT;
91
- // console.log('margin', dif);
92
- }
122
+ // Start new page - position after header and top padding
123
+ currentPage += 1;
124
+ _pages.push(currentPage);
125
+ ref.current.style.marginTop = `${startOfPageMargin}px`;
126
+ remainingHeight = USABLE_HEIGHT - height;
127
+ } else {
128
+ // Section fits on current page
129
+ if (!isFirst && remainingHeight !== USABLE_HEIGHT) {
130
+ ref.current.style.marginTop = `${SECTION_SPACING}px`;
131
+ remainingHeight -= (height + SECTION_SPACING);
93
132
  } else {
94
- incrHeight = newHeight + 24;
133
+ remainingHeight -= height;
95
134
  }
96
- // console.groupEnd();
97
- })
98
- setPages(_pages);
99
- }
100
- }, [sectionsConfig]);
135
+ }
136
+
137
+ // Add padding to last section
138
+ if (isLast) {
139
+ ref.current.style.paddingBottom = `${BOTTOM_PADDING}px`;
140
+ }
141
+ });
142
+
143
+ setPages(_pages);
144
+ }, [sectionsConfig, config.length]);
101
145
 
102
146
  useEffect(() => {
103
147
  doSizing();
@@ -117,7 +161,7 @@ export default function PdfView({
117
161
  {config.map((widgets, i) => (
118
162
  <Row
119
163
  widgets={widgets}
120
- key={`dashboard-sections=${i + 1}`}
164
+ key={`dashboard-sections-${i + 1}`}
121
165
  i={i}
122
166
  onChangeHeight={onChangeHeight}
123
167
  />
@@ -128,23 +172,20 @@ export default function PdfView({
128
172
  );
129
173
  }, [config, onChangeHeight]);
130
174
 
131
- // <div className="daf-analysis">
132
- // <Header title={t('Dashboard Title')} />
133
-
134
- // <div className="content">
135
- // <div className="view-content">
136
- // <div className="daf-analysis-layout">
137
- // <div className='sections-cont w-pt'>
138
- // <section>
139
-
140
175
  return (
141
176
  <div className={contClassName} style={{ position: 'relative' }}>
142
177
  {renderDashboard()}
143
178
  {pages.map((page) => (
144
- <>
179
+ <div key={`page-${page}`}>
145
180
  <div
146
- style={{ top: ((page - 1) * PAGE_HEIGHT), width: '100%', height: HEADER_HEIGHT - 24, position: 'absolute', left: 0, zIndex: 1000000 }}
147
- key={`headers-${page}`}
181
+ style={{
182
+ top: ((page - 1) * PAGE_HEIGHT),
183
+ width: '100%',
184
+ height: HEADER_HEIGHT - 24,
185
+ position: 'absolute',
186
+ left: 0,
187
+ zIndex: 1000000
188
+ }}
148
189
  className="flex-row dashboard-header"
149
190
  >
150
191
  <div className="flex flex-column justify-center flex-1">
@@ -155,8 +196,14 @@ export default function PdfView({
155
196
  </div>
156
197
  </div>
157
198
  <div
158
- style={{ top: (page * PAGE_HEIGHT) - FOOTER_HEIGHT, width: '100%', height: FOOTER_HEIGHT, position: 'absolute', left: 0, zIndex: 1000000 }}
159
- key={`footers-${page}`}
199
+ style={{
200
+ top: (page * PAGE_HEIGHT) - FOOTER_HEIGHT,
201
+ width: '100%',
202
+ height: FOOTER_HEIGHT,
203
+ position: 'absolute',
204
+ left: 0,
205
+ zIndex: 1000000
206
+ }}
160
207
  className="dashboard-footer flex-row"
161
208
  >
162
209
  <div className="flex flex-column justify-center">
@@ -190,7 +237,7 @@ export default function PdfView({
190
237
  <h5>{page}</h5>
191
238
  </div>
192
239
  </div>
193
- </>
240
+ </div>
194
241
  ))}
195
242
  </div>
196
243
  );
@@ -204,4 +251,5 @@ PdfView.propTypes = {
204
251
  userId: PropTypes.string,
205
252
  accountId: PropTypes.string,
206
253
  documentId: PropTypes.string,
207
- }
254
+ downloadId: PropTypes.string,
255
+ }
@@ -8,31 +8,31 @@ import { formatClassname } from '../../../../../../helpers/ClassesHelper.js'
8
8
  const { useToken } = theme;
9
9
 
10
10
  const WidgetCard = ({
11
- title,
11
+ title,
12
12
  backgroundColor,
13
13
  backgroundBorderColor,
14
- data = [],
15
- link,
16
- logoIcon,
17
- description,
18
- loading = false,
19
- iconColor,
14
+ data = [],
15
+ link,
16
+ logoIcon,
17
+ description,
18
+ loading=false,
19
+ iconColor,
20
20
  buttonIcon,
21
21
  imageUrl,
22
22
  buttonConfig = {},
23
23
  width,
24
- t = () => { },
24
+ t = () => {},
25
25
  }) => {
26
26
  const { token } = useToken();
27
27
  return (
28
28
  <Style backgroundColor={backgroundColor} backgroundBorderColor={backgroundBorderColor} width={width}>
29
29
  <Widget
30
30
  title={
31
- <div style={{ display: "flex", alignItems: "center" }}>
32
- {imageUrl ? <img src={imageUrl} className="widget-card-logo-icon mr-2" />
31
+ <div style={{display: "flex", alignItems: "center"}}>
32
+ {imageUrl ? <img src={imageUrl} className="widget-card-logo-icon mr-2" />
33
33
  : <div className="widget-card-logo-icon mr-2">
34
34
  <CustomIcon name={logoIcon} width={25} height={25} />
35
- </div>
35
+ </div>
36
36
  }
37
37
  <Tooltip title={title}>{title}</Tooltip>
38
38
  </div>
@@ -41,41 +41,12 @@ const WidgetCard = ({
41
41
  <>
42
42
  <div className="flex-1" />
43
43
  <Tooltip title={buttonConfig?.disabled ? (buttonConfig?.tooltipText || t("Currently unavailable")) : ""}>
44
- <a
45
- className={formatClassname(["widget-card-logo-icon", buttonConfig?.disabled && "disabled-anchor"])}
44
+ <a
45
+ className={formatClassname(["widget-card-logo-icon", buttonConfig?.disabled && "disabled-anchor"])}
46
46
  href={buttonConfig?.disabled ? undefined : link}
47
- onClick={(e) => {
48
- if (buttonConfig?.disabled) {
49
- e.preventDefault();
50
- } else if (buttonConfig?.onClick) {
51
- e.preventDefault();
52
- buttonConfig.onClick();
53
- } else if (buttonConfig?.action) {
54
- e.preventDefault();
55
- // Handle different action types
56
- switch (buttonConfig.action.type) {
57
- case 'modal':
58
- if (buttonConfig.action.onOpen) {
59
- buttonConfig.action.onOpen();
60
- }
61
- break;
62
- case 'navigate':
63
- if (buttonConfig.action.url) {
64
- window.location.href = buttonConfig.action.url;
65
- }
66
- break;
67
- case 'custom':
68
- if (buttonConfig.action.handler) {
69
- buttonConfig.action.handler();
70
- }
71
- break;
72
- default:
73
- break;
74
- }
75
- }
76
- }}
47
+ onClick={buttonConfig?.disabled ? (e) => e.preventDefault() : undefined}
77
48
  >
78
- <CustomIcon name={buttonIcon} size={16} color={buttonConfig?.disabled ? "#6C737F" : (iconColor || theme.colorPrimary)} />
49
+ <CustomIcon name={buttonIcon} size={16} color={buttonConfig?.disabled ? "#6C737F" : (iconColor || theme.colorPrimary)} />
79
50
  </a>
80
51
  </Tooltip>
81
52
  </>
@@ -83,21 +54,21 @@ const WidgetCard = ({
83
54
  loading={loading}
84
55
  className="with-tabs no-pt-body"
85
56
  >
86
- <div style={{ display: "flex", flexDirection: "column", height: "100%", marginTop: "0px" }}>
57
+ <div style={{display: "flex", flexDirection: "column", height: "100%", marginTop: "0px"}}>
87
58
  <div style={{
88
59
  display: "flex",
89
60
  flexDirection: "column",
90
61
  justifyContent: "flex-start",
91
62
  marginTop: "10px",
92
63
  marginBottom: "24px",
93
- minHeight: "0"
64
+ minHeight: "0"
94
65
  }}>
95
66
  {description ? (
96
67
  <p style={{
97
- margin: 0,
68
+ margin: 0,
98
69
  height: "45px",
99
70
  display: "-webkit-box",
100
- WebkitLineClamp: 3,
71
+ WebkitLineClamp: 3,
101
72
  WebkitBoxOrient: "vertical",
102
73
  overflow: "hidden",
103
74
  textOverflow: "ellipsis",
@@ -108,16 +79,16 @@ const WidgetCard = ({
108
79
  {description.length > 100 ? <Tooltip title={description}>{description.substring(0, 100)}...</Tooltip> : description}
109
80
  </p>
110
81
  ) : (
111
- <div style={{ height: "45px" }} />
82
+ <div style={{height: "45px"}} />
112
83
  )}
113
84
  </div>
114
-
85
+
115
86
  {data && data.length > 0 && (
116
- <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
87
+ <div style={{display: "flex", flexDirection: "column", gap: "8px"}}>
117
88
  {data.map((item) => (
118
- <div key={item} style={{ display: "flex", justifyContent: "space-between" }}>
119
- {item.isTag ? <Tag style={{ width: '90px', textAlign: 'center', borderRadius: '10px' }} color={item.tagColor || 'default'}>{item.label}</Tag> : <span>{item.label}</span>}
120
- <span style={{ fontSize: '12px', color: '#6C737F' }}>{item.value}</span>
89
+ <div key={item} style={{display: "flex", justifyContent: "space-between"}}>
90
+ {item.isTag ? <Tag style={{width: '90px', textAlign: 'center', borderRadius: '10px'}} color={item.tagColor || 'default'}>{item.label}</Tag> : <span>{item.label}</span>}
91
+ <span style={{fontSize: '12px', color: '#6C737F'}}>{item.value}</span>
121
92
  </div>
122
93
  ))}
123
94
  </div>
@@ -192,4 +192,14 @@ export const splitStringInMultipleLines = (s, limit = 20) => {
192
192
  if (line) result += line;
193
193
 
194
194
  return result;
195
- }
195
+ }
196
+
197
+ export const safeJsonParse = (value, fallback = value) => {
198
+ if (typeof value !== 'string') return value;
199
+ try {
200
+ return JSON.parse(value);
201
+ } catch {
202
+ console.warn('Failed to parse JSON:', value);
203
+ return fallback;
204
+ }
205
+ };
package/src/utils.js CHANGED
@@ -9,7 +9,7 @@ export { renderTooltip, renderTooltipJsx } from './@daf/utils/tooltip'
9
9
  export { getRangeOfTicks } from './helpers/chart'
10
10
 
11
11
  export { propHasValue } from './helpers/deepFind'
12
- export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines } from './helpers/StringHelper'
12
+ export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines, safeJsonParse } from './helpers/StringHelper'
13
13
  export { getNkey, groupSubsections, getImageUploadViewValue } from './@daf/core/components/ViewForm/helper'
14
14
  export { renderRows } from './@daf/core/components/Table/helper'
15
15
  export { filterOptions, filterString, hasNotChanged, filterSelectOptions, mapSubGroupsInSubmit, mapSubGroupsInGet, filterCreateData, changeInputMeta, renderDateFormatted } from './helpers/Forms'
@@ -1,330 +0,0 @@
1
- /* Isolated Mapbox GL CSS - Scoped to prevent Leaflet conflicts */
2
-
3
- /* Mapbox GL Core Styles - Scoped with .mapbox-gl-scope */
4
- .mapbox-gl-scope .mapboxgl-map {
5
- font: 12px/20px Helvetica Neue, Arial, Helvetica, sans-serif;
6
- overflow: hidden;
7
- position: relative;
8
- -webkit-tap-highlight-color: rgb(0 0 0/0);
9
- }
10
-
11
- .mapbox-gl-scope .mapboxgl-canvas {
12
- left: 0;
13
- position: absolute;
14
- top: 0;
15
- }
16
-
17
- .mapbox-gl-scope .mapboxgl-map:-webkit-full-screen {
18
- height: 100%;
19
- width: 100%;
20
- }
21
-
22
- .mapbox-gl-scope .mapboxgl-canary {
23
- background-color: salmon;
24
- }
25
-
26
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-interactive,
27
- .mapbox-gl-scope .mapboxgl-ctrl-group button.mapboxgl-ctrl-compass {
28
- cursor: grab;
29
- -webkit-user-select: none;
30
- user-select: none;
31
- }
32
-
33
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-interactive.mapboxgl-track-pointer {
34
- cursor: pointer;
35
- }
36
-
37
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-interactive:active,
38
- .mapbox-gl-scope .mapboxgl-ctrl-group button.mapboxgl-ctrl-compass:active {
39
- cursor: grabbing;
40
- }
41
-
42
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate,
43
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate .mapboxgl-canvas {
44
- touch-action: pan-x pan-y;
45
- }
46
-
47
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-drag-pan,
48
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-drag-pan .mapboxgl-canvas {
49
- touch-action: pinch-zoom;
50
- }
51
-
52
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan,
53
- .mapbox-gl-scope .mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan .mapboxgl-canvas {
54
- touch-action: none;
55
- }
56
-
57
- /* Control positioning */
58
- .mapbox-gl-scope .mapboxgl-ctrl-bottom,
59
- .mapbox-gl-scope .mapboxgl-ctrl-bottom-left,
60
- .mapbox-gl-scope .mapboxgl-ctrl-bottom-right,
61
- .mapbox-gl-scope .mapboxgl-ctrl-left,
62
- .mapbox-gl-scope .mapboxgl-ctrl-right,
63
- .mapbox-gl-scope .mapboxgl-ctrl-top,
64
- .mapbox-gl-scope .mapboxgl-ctrl-top-left,
65
- .mapbox-gl-scope .mapboxgl-ctrl-top-right {
66
- pointer-events: none;
67
- position: absolute;
68
- z-index: 2;
69
- }
70
-
71
- .mapbox-gl-scope .mapboxgl-ctrl-top-left {
72
- left: 0;
73
- top: 0;
74
- }
75
-
76
- .mapbox-gl-scope .mapboxgl-ctrl-top {
77
- left: 50%;
78
- top: 0;
79
- transform: translateX(-50%);
80
- }
81
-
82
- .mapbox-gl-scope .mapboxgl-ctrl-top-right {
83
- right: 0;
84
- top: 0;
85
- }
86
-
87
- .mapbox-gl-scope .mapboxgl-ctrl-right {
88
- right: 0;
89
- top: 50%;
90
- transform: translateY(-50%);
91
- }
92
-
93
- .mapbox-gl-scope .mapboxgl-ctrl-bottom-right {
94
- bottom: 0;
95
- right: 0;
96
- }
97
-
98
- .mapbox-gl-scope .mapboxgl-ctrl-bottom {
99
- bottom: 0;
100
- left: 50%;
101
- transform: translateX(-50%);
102
- }
103
-
104
- .mapbox-gl-scope .mapboxgl-ctrl-bottom-left {
105
- bottom: 0;
106
- left: 0;
107
- }
108
-
109
- .mapbox-gl-scope .mapboxgl-ctrl-left {
110
- left: 0;
111
- top: 50%;
112
- transform: translateY(-50%);
113
- }
114
-
115
- .mapbox-gl-scope .mapboxgl-ctrl {
116
- clear: both;
117
- pointer-events: auto;
118
- transform: translate(0);
119
- }
120
-
121
- .mapbox-gl-scope .mapboxgl-ctrl-top-left .mapboxgl-ctrl {
122
- float: left;
123
- margin: 10px 0 0 10px;
124
- }
125
-
126
- .mapbox-gl-scope .mapboxgl-ctrl-top .mapboxgl-ctrl {
127
- float: left;
128
- margin: 10px 0;
129
- }
130
-
131
- .mapbox-gl-scope .mapboxgl-ctrl-top-right .mapboxgl-ctrl {
132
- float: right;
133
- margin: 10px 10px 0 0;
134
- }
135
-
136
- .mapbox-gl-scope .mapboxgl-ctrl-bottom-right .mapboxgl-ctrl,
137
- .mapbox-gl-scope .mapboxgl-ctrl-right .mapboxgl-ctrl {
138
- float: right;
139
- margin: 0 10px 10px 0;
140
- }
141
-
142
- .mapbox-gl-scope .mapboxgl-ctrl-bottom .mapboxgl-ctrl {
143
- float: left;
144
- margin: 10px 0;
145
- }
146
-
147
- .mapbox-gl-scope .mapboxgl-ctrl-bottom-left .mapboxgl-ctrl,
148
- .mapbox-gl-scope .mapboxgl-ctrl-left .mapboxgl-ctrl {
149
- float: left;
150
- margin: 0 0 10px 10px;
151
- }
152
-
153
- /* Control group styling */
154
- .mapbox-gl-scope .mapboxgl-ctrl-group {
155
- background: #fff;
156
- border-radius: 4px;
157
- }
158
-
159
- .mapbox-gl-scope .mapboxgl-ctrl-group:not(:empty) {
160
- box-shadow: 0 0 0 2px #0000001a;
161
- }
162
-
163
- .mapbox-gl-scope .mapboxgl-ctrl-group button {
164
- background-color: initial;
165
- border: 0;
166
- box-sizing: border-box;
167
- cursor: pointer;
168
- display: block;
169
- height: 29px;
170
- outline: none;
171
- overflow: hidden;
172
- padding: 0;
173
- width: 29px;
174
- }
175
-
176
- .mapbox-gl-scope .mapboxgl-ctrl-group button+button {
177
- border-top: 1px solid #ddd;
178
- }
179
-
180
- .mapbox-gl-scope .mapboxgl-ctrl button .mapboxgl-ctrl-icon {
181
- background-position: 50%;
182
- background-repeat: no-repeat;
183
- display: block;
184
- height: 100%;
185
- width: 100%;
186
- }
187
-
188
- .mapbox-gl-scope .mapboxgl-ctrl-attrib-button:focus,
189
- .mapbox-gl-scope .mapboxgl-ctrl-group button:focus {
190
- box-shadow: 0 0 2px 2px #0096ff;
191
- }
192
-
193
- .mapbox-gl-scope .mapboxgl-ctrl button:disabled {
194
- cursor: not-allowed;
195
- }
196
-
197
- .mapbox-gl-scope .mapboxgl-ctrl button:disabled .mapboxgl-ctrl-icon {
198
- opacity: .25;
199
- }
200
-
201
- .mapbox-gl-scope .mapboxgl-ctrl-group button:first-child {
202
- border-radius: 4px 4px 0 0;
203
- }
204
-
205
- .mapbox-gl-scope .mapboxgl-ctrl-group button:last-child {
206
- border-radius: 0 0 4px 4px;
207
- }
208
-
209
- .mapbox-gl-scope .mapboxgl-ctrl-group button:only-child {
210
- border-radius: inherit;
211
- }
212
-
213
- .mapbox-gl-scope .mapboxgl-ctrl button:not(:disabled):hover {
214
- background-color: #0000000d;
215
- }
216
-
217
- /* Marker styles */
218
- .mapbox-gl-scope .mapboxgl-marker {
219
- position: absolute;
220
- z-index: 1;
221
- }
222
-
223
- .mapbox-gl-scope .mapboxgl-marker svg {
224
- display: block;
225
- }
226
-
227
- /* Popup styles */
228
- .mapbox-gl-scope .mapboxgl-popup {
229
- position: absolute;
230
- text-align: center;
231
- margin-bottom: 20px;
232
- }
233
-
234
- .mapbox-gl-scope .mapboxgl-popup-content-wrapper {
235
- padding: 1px;
236
- text-align: left;
237
- border-radius: 12px;
238
- }
239
-
240
- .mapbox-gl-scope .mapboxgl-popup-content {
241
- margin: 13px 24px 13px 20px;
242
- line-height: 1.3;
243
- font-size: 13px;
244
- min-height: 1px;
245
- }
246
-
247
- .mapbox-gl-scope .mapboxgl-popup-content p {
248
- margin: 17px 0;
249
- }
250
-
251
- .mapbox-gl-scope .mapboxgl-popup-tip-container {
252
- width: 40px;
253
- height: 20px;
254
- position: absolute;
255
- left: 50%;
256
- margin-top: -1px;
257
- margin-left: -20px;
258
- overflow: hidden;
259
- pointer-events: none;
260
- }
261
-
262
- .mapbox-gl-scope .mapboxgl-popup-tip {
263
- width: 17px;
264
- height: 17px;
265
- padding: 1px;
266
- margin: -10px auto 0;
267
- pointer-events: auto;
268
- -webkit-transform: rotate(45deg);
269
- -moz-transform: rotate(45deg);
270
- -ms-transform: rotate(45deg);
271
- transform: rotate(45deg);
272
- }
273
-
274
- .mapbox-gl-scope .mapboxgl-popup-content-wrapper,
275
- .mapbox-gl-scope .mapboxgl-popup-tip {
276
- background: white;
277
- color: #333;
278
- box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);
279
- }
280
-
281
- .mapbox-gl-scope .mapboxgl-popup-close-button {
282
- position: absolute;
283
- top: 0;
284
- right: 0;
285
- border: none;
286
- text-align: center;
287
- width: 24px;
288
- height: 24px;
289
- font: 16px/24px Tahoma, Verdana, sans-serif;
290
- color: #757575;
291
- text-decoration: none;
292
- background: transparent;
293
- }
294
-
295
- .mapbox-gl-scope .mapboxgl-popup-close-button:hover,
296
- .mapbox-gl-scope .mapboxgl-popup-close-button:focus {
297
- color: #585858;
298
- }
299
-
300
- /* Attribution */
301
- .mapbox-gl-scope .mapboxgl-ctrl-attribution {
302
- background: #fff;
303
- background: rgba(255, 255, 255, 0.8);
304
- margin: 0;
305
- }
306
-
307
- .mapbox-gl-scope .mapboxgl-ctrl-attribution,
308
- .mapbox-gl-scope .mapboxgl-ctrl-scale-line {
309
- padding: 0 5px;
310
- color: #333;
311
- line-height: 1.4;
312
- }
313
-
314
- .mapbox-gl-scope .mapboxgl-ctrl-attribution a {
315
- text-decoration: none;
316
- }
317
-
318
- .mapbox-gl-scope .mapboxgl-ctrl-attribution a:hover,
319
- .mapbox-gl-scope .mapboxgl-ctrl-attribution a:focus {
320
- text-decoration: underline;
321
- }
322
-
323
- /* Hide attribution by default */
324
- .mapbox-gl-scope .mapboxgl-ctrl-attribution {
325
- display: none !important;
326
- }
327
-
328
- .mapbox-gl-scope .mapboxgl-ctrl-logo {
329
- display: none !important;
330
- }