@visns-studio/visns-components 5.13.20 → 5.13.21

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
@@ -13,7 +13,7 @@
13
13
  "@nivo/pie": "^0.99.0",
14
14
  "@tinymce/miniature": "^6.0.0",
15
15
  "@tinymce/tinymce-react": "^6.2.1",
16
- "@uiw/react-color": "^2.7.1",
16
+ "@uiw/react-color": "^2.6.0",
17
17
  "@visns-studio/visns-datagrid-community": "1.1.0",
18
18
  "@visns-studio/visns-datagrid-enterprise": "1.1.0",
19
19
  "@vitejs/plugin-react": "^4.6.0",
@@ -24,13 +24,13 @@
24
24
  "dayjs": "^1.11.13",
25
25
  "fabric": "^6.7.0",
26
26
  "file-saver": "^2.0.5",
27
- "framer-motion": "^12.23.5",
27
+ "framer-motion": "^12.23.1",
28
28
  "html-react-parser": "^5.2.5",
29
29
  "lodash": "^4.17.21",
30
30
  "lodash.debounce": "^4.0.8",
31
31
  "lucide-react": "^0.525.0",
32
32
  "moment": "^2.30.1",
33
- "motion": "^12.23.5",
33
+ "motion": "^12.23.1",
34
34
  "numeral": "^2.0.6",
35
35
  "pluralize": "^8.0.0",
36
36
  "qrcode.react": "^4.2.0",
@@ -47,7 +47,7 @@
47
47
  "react-quill": "^2.0.0",
48
48
  "react-reveal": "^1.2.2",
49
49
  "react-router-dom": "^6.30.1",
50
- "react-select": "^5.10.2",
50
+ "react-select": "^5.10.1",
51
51
  "react-signature-pad-wrapper": "^4.1.1",
52
52
  "react-slugify": "^4.0.1",
53
53
  "react-sortable-hoc": "^2.0.0",
@@ -88,7 +88,7 @@
88
88
  "react-dom": "^17.0.0 || ^18.0.0"
89
89
  },
90
90
  "name": "@visns-studio/visns-components",
91
- "version": "5.13.20",
91
+ "version": "5.13.21",
92
92
  "description": "Various packages to assist in the development of our Custom Applications.",
93
93
  "main": "src/index.js",
94
94
  "files": [
@@ -33,15 +33,15 @@ const renderProgressBar = (value, options = {}) => {
33
33
  const backgroundColor = colorMap[color] || colorMap.primary;
34
34
 
35
35
  return (
36
- <div style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
36
+ <div style={{ width: '100%', minWidth: '150px' }}>
37
37
  <div
38
38
  style={{
39
- width: '100px',
40
- height: '20px',
39
+ width: '100%',
40
+ height: '24px',
41
41
  backgroundColor: '#e9ecef',
42
- borderRadius: '10px',
42
+ borderRadius: '12px',
43
43
  overflow: 'hidden',
44
- marginRight: showPercentage ? '8px' : '0'
44
+ position: 'relative'
45
45
  }}
46
46
  >
47
47
  <div
@@ -49,21 +49,66 @@ const renderProgressBar = (value, options = {}) => {
49
49
  width: `${Math.min(Math.max(percentage, 0), 100)}%`,
50
50
  height: '100%',
51
51
  backgroundColor: backgroundColor,
52
- borderRadius: '10px',
52
+ borderRadius: '12px',
53
53
  transition: 'width 0.3s ease'
54
54
  }}
55
55
  />
56
+ {showPercentage && (
57
+ <span style={{
58
+ position: 'absolute',
59
+ top: '50%',
60
+ left: '50%',
61
+ transform: 'translate(-50%, -50%)',
62
+ fontSize: '12px',
63
+ fontWeight: '600',
64
+ color: percentage > 50 ? '#fff' : '#333',
65
+ textShadow: percentage > 50 ? '0 1px 2px rgba(0,0,0,0.3)' : '0 1px 2px rgba(255,255,255,0.8)',
66
+ zIndex: 1
67
+ }}>
68
+ {percentage.toFixed(1)}%
69
+ </span>
70
+ )}
56
71
  </div>
57
- {showPercentage && (
58
- <span style={{ fontSize: '12px', color: '#6c757d', minWidth: '35px' }}>
59
- {percentage.toFixed(1)}%
60
- </span>
61
- )}
62
72
  </div>
63
73
  );
64
74
  };
65
75
 
