datastake-daf 0.6.183 → 0.6.185

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.183",
3
+ "version": "0.6.185",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -15,7 +15,7 @@
15
15
  "buffer": "^6.0.3",
16
16
  "countries-list": "^2.6.1",
17
17
  "country-city-location": "^1.0.13",
18
- "datastake-daf": "^0.5.780",
18
+ "datastake-daf": "0.6.184",
19
19
  "dayjs": "^1.11.12",
20
20
  "deepmerge": "^4.3.1",
21
21
  "dot-object": "^2.1.5",
@@ -8,6 +8,7 @@ import CustomIcon from "../../Icon/CustomIcon.jsx";
8
8
  import ComponentWithFocus from "../ComponentWithFocus/index.jsx";
9
9
  import { formatClassname } from "../../../../../helpers/ClassesHelper";
10
10
  import Filters from "../../Filters/FloatingFilters/index.js";
11
+ import { useResizeContext } from "../../../context/Resize/index.js";
11
12
 
12
13
  /**
13
14
  * Globe Component
@@ -129,6 +130,9 @@ function Globe({
129
130
  [data],
130
131
  );
131
132
 
133
+ // Get resize context for sidebar state changes
134
+ const { isCollapsed } = useResizeContext();
135
+
132
136
  // Use custom hook to configure globe functionality
133
137
  const { container, activeMarker, mapOptionsButtonsConfig, forceResize } = useGlobe({
134
138
  data: mappedData,
@@ -171,6 +175,36 @@ function Globe({
171
175
  }
172
176
  }, [forceResize]);
173
177
 
178
+ // Force resize when sidebar state changes (handles width changes)
179
+ useEffect(() => {
180
+ if (forceResize) {
181
+ // Trigger resize when sidebar collapses/expands
182
+ const timer = setTimeout(() => {
183
+ forceResize();
184
+ }, 100);
185
+
186
+ return () => clearTimeout(timer);
187
+ }
188
+ }, [isCollapsed, forceResize]);
189
+
190
+ // Add window resize listener as backup
191
+ useEffect(() => {
192
+ const handleWindowResize = () => {
193
+ if (forceResize) {
194
+ // Small delay to ensure DOM has updated
195
+ setTimeout(() => {
196
+ forceResize();
197
+ }, 100);
198
+ }
199
+ };
200
+
201
+ window.addEventListener('resize', handleWindowResize);
202
+
203
+ return () => {
204
+ window.removeEventListener('resize', handleWindowResize);
205
+ };
206
+ }, [forceResize]);
207
+
174
208
  return (
175
209
  <ComponentWithFocus>
176
210
  <Style className={formatClassname([showSider && activeMarker && "with-sider"])}>
@@ -5,7 +5,8 @@ const Style = styled.div`
5
5
  flex-direction: row;
6
6
  position: relative;
7
7
  width: 100%;
8
- height: 472px;
8
+ height: 100%;
9
+ min-height: 400px;
9
10
 
10
11
  .filter-cont {
11
12
  position: absolute;
@@ -96,6 +97,8 @@ const Style = styled.div`
96
97
  flex: 1;
97
98
  background: rgb(0, 0, 0);
98
99
  z-index: 1;
100
+ width: 100%;
101
+ height: 100%;
99
102
 
100
103
  /* Mapbox GL JS specific styles */
