pierrejeambrun commented on code in PR #68346:
URL: https://github.com/apache/airflow/pull/68346#discussion_r3413629883


##########
airflow-core/src/airflow/ui/src/components/DataTable/TableList.tsx:
##########
@@ -87,7 +93,22 @@ export const TableList = <TData,>({ allowFiltering, 
renderSubComponent, table }:
       <Table.Body>
         {table.getRowModel().rows.map((row) => (
           <Fragment key={row.id}>
-            <Table.Row>
+            <Table.Row
+              _hover={onRowClick === undefined ? undefined : { bg: "bg.subtle" 
}}
+              cursor={onRowClick === undefined ? undefined : "pointer"}
+              onClick={onRowClick === undefined ? undefined : () => 
onRowClick(row)}

Review Comment:
   Apparently we also need to set 'role' for accessibility on <tr> that have an 
onClick prop.



##########
airflow-core/src/airflow/ui/src/router.tsx:
##########
@@ -188,7 +188,7 @@ export const routerConfig = [
           { element: <DagRuns />, path: "runs" },
           { element: <Tasks />, path: "tasks" },
           { element: <Calendar />, path: "calendar" },
-          { element: <HITLTaskInstances />, path: "required_actions" },
+          { element: <Overview />, path: "required_actions" },
           { element: <Backfills />, path: "backfills" },

Review Comment:
   It looks like though the notification page is only showing the first 'page' 
of pending / completed HITLs. 
   
   IF there are more notifications than the 'limit' (100 by default), then it's 
not possible to review them from the notification panel, table won't display 
any pagination items to navigate the notifications.



##########
airflow-core/src/airflow/ui/src/components/HITLReview/HITLReviewDetailSummary.tsx:
##########
@@ -0,0 +1,86 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { Table, Text } from "@chakra-ui/react";
+import dayjs from "dayjs";
+import tz from "dayjs/plugin/timezone";
+import utc from "dayjs/plugin/utc";
+import type { ReactNode } from "react";
+import { useTranslation } from "react-i18next";
+
+import type { HITLDetail } from "openapi/requests/types.gen.ts";
+import Time from "src/components/Time.tsx";
+import { useTimezone } from "src/context/timezone";
+import { getRelativeTime } from "src/utils/datetimeUtils.ts";
+
+dayjs.extend(utc);
+dayjs.extend(tz);
+
+const getHitlReviewDetailDateFormat = (datetime: string, timezone: string) =>
+  dayjs(datetime).tz(timezone).isSame(dayjs().tz(timezone), "day") ? 
"HH:mm:ss" : "ddd, MMM D, HH:mm:ss";

Review Comment:
   `ddd, MMM D, HH:mm:ss` 
   
   This particular format doesn't seem consistent with the rest of the App. 
That's the only place it's defined like this. Should we update it to follow a 
more common format that already exists in the code base? 
   



##########
airflow-core/src/airflow/ui/src/router.tsx:
##########
@@ -188,7 +188,7 @@ export const routerConfig = [
           { element: <DagRuns />, path: "runs" },
           { element: <Tasks />, path: "tasks" },
           { element: <Calendar />, path: "calendar" },
-          { element: <HITLTaskInstances />, path: "required_actions" },
+          { element: <Overview />, path: "required_actions" },

Review Comment:
   Not sure if we should start doing this. 
   
   "for backwrad compatibility' I understand. But on the other side we also 
sometimes do breaking change in the UI consciously. And it was always accepted 
that the UI can hold breaking changes 🤔 



##########
airflow-core/src/airflow/ui/src/router.tsx:
##########
@@ -188,7 +188,7 @@ export const routerConfig = [
           { element: <DagRuns />, path: "runs" },
           { element: <Tasks />, path: "tasks" },
           { element: <Calendar />, path: "calendar" },
-          { element: <HITLTaskInstances />, path: "required_actions" },
+          { element: <Overview />, path: "required_actions" },
           { element: <Backfills />, path: "backfills" },

Review Comment:
   Also should we also use the Modal for 'Tasks' HITL ? Instead of keep the tab?



##########
airflow-core/src/airflow/ui/src/components/HITLReview/useHITLReviewModalSelection.ts:
##########
@@ -0,0 +1,64 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { useState } from "react";
+
+import type { HITLDetail } from "openapi/requests/types.gen.ts";
+
+export const useHITLReviewModalSelection = ({ hitlDetails }: { readonly 
hitlDetails: Array<HITLDetail> }) => {
+  const [selectedHITLDetailKey, setSelectedHITLDetailKey] = useState<string | 
undefined>(undefined);
+
+  const selectedIndex = (() => {
+    if (hitlDetails.length === 0) {
+      return -1;
+    }
+
+    const selectedIndexFromKey = hitlDetails.findIndex(
+      (hitlDetail) => hitlDetail.task_instance.id === selectedHITLDetailKey,
+    );
+
+    return selectedIndexFromKey === -1 ? 0 : selectedIndexFromKey;
+  })();
+  const isSelected = selectedIndex !== -1;
+
+  const hasNext = isSelected && selectedIndex < hitlDetails.length - 1;
+  const hasPrevious = selectedIndex > 0;
+
+  const onSelect = (hitl?: HITLDetail) => 
setSelectedHITLDetailKey(hitl?.task_instance.id);
+
+  const onNext = () => {
+    if (hasNext) {
+      onSelect(hitlDetails[selectedIndex + 1]);
+    }
+  };
+
+  const onPrevious = () => {
+    if (hasPrevious) {
+      onSelect(hitlDetails[selectedIndex - 1]);
+    }
+  };

Review Comment:
   I'm not sure to understand why we need those two buttons to select previous 
and next ? 
   
   This feel unnecessary to me, clicking on the row of interest seem enough. 
(And that's confusing with pagination selector)



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