Copilot commented on code in PR #64267:
URL: https://github.com/apache/airflow/pull/64267#discussion_r3025339154


##########
airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/PluginImportErrors.tsx:
##########
@@ -38,42 +38,50 @@ export const PluginImportErrors = ({ iconOnly = false }: { 
readonly iconOnly?: b
   const importErrors = data?.import_errors ?? [];
 
   if (isLoading) {
-    return <Skeleton height="9" width="225px" />;
+    // Skeleton dimensions match the rendered component sizes to prevent 
layout shift.
+    // iconOnly: 28px × 60px matches StateBadge (height={7} = 28px in Chakra 
spacing scale).
+    // full: 42px × 175px matches the rendered StatsCard dimensions.
+    return iconOnly ? (
+      <Skeleton height="28px" width="60px" />
+    ) : (
+      <Skeleton height="42px" width="175px" />
+    );

Review Comment:
   The loading Skeleton sizes are duplicated and hard-coded (28×60 and 42×175). 
This risks getting out of sync with `StateBadge` / `StatsCard` styling changes 
and reintroducing layout shift. Consider reusing `StatsCard`’s loading skeleton 
for the full variant and centralizing the `iconOnly` placeholder dimensions (or 
rendering a fixed-size `StateBadge`-like wrapper) to avoid repeating magic 
numbers.



##########
airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx:
##########
@@ -37,38 +37,46 @@ export const DAGImportErrors = ({ iconOnly = false }: { 
readonly iconOnly?: bool
   const importErrorsCount = data?.total_entries ?? 0;
 
   if (isLoading) {
-    return <Skeleton height="9" width="225px" />;
+    // Skeleton dimensions match the rendered component sizes to prevent 
layout shift.
+    // iconOnly: 28px × 60px matches StateBadge (height={7} = 28px in Chakra 
spacing scale).
+    // full: 42px × 175px matches the rendered StatsCard dimensions.
+    return iconOnly ? (
+      <Skeleton height="28px" width="60px" />
+    ) : (
+      <Skeleton height="42px" width="175px" />
+    );

Review Comment:
   The loading Skeleton sizes are hard-coded here (28×60 and 42×175). This can 
easily drift from the real rendered sizes if `StateBadge` / `StatsCard` styles 
change (reintroducing layout shift). Consider deriving these from the same 
source (e.g. reuse `StatsCard`’s built-in loading skeleton for the full 
variant, and for `iconOnly` either render a `StateBadge` container with a 
fixed/min width while loading, or share constants with the badge styles) to 
avoid duplicated magic numbers.



##########
airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx:
##########
@@ -37,38 +37,46 @@ export const DAGImportErrors = ({ iconOnly = false }: { 
readonly iconOnly?: bool
   const importErrorsCount = data?.total_entries ?? 0;
 
   if (isLoading) {
-    return <Skeleton height="9" width="225px" />;
+    // Skeleton dimensions match the rendered component sizes to prevent 
layout shift.
+    // iconOnly: 28px × 60px matches StateBadge (height={7} = 28px in Chakra 
spacing scale).
+    // full: 42px × 175px matches the rendered StatsCard dimensions.
+    return iconOnly ? (
+      <Skeleton height="28px" width="60px" />
+    ) : (
+      <Skeleton height="42px" width="175px" />
+    );
   }
 
-  if (importErrorsCount === 0) {
+  if (importErrorsCount === 0 && !error) {
     return undefined;
   }

Review Comment:
   This changes behavior so the component renders (via `ErrorAlert`) when the 
import-errors query fails (previously it returned early when `total_entries` 
defaulted to 0). Please add a regression test that simulates an API error (e.g. 
500) and asserts the error alert is shown and the badge/card is not rendered 
when `total_entries` is 0.



##########
airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/PluginImportErrors.tsx:
##########
@@ -38,42 +38,50 @@ export const PluginImportErrors = ({ iconOnly = false }: { 
readonly iconOnly?: b
   const importErrors = data?.import_errors ?? [];
 
   if (isLoading) {
-    return <Skeleton height="9" width="225px" />;
+    // Skeleton dimensions match the rendered component sizes to prevent 
layout shift.
+    // iconOnly: 28px × 60px matches StateBadge (height={7} = 28px in Chakra 
spacing scale).
+    // full: 42px × 175px matches the rendered StatsCard dimensions.
+    return iconOnly ? (
+      <Skeleton height="28px" width="60px" />
+    ) : (
+      <Skeleton height="42px" width="175px" />
+    );
   }
 
   if (Boolean(error) && (error as ExpandedApiError).status === 403) {
     return undefined;
   }
 
-  if (importErrorsCount === 0) {
+  if (importErrorsCount === 0 && !error) {
     return undefined;
   }

Review Comment:
   This updates the early-return guard to allow the `ErrorAlert` to render when 
the query fails (since `total_entries` defaults to 0 on failure). Please add a 
regression test that mocks an API error and verifies the error alert shows even 
when `importErrorsCount` is 0, and that the badge/card only renders when 
`importErrorsCount > 0`.



##########
airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/PluginImportErrors.tsx:
##########
@@ -38,42 +38,50 @@ export const PluginImportErrors = ({ iconOnly = false }: { 
readonly iconOnly?: b
   const importErrors = data?.import_errors ?? [];
 
   if (isLoading) {
-    return <Skeleton height="9" width="225px" />;
+    // Skeleton dimensions match the rendered component sizes to prevent 
layout shift.
+    // iconOnly: 28px × 60px matches StateBadge (height={7} = 28px in Chakra 
spacing scale).
+    // full: 42px × 175px matches the rendered StatsCard dimensions.
+    return iconOnly ? (
+      <Skeleton height="28px" width="60px" />
+    ) : (
+      <Skeleton height="42px" width="175px" />
+    );
   }
 
   if (Boolean(error) && (error as ExpandedApiError).status === 403) {

Review Comment:
   The 403 handling does an unsafe cast `(error as ExpandedApiError).status`. 
Elsewhere in the UI (e.g. `pages/Dashboard/PoolSummary/PoolSummary.tsx:50-52`) 
code checks `error?.status === 403` without a cast. Consider typing the query 
hook’s `error` (via generics) or using optional chaining (`(error as 
ExpandedApiError | undefined)?.status`) to avoid a potential runtime crash if 
`error` is not an `ApiError` shape.
   ```suggestion
     if ((error as ExpandedApiError | undefined)?.status === 403) {
   ```



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

Reply via email to