101
104
  .mapboxgl-ctrl-top-right {
@@ -0,0 +1,38 @@
1
+ import ExcelTest from "./index";
2
+ import ThemeLayout from "../ThemeLayout";
3
+ import { storyData } from "./storyconfig";
4
+ import PlanningDemo from "./planningDemo";
5
+
6
+ export default {
7
+ title: "Core/ExcelTest",
8
+ component: ExcelTest,
9
+ tags: ["autodocs"],
10
+ decorators: [
11
+ (Story) => (
12
+ <div style={{ margin: "2em" }}>
13
+ <ThemeLayout>
14
+ <Story />
15
+ </ThemeLayout>
16
+ </div>
17
+ ),
18
+ ],
19
+ };
20
+
21
+ export const Primary = {
22
+ name: "Form Test Default",
23
+ args: {
24
+ // Add any props your component needs here
25
+ // Currently your component doesn't accept props but you might want to pass data
26
+ },
27
+ };
28
+
29
+ export const Planning = {
30
+ name: "Planning Configuration",
31
+ render: () => (
32
+ <div style={{ margin: "2em" }}>
33
+ <ThemeLayout>
34
+ <PlanningDemo />
35
+ </ThemeLayout>
36
+ </div>
37
+ ),
38
+ };
@@ -0,0 +1,254 @@
1
+ import { showHideInput } from "../ViewForm/helper";
2
+ import { renderDateFormatted } from "../../../../helpers/Forms";
3
+
4
+
5
+ // Helper function to format references - show only one line to distinguish each
6
+ const formatReferences = (description) => {
7
+ if (!description) return "";
8
+ return description.split("<br>")
9
+ .filter(line => line.trim())
10
+ .map(line => line.trim().replace(/^-+\s*/, '')) // Remove existing dashes
11
+ .filter(line => line) // Remove empty lines
12
+ .join("\n"); // Single line separation
13
+ };
14
+
15
+ // Helper function to format comments
16
+ const formatComments = (comments) => {
17
+ if (!comments || !Array.isArray(comments)) return "";
18
+ return comments.map(comment => `- ${comment.text || comment.description || ""}`).join("\n");
19
+ };
20
+
21
+ // Helper function to format verification method - remove <br> and add appropriate separators
22
+ const formatVerificationMethod = (description, forCSV = false) => {
23
+ if (!description) return "";
24
+ const lines = description.split("<br>")
25
+ .filter(line => line.trim())
26
+ .map(line => line.trim());
27
+
28
+ // For CSV export, use semicolon separator to avoid newline issues
29
+ if (forCSV) {
30
+ return lines.join("; ");
31
+ }
32
+
33
+ // For display, use newlines
34
+ return lines.join("\n");
35
+ };
36
+
37
+ // Helper function to get description by language
38
+ const getDescriptionByLanguage = (descriptions, language = "en") => {
39
+ if (!descriptions) return "";
40
+ return descriptions[language] || descriptions.en || descriptions.sp || descriptions.fr || "";
41
+ };
42
+
43
+ const getAspectToVerify = (form, sectionKey, kidPosition, country) => {
44
+ const titlesSection = form?.titles?.[sectionKey];
45
+ if (!titlesSection) return "";
46
+
47
+ const matchingTitles = Object.keys(titlesSection)
48
+ .filter(key => key.startsWith('title'))
49
+ .map(key => titlesSection[key])
50
+ .filter(title => {
51
+ if (!title.showIf) return false;
52
+ const condition = title.showIf.toLowerCase();
53
+ if (condition.includes('country is')) {
54
+ const requiredCountry = condition.replace('country is', '').trim();
55
+ return country && country.toLowerCase() === requiredCountry.toLowerCase();
56
+ }
57
+ return true;
58
+ })
59
+ .sort((a, b) => (a.position || 0) - (b.position || 0));
60
+
61
+ if (matchingTitles.length === 0) return "";
62
+
63
+ let selectedTitle = matchingTitles[0];
64
+
65
+ for (let i = 0; i < matchingTitles.length; i++) {
66
+ const titlePosition = matchingTitles[i].position || 0;
67
+ if (titlePosition <= kidPosition) {
68
+ selectedTitle = matchingTitles[i];
69
+ } else {
70
+ break;
71
+ }
72
+ }
73
+
74
+
75
+ const label = selectedTitle?.label || "";
76
+ return label.replace(/\\"/g, '"').replace(/\n/g, " ").replace(/\r/g, " ").replace(/\t/g, " ").trim();
77
+ };
78
+
79
+ export const fixDataForExcel = (originalData, stepParam = 1, module = "", t = (key) => key) => {
80
+ const {form, data} = originalData;
81
+ const language = data?.user?.language || "en";
82
+ const step = Number(stepParam);
83
+ // Table 1 data - Basic Information (vertical key-value format)
84
+ const table1Data = [
85
+ { key: t('mine'), value: data?.location?.name || "" },
86
+ { key: t('module'), value: module },
87
+ { key: t('sources'), value: "" }, // Leave blank as requested
88
+ { key: t('version'), value: data?.version || data?.location?.version || "" },
89
+ { key: t('date'), value: renderDateFormatted(new Date().toISOString(), 'DD MMM YYYY', (language === 'sp' ? 'es' : language) || 'en') } // Current date in YYYY-MM-DD format
90
+ ];
91
+
92
+ console.log("Table 1 Data:", table1Data);
93
+
94
+ // Table 2 data - Detailed Evaluation Data
95
+ const table2Data = [];
96
+
97
+ const sections = (form?.identification?.category?.options || [])?.map((option) => ({
98
+ group: option.label,
99
+ key: option.value,
100
+ criterias: (form?.identification?.subCategory?.options || [])
101
+ .filter((_option) => {
102
+ const categoryFilter = _option?.filters?.find((f) => f.name === "category");
103
+ const stepFilter = _option?.filters?.find((f) => f.name === "step");
104
+
105
+ return (
106
+ (stepFilter?.value || 1) === step &&
107
+ (categoryFilter?.value || []).includes(option.value) &&
108
+ !!(data?.criteria || []).find(
109
+ (c) => c.subCategory === _option.value,
110
+ )
111
+ );
112
+ })
113
+ .map((_option) => {
114
+ const _criteria = (data?.criteria || []).find(
115
+ (c) => c.subCategory === _option.value,
116
+ );
117
+ const subCategoryForm = form[_criteria.subCategory];
118
+
119
+ const kids = Object.keys(subCategoryForm)
120
+ .filter((k) => {
121
+ const val = subCategoryForm[k];
122
+ if (val.showIf) {
123
+ const show = showHideInput(val, data);
124
+ return show;
125
+ }
126
+ return val?.type === "group";
127
+ })
128
+ .sort((a, b) => {
129
+ const valA = subCategoryForm[a];
130
+ const valB = subCategoryForm[b];
131
+ return valA?.position - valB?.position;
132
+ })
133
+ .map((k) => {
134
+ const formVal = subCategoryForm[k];
135
+ const evalData = _criteria[k];
136
+ const meta = (_criteria?.meta?.inputs || {})[k];
137
+
138
+ // Get reference description from form object description field
139
+ const referenceDescription = formVal.description || "";
140
+
141
+ // Get verification method from form meta
142
+ const verificationMethod = getDescriptionByLanguage(
143
+ formVal?.meta?.groupInfo?.description,
144
+ language
145
+ );
146
+
147
+ return {
148
+ key: k,
149
+ group: option.value,
150
+ criteria: formVal.label,
151
+ position: formVal.position || 0, // Include position for title mapping
152
+ lastUpdate: _criteria.updatedAt,
153
+ meta,
154
+ referenceDescription,
155
+ verificationMethod,
156
+ ...evalData,
157
+ };
158
+ });
159
+
160
+ return {
161
+ key: _option.value,
162
+ group: option.value,
163
+ criteria: _option.label,
164
+ completion: _criteria.completion,
165
+ evaluationScore: _criteria.evaluationScore,
166
+ description: (form?.identification?.dscription?.options || []).find(
167
+ (d) => d.value === _option.value,
168
+ )?.label || "-",
169
+ lastUpdate: _criteria.updatedAt,
170
+ kids,
171
+ };
172
+ })
173
+ }));
174
+
175
+ // Process sections to create table 2 data
176
+ sections.forEach((section) => {
177
+ section.criterias.forEach((criteria) => {
178
+ criteria.kids.forEach((kid) => {
179
+ const row = {
180
+ stage: `0${step}`,
181
+ aspect: section.group, // From sections group
182
+ criteria: criteria.criteria, // From criterias -> criteria key
183
+ aspectToVerify: getAspectToVerify(form, criteria.key, kid.position, data?.location?.country), // Get from titles based on showIf condition and actual kid position
184
+ reference: formatReferences(kid.referenceDescription), // Format references properly
185
+ subcriteria: kid.criteria, // From kids -> criteria key
186
+ verificationMethod: formatVerificationMethod(kid.verificationMethod || ""), // Remove <br> and add newlines
187
+ valuation: (kid?.valuation === 'na' ? 'N/A' : `${kid.valuation}%`) ?? "", // Add % formatting
188
+ comments: formatComments(kid.comment), // Format comments with - on each line
189
+ totalValuation: (criteria?.evaluationScore === 'na' ? 'N/A' : `${criteria.evaluationScore}%`) ?? "" // Add % formatting
190
+ };
191
+ table2Data.push(row);
192
+ });
193
+ });
194
+ });
195
+
196
+ console.log("Table 2 Data:", table2Data);
197
+ console.log("Sections:", sections);
198
+
199
+ return {
200
+ table1: table1Data,
201
+ table2: table2Data,
202
+ sections: sections
203
+ };
204
+ };
205
+
206
+
207
+ export const exportToCSV = (data, filename = "evaluation_data.csv", t = (key) => key) => {
208
+ const { table1, table2 } = data;
209
+
210
+ let csvContent = "";
211
+
212
+ // Add Table 1 data (vertical key-value format, no title)
213
+ table1.forEach(item => {
214
+ csvContent += `"${item.key}","${item.value}"\n`;
215
+ });
216
+ csvContent += "\n"; // Empty line separator
217
+
218
+ // Add Table 2 header and data (no title, use translation function for headers)
219
+ csvContent += `"${t('stage')}","${t('aspect')}","${t('criteria')}","${t('aspectToVerify')}","${t('reference')}","${t('subcriteria')}","${t('verificationMethod')}","${t('valuation')}","${t('comments')}","${t('totalValuation')}"\n`;
220
+
221
+ table2.forEach(row => {
222
+ const csvRow = [
223
+ row.stage,
224
+ row.aspect,
225
+ row.criteria,
226
+ (row.aspectToVerify || "").replace(/"/g, '""'), // Escape quotes properly
227
+ (row.reference || "").replace(/"/g, '""'), // Escape quotes
228
+ row.subcriteria,
229
+ formatVerificationMethod(row.verificationMethod || "", true).replace(/"/g, '""'), // Format for CSV and escape quotes
230
+ row.valuation,
231
+ (row.comments || "").replace(/"/g, '""'), // Escape quotes
232
+ row.totalValuation
233
+ ].map(field => `"${field}"`).join(",");
234
+
235
+ csvContent += csvRow + "\n";
236
+ });
237
+
238
+ return csvContent;
239
+ };
240
+
241
+ // Utility function to download CSV file
242
+ export const downloadCSV = (data, filename = "evaluation_data.csv", t = (key) => key) => {
243
+ const csvContent = exportToCSV(data, filename, t);
244
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
245
+ const link = document.createElement("a");
246
+ const url = URL.createObjectURL(blob);
247
+
248
+ link.setAttribute("href", url);
249
+ link.setAttribute("download", filename);
250
+ link.style.visibility = 'hidden';
251
+ document.body.appendChild(link);
252
+ link.click();
253
+ document.body.removeChild(link);
254
+ };
@@ -0,0 +1,139 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { storyData } from './storyconfig'
3
+ import { fixDataForExcel, downloadCSV } from './config'
4
+
5
+ function ExcelTest() {
6
+ const [excelData, setExcelData] = useState(null);
7
+
8
+ // Simple translation function for testing
9
+ const t = (key) => {
10
+ const translations = {
11
+ mine: "Mine",
12
+ module: "Module",
13
+ sources: "Sources",
14
+ version: "Version",
15
+ date: "Date",
16
+ stage: "Stage",
17
+ aspect: "Aspect",
18
+ criteria: "Criteria",
19
+ aspectToVerify: "Aspect to Verify",
20
+ reference: "Reference",
21
+ subcriteria: "Subcriteria",
22
+ verificationMethod: "Verification Method",
23
+ valuation: "Valuation",
24
+ comments: "Comments",
25
+ totalValuation: "Total Valuation"
26
+ };
27
+ return translations[key] || key;
28
+ };
29
+
30
+ useEffect(() => {
31
+ // Test the function with sample parameters including translation function
32
+ const response = fixDataForExcel(storyData, 1, "Sample Module", t);
33
+ setExcelData(response);
34
+ console.log("Excel Data Generated:", response);
35
+ }, []);
36
+
37
+ return (
38
+ <div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
39
+ <h1>Form Test - Excel Data Mapping</h1>
40
+
41
+ {excelData && (
42
+ <>
43
+ <div style={{ marginBottom: '20px' }}>
44
+ <button
45
+ onClick={() => downloadCSV(excelData, 'evaluation_data.csv', t)}
46
+ style={{
47
+ backgroundColor: '#4CAF50',
48
+ color: 'white',
49
+ padding: '10px 20px',
50
+ border: 'none',
51
+ borderRadius: '4px',
52
+ cursor: 'pointer',
53
+ fontSize: '16px'
54
+ }}
55
+ >
56
+ 📥 Download as CSV
57
+ </button>
58
+ <p style={{ marginTop: '5px', color: '#666', fontSize: '14px' }}>
59
+ Click to download the data as CSV file for Excel import
60
+ <br />
61
+ <strong>Note:</strong> For duplicate values (like same Stage), manually merge cells in Excel after import.
62
+ </p>
63
+ </div>
64
+
65
+ </>
66
+ )}
67
+
68
+ {excelData && (
69
+ <>
70
+ <h2>Basic Information</h2>
71
+ <div style={{ marginBottom: '30px' }}>
72
+ <table border="1" style={{ borderCollapse: 'collapse', width: '50%' }}>
73
+ <thead>
74
+ <tr>
75
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>Field</th>
76
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>Value</th>
77
+ </tr>
78
+ </thead>
79
+ <tbody>
80
+ {excelData.table1.map((item, index) => (
81
+ <tr key={index}>
82
+ <td style={{ padding: '8px', fontWeight: 'bold' }}>{item.key}</td>
83
+ <td style={{ padding: '8px' }}>{item.value}</td>
84
+ </tr>
85
+ ))}
86
+ </tbody>
87
+ </table>
88
+ </div>
89
+
90
+ <h2>Detailed Evaluation Data</h2>
91
+ <div style={{ overflowX: 'auto' }}>
92
+ <table border="1" style={{ borderCollapse: 'collapse', width: '100%', minWidth: '1200px' }}>
93
+ <thead>
94
+ <tr>
95
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('stage')}</th>
96
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('aspect')}</th>
97
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('criteria')}</th>
98
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('aspectToVerify')}</th>
99
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('reference')}</th>
100
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('subcriteria')}</th>
101
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('verificationMethod')}</th>
102
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('valuation')}</th>
103
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('comments')}</th>
104
+ <th style={{ padding: '8px', backgroundColor: '#f5f5f5' }}>{t('totalValuation')}</th>
105
+ </tr>
106
+ </thead>
107
+ <tbody>
108
+ {excelData.table2.map((row, index) => (
109
+ <tr key={index}>
110
+ <td style={{ padding: '8px' }}>{row.stage}</td>
111
+ <td style={{ padding: '8px' }}>{row.aspect}</td>
112
+ <td style={{ padding: '8px' }}>{row.criteria}</td>
113
+ <td style={{ padding: '8px' }}>{row.aspectToVerify}</td>
114
+ <td style={{ padding: '8px', whiteSpace: 'pre-line' }}>{row.reference}</td>
115
+ <td style={{ padding: '8px' }}>{row.subcriteria}</td>
116
+ <td style={{ padding: '8px', whiteSpace: 'pre-line' }}>{row.verificationMethod}</td>
117
+ <td style={{ padding: '8px' }}>{row.valuation}</td>
118
+ <td style={{ padding: '8px', whiteSpace: 'pre-line' }}>{row.comments}</td>
119
+ <td style={{ padding: '8px' }}>{row.totalValuation}</td>
120
+ </tr>
121
+ ))}
122
+ </tbody>
123
+ </table>
124
+ </div>
125
+
126
+ <h3>Debug Information</h3>
127
+ <details style={{ marginTop: '20px' }}>
128
+ <summary>Raw Data Structure</summary>
129
+ <pre style={{ background: '#f5f5f5', padding: '10px', overflow: 'auto', maxHeight: '400px' }}>
130
+ {JSON.stringify(excelData, null, 2)}
131
+ </pre>
132
+ </details>
133
+ </>
134
+ )}
135
+ </div>
136
+ )
137
+ }
138
+
139
+ export default ExcelTest