Copilot commented on code in PR #36050:
URL: https://github.com/apache/superset/pull/36050#discussion_r2519355681


##########
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:
##########
@@ -470,6 +644,9 @@ export class TableRenderer extends Component {
               namesMapping,
               allowRenderHtml,
             )}
+            <span role="columnheader button" tabIndex={0}>
+              {visibleSortIcon && getSortIcon(i)}
+            </span>

Review Comment:
   The `role` attribute has an invalid value. ARIA roles cannot have multiple 
space-separated values like `\"columnheader button\"`. The span should use 
`role=\"button\"` since it's an interactive element for sorting. The parent 
`<th>` element already has `role=\"columnheader button\"` which also needs to 
be corrected to just `role=\"columnheader\"`.



##########
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:
##########
@@ -348,6 +420,84 @@ export class TableRenderer extends Component {
     return spans;
   }
 
+  calculateGroups(pivotData, visibleColName) {
+    const groups = {};
+    const rows = pivotData.rowKeys;
+    rows.forEach(rowKey => {
+      const aggValue = pivotData.getAggregator(rowKey, visibleColName).value();
+      let current = groups;
+      let sumGroup = 0;
+      rowKey.forEach(key => {
+        if (!current[key]) {
+          current[key] = { currentVal: 0 };
+        }
+        sumGroup += aggValue;
+        current[key].currentVal = sumGroup;
+        current = current[key];
+      });
+    });
+    return groups;
+  }

Review Comment:
   The `sumGroup` variable is being accumulated incorrectly. It's initialized 
to 0 for each `rowKey` and then adds `aggValue` for every nested key in the 
hierarchy. This means if a rowKey has 3 levels, the aggValue gets multiplied by 
3. The `sumGroup` should either be set to `aggValue` directly (not 
accumulated), or the accumulation logic needs to be reconsidered based on the 
actual requirements for hierarchical aggregation.



##########
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:
##########
@@ -470,6 +644,9 @@ export class TableRenderer extends Component {
               namesMapping,
               allowRenderHtml,
             )}
+            <span role="columnheader button" tabIndex={0}>

Review Comment:
   The span has `tabIndex={0}` making it keyboard-focusable, but there's no 
`onKeyDown` handler to trigger sorting via keyboard. Users navigating with 
keyboard won't be able to activate the sort functionality. Add an `onKeyDown` 
handler that triggers the sort when Enter or Space is pressed.
   ```suggestion
               <span
                 role="columnheader button"
                 tabIndex={0}
                 onKeyDown={e => {
                   if (e.key === 'Enter' || e.key === ' ') {
                     e.preventDefault();
                     this.clickHeaderHandler(
                       pivotData,
                       colKey,
                       this.props.cols,
                       attrIdx,
                       this.props.tableOptions.clickColumnHeaderCallback,
                     )(e);
                   }
                 }}
               >
   ```



##########
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:
##########
@@ -71,15 +74,84 @@ function displayHeaderCell(
   );
 }
 
+function sortHierarchicalObject(obj, objSort, rowPartialOnTop) {
+  const sortedKeys = Object.keys(obj).sort((a, b) => {
+    const valA = obj[a].currentVal || 0;
+    const valB = obj[b].currentVal || 0;
+    if (rowPartialOnTop) {
+      if (obj[a].currentVal !== undefined && obj[b].currentVal === undefined) {
+        return -1;
+      }
+      if (obj[b].currentVal !== undefined && obj[a].currentVal === undefined) {
+        return 1;
+      }
+    }
+    return objSort === 'asc' ? valA - valB : valB - valA;
+  });
+  return sortedKeys.reduce((acc, key) => {
+    acc[key] =
+      typeof obj[key] === 'object' && !Array.isArray(obj[key])
+        ? sortHierarchicalObject(obj[key], objSort, rowPartialOnTop)
+        : obj[key];
+    return acc;
+  }, {});
+}
+
+function convertToArray(
+  obj,
+  rowEnabled,
+  rowPartialOnTop,
+  maxRowIndex,
+  parentKeys = [],
+  result = [],
+  flag = false,
+) {
+  let updatedFlag = flag;
+  Object.keys(obj).forEach(key => {
+    if (key === 'currentVal') {
+      return;
+    }
+    if (rowEnabled && rowPartialOnTop && parentKeys.length < maxRowIndex - 1) {
+      result.push(parentKeys.length > 0 ? [...parentKeys, key] : [key]);
+      updatedFlag = true;
+    }
+    if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
+      parentKeys.push(key);
+      convertToArray(
+        obj[key],
+        rowEnabled,
+        rowPartialOnTop,
+        maxRowIndex,
+        parentKeys,
+        result,
+      );
+      parentKeys.pop();
+    }
+    if (
+      parentKeys.length >= maxRowIndex - 1 ||
+      (rowEnabled && !rowPartialOnTop)
+    ) {
+      if (!updatedFlag) {
+        result.push(parentKeys.length > 0 ? [...parentKeys, key] : [key]);
+        return;
+      }
+    }
+    if (parentKeys.length === 0 && maxRowIndex === 1) {
+      result.push([key]);
+    }
+  });
+  return result;
+}

Review Comment:
   The `updatedFlag` variable is set to `true` on line 116 but is never reset 
to `false` when processing subsequent siblings. This means once one sibling 
sets the flag, all following siblings at the same level will see 
`updatedFlag=true`, potentially causing incorrect behavior in the conditional 
on line 134. The flag should be reset at the appropriate scope or the logic 
should be restructured to properly handle sibling iteration.



##########
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.jsx:
##########
@@ -433,11 +583,35 @@ export class TableRenderer extends Component {
         ) {
           colLabelClass += ' active';
         }
+        const { maxRowVisible: maxRowIndex, maxColVisible } = pivotSettings;
+        const visibleSortIcon = maxColVisible - 1 === attrIdx;
 
         const rowSpan = 1 + (attrIdx === colAttrs.length - 1 ? rowIncrSpan : 
0);
         const flatColKey = flatKey(colKey.slice(0, attrIdx + 1));
         const onArrowClick = needToggle ? this.toggleColKey(flatColKey) : null;
 
+        const getSortIcon = key => {
+          const { activeSortColumn, sortingOrder } = this.state;
+
+          if (activeSortColumn !== key) {
+            return (
+              <FaSort
+                onClick={() =>
+                  this.sortData(key, visibleColKeys, pivotData, maxRowIndex)
+                }
+              />
+            );
+          }
+
+          const SortIcon = sortingOrder[key] === 'asc' ? FaSortAsc : 
FaSortDesc;
+          return (
+            <SortIcon
+              onClick={() =>
+                this.sortData(key, visibleColKeys, pivotData, maxRowIndex)
+              }
+            />
+          );
+        };

Review Comment:
   The `onClick` handler with identical parameters is duplicated in both 
branches. Extract it to a common variable or function to reduce duplication and 
improve maintainability. For example: `const handleClick = () => 
this.sortData(key, visibleColKeys, pivotData, maxRowIndex);` and then use 
`onClick={handleClick}` in both icon components.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to