datastake-daf 0.6.826 → 0.6.827

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.
@@ -55413,14 +55413,19 @@ const PlantingActivitiesTimeline = ({
55413
55413
  const dataToProcess = !activitiesTimelineChart || !Array.isArray(activitiesTimelineChart) || activitiesTimelineChart.length === 0 ? [] : activitiesTimelineChart;
55414
55414
 
55415
55415
  // Process data without cumulative calculation (for activities timeline)
55416
- return processChartDateData({
55416
+ const processedData = processChartDateData({
55417
55417
  mainData: dataToProcess,
55418
55418
  isCumulative: false,
55419
55419
  valueField: 'count'
55420
55420
  });
55421
- }, [activitiesTimelineChart, processChartDateData]);
55422
55421
 
55423
- // Calculate max value for Y-axis (default to 100 if all values are 0 or very small)
55422
+ // Remove trailing periods with 0 jobs (optional: remove all zero if you prefer)
55423
+ let lastNonZeroIndex = processedData.length - 1;
55424
+ while (lastNonZeroIndex >= 0 && (processedData[lastNonZeroIndex].jobs || 0) === 0) {
55425
+ lastNonZeroIndex--;
55426
+ }
55427
+ return processedData.slice(0, lastNonZeroIndex + 1);
55428
+ }, [activitiesTimelineChart, processChartDateData]);
55424
55429
  const maxActivitiesYValue = React.useMemo(() => {
55425
55430
  if (!activitiesTimelineData || activitiesTimelineData.length === 0) {
55426
55431
  return 100;
@@ -55765,6 +55770,29 @@ const CyclePartners = ({
55765
55770
  });
55766
55771
  };
55767
55772
 
55773
+ // Custom tooltip labels per field/value
55774
+ const FIELD_TOOLTIP_LABELS = {
55775
+ aidKitAccessible: {
55776
+ compliant: "Available",
55777
+ notCompliant: "Not available",
55778
+ empty: "No data"
55779
+ },
55780
+ hsTrainingConfirmation: {
55781
+ compliant: "Training delivered",
55782
+ notCompliant: "No training",
55783
+ empty: "No data"
55784
+ },
55785
+ duosFormed: {
55786
+ compliant: "Duos formed",
55787
+ notCompliant: "Not implemented",
55788
+ empty: "No data"
55789
+ },
55790
+ presenceOfChildren: {
55791
+ compliant: "None reported",
55792
+ notCompliant: "Children present",
55793
+ empty: "No data"
55794
+ }
55795
+ };
55768
55796
  const HEALTH_SAFETY_COLORS = {
55769
55797
  compliant: '#016C6E',
55770
55798
  notCompliant: '#F97066',
@@ -55776,12 +55804,6 @@ const getIndicatorType$1 = value => {
55776
55804
  if (value === null || value === undefined) return "empty";
55777
55805
  return "empty";
55778
55806
  };
55779
-
55780
- /**
55781
- * Gets health and safety distribution data from activity data
55782
- * @param {Object} activityData - Activity data object
55783
- * @returns {Object} Distribution object with compliant, notCompliant, and empty counts
55784
- */
55785
55807
  const getHealthAndSafetyDistributionData = activityData => {
55786
55808
  // Define health and safety indicator fields
55787
55809
  const indicators = [{
@@ -55817,53 +55839,26 @@ const getHealthAndSafetyDistributionData = activityData => {
55817
55839
  });
55818
55840
  return distribution;
55819
55841
  };
55820
-
55821
- /**
55822
- * Checks if the health and safety distribution data is empty
55823
- * @param {Object} healthAndSafetyDistributionData - Distribution object
55824
- * @returns {boolean} True if all values are 0 or empty
55825
- */
55826
55842
  const isHealthAndSafetyDistributionEmpty = healthAndSafetyDistributionData => {
55827
55843
  return Object.values(healthAndSafetyDistributionData).every(val => !val || val === 0);
55828
55844
  };
55829
-
55830
- /**
55831
- * Calculates pie chart data from health and safety distribution
55832
- * @param {Object} healthAndSafetyDistributionData - Distribution object
55833
- * @param {Function} t - Translation function
55834
- * @returns {Array} Array of pie chart data points with value, percent, color, label, and key
55835
- */
55836
- const calculateHealthAndSafetyPieData = (healthAndSafetyDistributionData, t) => {
55837
- const total = Object.values(healthAndSafetyDistributionData).reduce((all, val) => all + (val || 0), 0);
55845
+ const calculateHealthAndSafetyPieData = (data, t, selectedField) => {
55846
+ const total = Object.values(data).reduce((a, v) => a + (v || 0), 0);
55838
55847
  const labels = {
55839
55848
  compliant: t("Available"),
55840
55849
  notCompliant: t("Not available"),
55841
55850
  empty: t("Not answered")
55842
55851
  };
55843
- return Object.keys(healthAndSafetyDistributionData).map(key => {
55844
- const color = HEALTH_SAFETY_COLORS[key] || '#D9D9D9';
55845
- return {
55846
- value: healthAndSafetyDistributionData[key] || 0,
55847
- percent: total > 0 ? (healthAndSafetyDistributionData[key] || 0) / total : 0,
55848
- color: color,
55849
- label: labels[key] || key,
55850
- key: key
55851
- };
55852
- });
55852
+ return Object.keys(data).map(key => ({
55853
+ value: data[key] || 0,
55854
+ percent: total > 0 ? (data[key] || 0) / total : 0,
55855
+ color: HEALTH_SAFETY_COLORS[key] || '#D9D9D9',
55856
+ label: labels[key] || key,
55857
+ key,
55858
+ keyOfField: selectedField // <-- ADD THIS
55859
+ }));
55853
55860
  };
55854
-
55855
- /**
55856
- * Generates tooltip content for health and safety pie chart
55857
- * Shows all statuses with their percentages
55858
- * @param {Object} item - The pie chart item being hovered (not used, but kept for compatibility)
55859
- * @param {boolean} isEmpty - Whether the distribution is empty
55860
- * @param {Object} healthAndSafetyDistributionData - Distribution object
55861
- * @param {Function} t - Translation function
55862
- * @param {Function} renderTooltipJsx - Function to render tooltip JSX
55863
- * @param {string} tooltipTitle - Title to display in the tooltip (defaults to "Health and Safety")
55864
- * @returns {JSX.Element|null} Tooltip content or null
55865
- */
55866
- const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx, tooltipTitle = "Health and Safety") => {
55861
+ const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistributionData, t, renderTooltipJsx, tooltipTitle = "Health and Safety", selectedField) => {
55867
55862
  // If empty or no data, return null to display nothing
55868
55863
  if (isEmpty || !Object.keys(healthAndSafetyDistributionData).length) {
55869
55864
  return null;
@@ -55876,10 +55871,10 @@ const getHealthAndSafetyTooltipChildren = (item, isEmpty, healthAndSafetyDistrib
55876
55871
  if (total === 0) {
55877
55872
  return null;
55878
55873
  }
55879
- const labels = {
55874
+ const labels = FIELD_TOOLTIP_LABELS[item?.keyOfField] || {
55880
55875
  compliant: t("Available"),
55881
55876
  notCompliant: t("Not available"),
55882
- empty: t("Not answered")
55877
+ empty: t("No data")
55883
55878
  };
55884
55879
 
55885
55880
  // Filter items with values > 0
@@ -55962,7 +55957,6 @@ const HealthAndSafety = ({
55962
55957
  getData: customGetData
55963
55958
  });
55964
55959
 
55965
- // Process the fetched pie chart data
55966
55960
  // The API returns data in format: [{count: 1, [field]: "null"}, {count: 1, [field]: "no"}, {count: 1, [field]: "yes"}]
55967
55961
  const healthAndSafetyDistributionData = React.useMemo(() => {
55968
55962
  if (!pieChartData) return {
@@ -56003,7 +55997,7 @@ const HealthAndSafety = ({
56003
55997
  return getHealthAndSafetyDistributionData(pieChartData);
56004
55998
  }, [pieChartData, selectedField]);
56005
55999
  const isEmpty = React.useMemo(() => isHealthAndSafetyDistributionEmpty(healthAndSafetyDistributionData), [healthAndSafetyDistributionData]);
56006
- const pieData = React.useMemo(() => calculateHealthAndSafetyPieData(healthAndSafetyDistributionData, t), [healthAndSafetyDistributionData, t]);
56000
+ const pieData = React.useMemo(() => calculateHealthAndSafetyPieData(healthAndSafetyDistributionData, t, selectedField), [healthAndSafetyDistributionData, t, selectedField]);
56007
56001
 
56008
56002
  // Get the label for the selected field to use as tooltip title
56009
56003
  const selectedFieldLabel = React.useMemo(() => {
@@ -56017,9 +56011,10 @@ const HealthAndSafety = ({
56017
56011
  return /*#__PURE__*/jsxRuntime.jsx(Widget, {
56018
56012
  loading: loading || pieChartLoading,
56019
56013
  title: /*#__PURE__*/jsxRuntime.jsx("div", {
56020
- children: t("Health and Safety")
56014
+ children: t("Operational Health & Safety")
56021
56015
  }),
56022
- className: "with-border-header h-w-btn-header ",
56016
+ className: "with-border-header h-w-btn-header",
56017
+ description: t("Across all activities in this cycle."),
56023
56018
  addedHeader: /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
56024
56019
  children: [/*#__PURE__*/jsxRuntime.jsx("div", {
56025
56020
  className: "flex-1"
@@ -56338,17 +56333,41 @@ const JobsTimeline = ({
56338
56333
  defaultFilter: 'monthly'
56339
56334
  });
56340
56335
  const jobsData = Array.isArray(dayJobsTimeline) ? dayJobsTimeline : dayJobsTimeline?.jobsTimeline || dayJobsTimeline?.jobs || dayJobsTimeline?.timeline || [];
56336
+
56337
+ // const jobsTimelineData = useMemo(() => {
56338
+ // // Always process data, even if empty, to generate default date range for x-axis
56339
+ // const dataToProcess = (!jobsData || !Array.isArray(jobsData) || jobsData.length === 0)
56340
+ // ? []
56341
+ // : jobsData;
56342
+
56343
+ // // Process data without cumulative calculation (for jobs timeline)
56344
+ // // Try to find value in total, count, jobs, or value fields
56345
+ // return processChartDateData({
56346
+ // mainData: dataToProcess,
56347
+ // isCumulative: false,
56348
+ // valueField: 'total', // Will fallback to count/jobs/value if total doesn't exist
56349
+ // });
56350
+ // }, [jobsData, processChartDateData]);
56351
+
56341
56352
  const jobsTimelineData = React.useMemo(() => {
56342
- // Always process data, even if empty, to generate default date range for x-axis
56353
+ // Prepare data first
56343
56354
  const dataToProcess = !jobsData || !Array.isArray(jobsData) || jobsData.length === 0 ? [] : jobsData;
56344
56355
 
56345
- // Process data without cumulative calculation (for jobs timeline)
56346
- // Try to find value in total, count, jobs, or value fields
56347
- return processChartDateData({
56356
+ // Process data without cumulative calculation
56357
+ const processedData = processChartDateData({
56348
56358
  mainData: dataToProcess,
56349
56359
  isCumulative: false,
56350
- valueField: 'total' // Will fallback to count/jobs/value if total doesn't exist
56360
+ valueField: 'total' // fallback handled inside processChartDateData
56351
56361
  });
56362
+
56363
+ // Find last index with jobs > 0
56364
+ let lastNonZeroIndex = processedData.length - 1;
56365
+ while (lastNonZeroIndex >= 0 && (processedData[lastNonZeroIndex].jobs || 0) === 0) {
56366
+ lastNonZeroIndex--;
56367
+ }
56368
+
56369
+ // Slice up to last period with data
56370
+ return processedData.slice(0, lastNonZeroIndex + 1);
56352
56371
  }, [jobsData, processChartDateData]);
56353
56372
  const maxYValue = React.useMemo(() => {
56354
56373
  if (!jobsTimelineData || jobsTimelineData.length === 0) {
@@ -0,0 +1,330 @@
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.826",
3
+ "version": "0.6.827",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -20,21 +20,44 @@ const JobsTimeline = ({
20
20
  ? dayJobsTimeline
21
21
  : (dayJobsTimeline?.jobsTimeline || dayJobsTimeline?.jobs || dayJobsTimeline?.timeline || []);
22
22
 
23
+ // const jobsTimelineData = useMemo(() => {
24
+ // // Always process data, even if empty, to generate default date range for x-axis
25
+ // const dataToProcess = (!jobsData || !Array.isArray(jobsData) || jobsData.length === 0)
26
+ // ? []
27
+ // : jobsData;
28
+
29
+ // // Process data without cumulative calculation (for jobs timeline)
30
+ // // Try to find value in total, count, jobs, or value fields
31
+ // return processChartDateData({
32
+ // mainData: dataToProcess,
33
+ // isCumulative: false,
34
+ // valueField: 'total', // Will fallback to count/jobs/value if total doesn't exist
35
+ // });
36
+ // }, [jobsData, processChartDateData]);
37
+
23
38
  const jobsTimelineData = useMemo(() => {
24
- // Always process data, even if empty, to generate default date range for x-axis
25
- const dataToProcess = (!jobsData || !Array.isArray(jobsData) || jobsData.length === 0)
26
- ? []
39
+ // Prepare data first
40
+ const dataToProcess = (!jobsData || !Array.isArray(jobsData) || jobsData.length === 0)
41
+ ? []
27
42
  : jobsData;
28
-
29
- // Process data without cumulative calculation (for jobs timeline)
30
- // Try to find value in total, count, jobs, or value fields
31
- return processChartDateData({
43
+
44
+ // Process data without cumulative calculation
45
+ const processedData = processChartDateData({
32
46
  mainData: dataToProcess,
33
47
  isCumulative: false,
34
- valueField: 'total', // Will fallback to count/jobs/value if total doesn't exist
48
+ valueField: 'total', // fallback handled inside processChartDateData
35
49
  });
50
+
51
+ // Find last index with jobs > 0
52
+ let lastNonZeroIndex = processedData.length - 1;
53
+ while (lastNonZeroIndex >= 0 && (processedData[lastNonZeroIndex].jobs || 0) === 0) {
54
+ lastNonZeroIndex--;
55
+ }
56
+
57
+ // Slice up to last period with data
58
+ return processedData.slice(0, lastNonZeroIndex + 1);
36
59
  }, [jobsData, processChartDateData]);
37
-
60
+
38
61
  const maxYValue = useMemo(() => {
39
62
  if (!jobsTimelineData || jobsTimelineData.length === 0) {
40
63
  return 100;