@visns-studio/visns-components 5.16.3 → 5.18.0

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
@@ -94,7 +94,7 @@
94
94
  "react-dom": "^17.0.0 || ^18.0.0"
95
95
  },
96
96
  "name": "@visns-studio/visns-components",
97
- "version": "5.16.3",
97
+ "version": "5.18.0",
98
98
  "description": "Various packages to assist in the development of our Custom Applications.",
99
99
  "main": "src/index.js",
100
100
  "files": [
@@ -921,6 +921,36 @@ const DataGrid = forwardRef(
921
921
  [selected, ajaxSetting]
922
922
  );
923
923
 
924
+ const isGroupPartiallySelected = useCallback(
925
+ (groupValue) => {
926
+ if (!dataRef.current || !ajaxSetting?.groupBy) {
927
+ return false;
928
+ }
929
+
930
+ const groupField = ajaxSetting.groupBy[0];
931
+ const validRows = dataRef.current.filter(
932
+ (row) =>
933
+ row &&
934
+ row[groupField] === groupValue &&
935
+ row.id !== undefined &&
936
+ row.id !== null
937
+ );
938
+
939
+ if (validRows.length === 0) {
940
+ return false;
941
+ }
942
+
943
+ const selectedCount = validRows.filter(
944
+ (row) =>
945
+ selected[row.id] &&
946
+ !selected[row.id].__group
947
+ ).length;
948
+
949
+ return selectedCount > 0 && selectedCount < validRows.length;
950
+ },
951
+ [selected, ajaxSetting]
952
+ );
953
+
924
954
  const findUpdatedFilter = (filters, currentValues) => {
925
955
  for (const filter of filters) {
926
956
  const matchingCurrentValue = currentValues.find(
@@ -1398,11 +1428,21 @@ const DataGrid = forwardRef(
1398
1428
  // Check if all show conditions are met
1399
1429
  return iconConfig.show.every((condition) => {
1400
1430
  const { id, value } = condition;
1431
+ const hasValueProp = condition.hasOwnProperty('value');
1401
1432
 
1402
1433
  // Check if any row in the group matches the condition
1403
1434
  return groupRows.some((row) => {
1404
1435
  const rowValue = row[id];
1405
1436
 
1437
+ // No value prop → field must be truthy (set/non-empty)
1438
+ if (!hasValueProp) {
1439
+ return (
1440
+ rowValue !== null &&
1441
+ rowValue !== undefined &&
1442
+ rowValue !== ''
1443
+ );
1444
+ }
1445
+
1406
1446
  // Handle null value condition
1407
1447
  if (value === null) {
1408
1448
  return (
@@ -3532,6 +3572,7 @@ const DataGrid = forwardRef(
3532
3572
 
3533
3573
  {/* DataGrid container with its own border */}
3534
3574
  <div className={styles.dataGridContainer}>
3575
+
3535
3576
  {limit && limit > 0 ? (
3536
3577
  <ReactDataGrid
3537
3578
  key={`datagrid-${ajaxSetting?.url || ''}-${
@@ -3754,6 +3795,37 @@ const DataGrid = forwardRef(
3754
3795
  styles.groupActionContainer
3755
3796
  }
3756
3797
  >
3798
+ {tableSetting?.checkboxColumn && (
3799
+ <input
3800
+ type="checkbox"
3801
+ className={
3802
+ styles.groupHeaderCheckbox
3803
+ }
3804
+ checked={isGroupSelected(
3805
+ groupValue
3806
+ )}
3807
+ ref={(el) => {
3808
+ if (el) {
3809
+ el.indeterminate =
3810
+ isGroupPartiallySelected(
3811
+ groupValue
3812
+ );
3813
+ }
3814
+ }}
3815
+ onClick={(e) =>
3816
+ e.stopPropagation()
3817
+ }
3818
+ onChange={(e) => {
3819
+ e.stopPropagation();
3820
+ handleGroupSelectionChange(
3821
+ groupValue,
3822
+ e.target
3823
+ .checked
3824
+ );
3825
+ }}
3826
+ aria-label="Select all items in this group"
3827
+ />
3828
+ )}
3757
3829
  <button
3758
3830
  className={`group-expand-btn ${styles.groupExpandBtn}`}
3759
3831
  onClick={(e) => {
@@ -2229,6 +2229,30 @@ function Form({
2229
2229
  }
2230
2230
  }, [tableData.dataSource]);
2231
2231
 
2232
+ // Auto-submit on mount when formSettings.autoSubmit is true.
2233
+ // Used for "report" tabs that should show their results immediately instead of
2234
+ // requiring the user to click "View Report" with an empty filter form.
2235
+ // We trigger an actual click on the rendered Save button so the path is
2236
+ // identical to the user clicking it manually.
2237
+ const autoSubmittedRef = useRef(false);
2238
+ useEffect(() => {
2239
+ if (formSettings?.autoSubmit && !autoSubmittedRef.current) {
2240
+ autoSubmittedRef.current = true;
2241
+ const timer = setTimeout(() => {
2242
+ const saveBtn = document.querySelector('[data-type="save"]');
2243
+ if (saveBtn) {
2244
+ saveBtn.click();
2245
+ } else {
2246
+ handleSubmit({
2247
+ preventDefault: () => {},
2248
+ target: { dataset: { type: 'save' } },
2249
+ });
2250
+ }
2251
+ }, 150);
2252
+ return () => clearTimeout(timer);
2253
+ }
2254
+ }, [formSettings?.autoSubmit]);
2255
+
2232
2256
  useEffect(() => {
2233
2257
  formSettings.fields.forEach((field) => {
2234
2258
  // showIfEmpty: only show field when its own value is empty/null/undefined/[]
@@ -241,6 +241,20 @@ function GenericIndex({
241
241
  const [customActionFormData, setCustomActionFormData] = useState({});
242
242
  const [customActionConfig, setCustomActionConfig] = useState(null);
243
243
  const { windowHeight, windowWidth } = useWindowDimensions();
244
+
245
+ // Toggle a body-level "tablet-mode" class when this view opts in via
246
+ // setting.tabletMode. Lets consumer projects style the whole UI
247
+ // (including app-level chrome) for tablet use without touching this lib.
248
+ useEffect(() => {
249
+ if (!setting?.tabletMode) {
250
+ return undefined;
251
+ }
252
+ document.body.classList.add('tablet-mode');
253
+ return () => {
254
+ document.body.classList.remove('tablet-mode');
255
+ };
256
+ }, [setting?.tabletMode]);
257
+
244
258
  const { config, setConfig, subnav, setSubnav } = useConfig(
245
259
  setting,
246
260
  setting.tabs,
@@ -879,6 +879,21 @@
879
879
  position: relative;
880
880
  }
881
881
 
882
+ .groupHeaderCheckbox {
883
+ width: 22px;
884
+ height: 22px;
885
+ margin-right: 12px;
886
+ cursor: pointer;
887
+ accent-color: var(--primary-color, #3b82f6);
888
+ flex-shrink: 0;
889
+ border-radius: 4px;
890
+ transition: transform 0.15s ease;
891
+
892
+ &:hover {
893
+ transform: scale(1.08);
894
+ }
895
+ }
896
+
882
897
  .groupExpandBtn {
883
898
  background: var(--primary-color, #3b82f6);
884
899
  border: none;
@@ -1200,3 +1215,5 @@
1200
1215
  transform: scale(1.2);
1201
1216
  }
1202
1217
  }
1218
+
1219
+