66
- const renderCellContent = (value, column, widget) => {
76
+ const renderStatusMessage = (status, messages) => {
77
+ const message = messages[status] || messages.default || 'Status not available';
78
+ return (
79
+ <div style={{
80
+ fontSize: '12px',
81
+ color: '#6c757d',
82
+ fontStyle: 'italic',
83
+ padding: '4px 8px',
84
+ backgroundColor: '#f8f9fa',
85
+ borderRadius: '4px',
86
+ border: '1px solid #e9ecef'
87
+ }}>
88
+ {message}
89
+ </div>
90
+ );
91
+ };
92
+
93
+ const checkCondition = (rowData, condition) => {
94
+ if (!condition || !rowData) return false;
95
+
96
+ const { field, value, operator = 'equals' } = condition;
97
+ const fieldValue = rowData[field];
98
+
99
+ switch (operator) {
100
+ case 'equals':
101
+ return fieldValue === value;
102
+ case 'not_equals':
103
+ return fieldValue !== value;
104
+ case 'contains':
105
+ return fieldValue && fieldValue.toString().includes(value);
106
+ default:
107
+ return false;
108
+ }
109
+ };
110
+
111
+ const renderCellContent = (value, column, widget, rowData = {}) => {
67
112
  const columnFormatting = widget.columnFormatting || {};
68
113
  const formatting = columnFormatting[column];
69
114
 
@@ -71,6 +116,17 @@ const renderCellContent = (value, column, widget) => {
71
116
  return renderProgressBar(value, formatting);
72
117
  }
73
118
 
119
+ if (formatting && formatting.type === 'conditionalProgressBar') {
120
+ const conditionMet = checkCondition(rowData, formatting.condition);
121
+
122
+ if (conditionMet) {
123
+ return renderProgressBar(value, formatting);
124
+ } else if (formatting.fallback && formatting.fallback.type === 'statusMessage') {
125
+ const status = rowData[formatting.condition.field] || 'default';
126
+ return renderStatusMessage(status, formatting.fallback.messages);
127
+ }
128
+ }
129
+
74
130
  return value;
75
131
  };
76
132
 
@@ -94,6 +150,9 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
94
150
  const [widgetAdded, setWidgetAdded] = useState(false);
95
151
  // State to track viewport width
96
152
  const [viewportWidth, setViewportWidth] = useState(window.innerWidth);
153
+ // Auto-refresh state
154
+ const [autoRefreshEnabled, setAutoRefreshEnabled] = useState(false);
155
+ const autoRefreshIntervalRef = useRef(null);
97
156
 
98
157
  // Compute available widgets from original settings that are not yet added.
99
158
  const availableWidgets = setting.widgets.filter(
@@ -260,6 +319,39 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
260
319
  };
261
320
  }, []);
262
321
 
322
+ // Auto-refresh functionality
323
+ useEffect(() => {
324
+ const widgets = dashboardSetting.widgets || [];
325
+ const autoRefreshWidget = widgets.find(widget => widget.autoRefresh?.enabled);
326
+
327
+ if (autoRefreshWidget && autoRefreshEnabled) {
328
+ const interval = autoRefreshWidget.autoRefresh.interval || 30000; // Default 30 seconds
329
+
330
+ autoRefreshIntervalRef.current = setInterval(() => {
331
+ if (Object.keys(filters).length > 0) {
332
+ fetchData(filters);
333
+ }
334
+ }, interval);
335
+ }
336
+
337
+ return () => {
338
+ if (autoRefreshIntervalRef.current) {
339
+ clearInterval(autoRefreshIntervalRef.current);
340
+ autoRefreshIntervalRef.current = null;
341
+ }
342
+ };
343
+ }, [autoRefreshEnabled, filters, dashboardSetting]);
344
+
345
+ // Initialize auto-refresh from widget settings
346
+ useEffect(() => {
347
+ const widgets = dashboardSetting.widgets || [];
348
+ const autoRefreshWidget = widgets.find(widget => widget.autoRefresh?.enabled);
349
+
350
+ if (autoRefreshWidget) {
351
+ setAutoRefreshEnabled(true);
352
+ }
353
+ }, [dashboardSetting]);
354
+
263
355
  const openModal = (widgetId) => {
264
356
  setModalContent(widgetId);
265
357
  setModalShow(true);
@@ -1119,7 +1211,8 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
1119
1211
  {renderCellContent(
1120
1212
  row[column],
1121
1213
  column,
1122
- widget
1214
+ widget,
1215
+ row
1123
1216
  )}
1124
1217
  </td>
1125
1218
  )
@@ -1333,6 +1426,25 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
1333
1426
  >
1334
1427
  <div className={styles.widgetTitle}>
1335
1428
  <h2>{widget.title}</h2>
1429
+ {widget.autoRefresh?.enabled && widget.autoRefresh?.showControls && (
1430
+ <div className={styles.autoRefreshControl}>
1431
+ <label style={{
1432
+ display: 'flex',
1433
+ alignItems: 'center',
1434
+ fontSize: '12px',
1435
+ color: '#6c757d',
1436
+ marginLeft: '10px'
1437
+ }}>
1438
+ <input
1439
+ type="checkbox"
1440
+ checked={autoRefreshEnabled}
1441
+ onChange={(e) => setAutoRefreshEnabled(e.target.checked)}
1442
+ style={{ marginRight: '5px' }}
1443
+ />
1444
+ Auto-refresh ({Math.round((widget.autoRefresh.interval || 30000) / 1000)}s)
1445
+ </label>
1446
+ </div>
1447
+ )}
1336
1448
  </div>
1337
1449
  {renderFilters(widget)}
1338
1450
  <div>{renderWidget(widget)}</div>
@@ -63,6 +63,9 @@
63
63
  height: auto;
64
64
  padding: 0;
65
65
  margin-bottom: 0.85rem;
66
+ display: flex;
67
+ justify-content: space-between;
68
+ align-items: center;
66
69
  }
67
70
  .widgetTitle h2 {
68
71
  font-size: 1rem;