codeant-ai-for-open-source[bot] commented on code in PR #38145:
URL: https://github.com/apache/superset/pull/38145#discussion_r2835635130


##########
superset-frontend/plugins/plugin-chart-table/src/transformProps.ts:
##########
@@ -384,89 +384,87 @@ const processComparisonColumns = (
   props: TableChartProps,
   comparisonSuffix: string,
 ) =>
-  columns
-    .map(col => {
-      const {
-        datasource: { columnFormats, currencyFormats },
-        rawFormData: { column_config: columnConfig = {} },
-      } = props;
-      const savedFormat = columnFormats?.[col.key];
-      const savedCurrency = currencyFormats?.[col.key];
-      const originalLabel = col.label;
-      if (
-        (col.isMetric || col.isPercentMetric) &&
-        !col.key.includes(comparisonSuffix) &&
-        col.isNumeric
-      ) {
-        return [
-          {
-            ...col,
-            originalLabel,
-            label: t('Main'),
-            key: `${t('Main')} ${col.key}`,
-            config: getComparisonColConfig(t('Main'), col.key, columnConfig),
-            formatter: getComparisonColFormatter(
-              t('Main'),
-              col,
-              columnConfig,
-              savedFormat,
-              savedCurrency,
-            ),
-          },
-          {
-            ...col,
-            originalLabel,
-            label: `#`,
-            key: `# ${col.key}`,
-            config: getComparisonColConfig(`#`, col.key, columnConfig),
-            formatter: getComparisonColFormatter(
-              `#`,
-              col,
-              columnConfig,
-              savedFormat,
-              savedCurrency,
-            ),
-          },
-          {
-            ...col,
-            originalLabel,
-            label: `△`,
-            key: `△ ${col.key}`,
-            config: getComparisonColConfig(`△`, col.key, columnConfig),
-            formatter: getComparisonColFormatter(
-              `△`,
-              col,
-              columnConfig,
-              savedFormat,
-              savedCurrency,
-            ),
-          },
-          {
-            ...col,
-            originalLabel,
-            label: `%`,
-            key: `% ${col.key}`,
-            config: getComparisonColConfig(`%`, col.key, columnConfig),
-            formatter: getComparisonColFormatter(
-              `%`,
-              col,
-              columnConfig,
-              savedFormat,
-              savedCurrency,
-            ),
-          },
-        ];
-      }
-      if (
-        !col.isMetric &&
-        !col.isPercentMetric &&
-        !col.key.includes(comparisonSuffix)
-      ) {
-        return [col];
-      }
-      return [];
-    })
-    .flat();
+  columns.flatMap(col => {
+    const {
+      datasource: { columnFormats, currencyFormats },
+      rawFormData: { column_config: columnConfig = {} },
+    } = props;
+    const savedFormat = columnFormats?.[col.key];
+    const savedCurrency = currencyFormats?.[col.key];
+    const originalLabel = col.label;
+    if (
+      (col.isMetric || col.isPercentMetric) &&
+      !col.key.includes(comparisonSuffix) &&
+      col.isNumeric
+    ) {
+      return [
+        {
+          ...col,
+          originalLabel,
+          label: t('Main'),
+          key: `${t('Main')} ${col.key}`,

Review Comment:
   **Suggestion:** The comparison column metadata uses a translated label 
(`t('Main')`) as part of the column `key`, while the comparison data records 
and totals are built with a hard-coded `"Main "` prefix; in non-English locales 
this mismatch means the table will look for fields like "TraduçãoDoMain 
<metric>" that do not exist in the row data, resulting in empty cells and 
broken totals for time comparison columns. To fix this, keep the user-facing 
`label` translated but use a stable, non-translated `"Main "` prefix for the 
`key` so it matches the field names produced in `processComparisonDataRecords` 
and `processComparisonTotals`. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Main time-comparison metric column renders empty in non-English UI.
   - ❌ Summary totals for main comparison metrics show as blank.
   - ⚠️ Users can misinterpret comparison tables as having missing data.
   ```
   </details>
   
   ```suggestion
             key: `Main ${col.key}`,
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Run Superset with the UI locale set to a non-English language where 
`t('Main')` is not
   equal to the literal string `"Main"` (frontend translation function from
   `@apache-superset/core` is used at
   `superset-frontend/plugins/plugin-chart-table/src/transformProps.ts:20` and
   `superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:57`).
   
   2. In Explore, create or open a Table chart that has at least one numeric 
metric (so
   `isMetric` is true) and enable time comparison with `Values` comparison type 
(this sets
   `time_compare` and `comparison_type`, making `isUsingTimeComparison` true in
   `transformProps` at `transformProps.ts:515-538`).
   
   3. Observe that `transformProps` builds comparison row data with hard-coded 
keys using the
   English prefix `Main` in `processComparisonDataRecords` 
(`transformedItem['Main ' +
   origCol.key]` at `transformProps.ts:179`) and builds totals with the same 
hard-coded key
   pattern in `processComparisonTotals` (`transformedTotals['Main ' + key]` at
   `transformProps.ts:131-145`).
   
   4. At the same time, `processComparisonColumns` constructs column metadata 
with keys based
   on the translated label `${t('Main')} ${col.key}` at 
`transformProps.ts:404-405`, so for a
   French locale this becomes e.g. `'Principal my_metric'`, while the data 
objects still use
   `'Main my_metric'`. When `TableChart` renders cells, it accesses values by 
`datum[key]` in
   the accessor at 
`superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx:917-918`
   and totals by `displayedTotals[key]` in the footer at 
`TableChart.tsx:1231-1233`, so the
   mismatch between translated keys (e.g. `'Principal my_metric'`) and 
hard-coded data keys
   (`'Main my_metric'`) causes the main comparison column's cells and totals to 
be
   `undefined`/empty in non-English locales.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset-frontend/plugins/plugin-chart-table/src/transformProps.ts
   **Line:** 405:405
   **Comment:**
        *Logic Error: The comparison column metadata uses a translated label 
(`t('Main')`) as part of the column `key`, while the comparison data records 
and totals are built with a hard-coded `"Main "` prefix; in non-English locales 
this mismatch means the table will look for fields like "TraduçãoDoMain 
<metric>" that do not exist in the row data, resulting in empty cells and 
broken totals for time comparison columns. To fix this, keep the user-facing 
`label` translated but use a stable, non-translated `"Main "` prefix for the 
`key` so it matches the field names produced in `processComparisonDataRecords` 
and `processComparisonTotals`.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38145&comment_hash=cdb872b9a48cdada7c759acb12a79d60775fd9d27505ab713af41cbe6c22924c&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38145&comment_hash=cdb872b9a48cdada7c759acb12a79d60775fd9d27505ab713af41cbe6c22924c&reaction=dislike'>👎</a>



##########
superset-frontend/src/SqlLab/reducers/getInitialState.ts:
##########
@@ -242,7 +242,7 @@ export default function getInitialState({
             }
           });
         }
-        lastUpdatedActiveTab = tabHistory.slice(tabHistory.length - 1)[0] || 
'';
+        lastUpdatedActiveTab = tabHistory.slice(-1)[0] || '';

Review Comment:
   **Suggestion:** The new assignment of the last-synced active tab id to the 
last entry in the merged tab history overwrites the backend-sourced value, so 
`lastUpdatedActiveTab` can point to a tab that has never been persisted; this 
breaks the contract used by `EditorAutoSync` and `persistSqlLabStateEnhancer`, 
which rely on detecting when the current active tab differs from 
`lastUpdatedActiveTab` to push state to the backend, meaning the active tab may 
never be synced after localStorage migration. Removing this reassignment 
preserves the backend-sourced value and keeps the sync logic working as 
intended. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Backend active tab may never update after localStorage migration.
   - ⚠️ EditorAutoSync skips syncing active tab on first load.
   - ⚠️ Subsequent sessions may open outdated active tab from backend.
   ```
   </details>
   
   ```suggestion
           // Preserve lastUpdatedActiveTab from the backend-sourced initial 
state.
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Enable the `SqllabBackendPersistence` feature flag so that SQL Lab uses 
backend
   persistence, as checked in
   
`superset-frontend/src/SqlLab/middlewares/persistSqlLabStateEnhancer.ts:79-80` 
with
   `isFeatureEnabled(FeatureFlag.SqllabBackendPersistence)`.
   
   2. In an older session (before this PR's change), use SQL Lab so that state 
is saved into
   browser localStorage under the `redux` key via 
`persistSqlLabStateEnhancer`'s slicer at
   
`superset-frontend/src/SqlLab/middlewares/persistSqlLabStateEnhancer.ts:71-123`,
 which
   persists `sqlLab.tabHistory` and other fields.
   
   3. Restart the frontend so a fresh Redux store is created, keeping the 
`redux`
   localStorage entry; when the app initializes, 
`superset-frontend/src/views/store.ts:157`
   calls `getInitialState(bootstrapData)` from
   `superset-frontend/src/SqlLab/reducers/getInitialState.ts` to build the 
initial `sqlLab`
   slice, and the SQL Lab page mounts `EditorAutoSync`
   (`superset-frontend/src/pages/SqlLab/index.tsx:78`).
   
   4. During `getInitialState` execution, backend bootstrap data defines 
`active_tab` (used
   to set `tabHistory` and `lastUpdatedActiveTab` at lines 117-118), and then 
the
   localStorage state is merged: `localStorageData` is parsed at lines 162-167,
   `sqlLab.tabHistory` from localStorage is pushed into the in-memory 
`tabHistory` at lines
   230-235, and finally `lastUpdatedActiveTab` is overwritten with the last 
merged history
   entry via `lastUpdatedActiveTab = tabHistory.slice(-1)[0] || '';` at line 
245.
   
   5. After this initialization, the Redux state has `sqlLab.tabHistory` ending 
with the last
   locally stored tab id (e.g. `'local-tab-id'`), and 
`sqlLab.lastUpdatedActiveTab` equal to
   that same id due to line 245, even though the backend's notion of the active 
tab (the
   `active_tab` passed in bootstrap) may differ and has never been updated to 
this new value.
   
   6. `EditorAutoSync` reads `currentQueryEditorId` as 
`state.sqlLab.tabHistory.slice(-1)[0]
   || ''` and `lastUpdatedActiveTab` as `state.sqlLab.lastUpdatedActiveTab` at
   `superset-frontend/src/SqlLab/components/EditorAutoSync/index.tsx:92-97`; in
   `syncCurrentQueryEditor` (lines 127-140), the condition 
`currentQueryEditorId &&
   currentQueryEditorId !== lastUpdatedActiveTab && 
!queryEditors.find(...).inLocalStorage`
   evaluates to false because `currentQueryEditorId === lastUpdatedActiveTab`, 
so
   `updateCurrentSqlEditor` is never called and `setLastUpdatedActiveTab` is 
never
   dispatched.
   
   7. Because `lastUpdatedActiveTab` was pre-set to the merged tabHistory's 
last entry
   instead of the backend's `active_tab`, both `EditorAutoSync` and
   `persistSqlLabStateEnhancer`'s `hasUnsavedActiveTabState` check at
   `persistSqlLabStateEnhancer.ts:95-96` incorrectly conclude there is no 
unsynced active-tab
   change, so the active tab chosen from localStorage after migration may never 
be reported
   back to the backend unless the user later switches to yet another tab, which 
breaks the
   intended "detect change and sync" contract during localStorage migration.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset-frontend/src/SqlLab/reducers/getInitialState.ts
   **Line:** 245:245
   **Comment:**
        *Logic Error: The new assignment of the last-synced active tab id to 
the last entry in the merged tab history overwrites the backend-sourced value, 
so `lastUpdatedActiveTab` can point to a tab that has never been persisted; 
this breaks the contract used by `EditorAutoSync` and 
`persistSqlLabStateEnhancer`, which rely on detecting when the current active 
tab differs from `lastUpdatedActiveTab` to push state to the backend, meaning 
the active tab may never be synced after localStorage migration. Removing this 
reassignment preserves the backend-sourced value and keeps the sync logic 
working as intended.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38145&comment_hash=059559291ef8727a000ad6412e5de9d2d08ca8bb71b25ab91fa105a9ceda79bf&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38145&comment_hash=059559291ef8727a000ad6412e5de9d2d08ca8bb71b25ab91fa105a9ceda79bf&reaction=dislike'>👎</a>



-- 
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