You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ep...@apache.org on 2023/08/03 12:36:03 UTC

[airflow] 01/09: Only load task action modal if user can edit (#32992)

This is an automated email from the ASF dual-hosted git repository.

ephraimanierobi pushed a commit to branch v2-7-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 9d4848dce7529662567dae0fac65aeb45bedbdf8
Author: Brent Bovenzi <br...@astronomer.io>
AuthorDate: Thu Aug 3 16:29:03 2023 +0800

    Only load task action modal if user can edit (#32992)
    
    (cherry picked from commit 943b97850a1e82e4da22e8489c4ede958a42213d)
---
 .../taskInstance/taskActions/ClearInstance.tsx     | 222 +++++++++++--------
 .../taskInstance/taskActions/MarkInstanceAs.tsx    | 244 ++++++++++++---------
 2 files changed, 265 insertions(+), 201 deletions(-)

diff --git a/airflow/www/static/js/dag/details/taskInstance/taskActions/ClearInstance.tsx b/airflow/www/static/js/dag/details/taskInstance/taskActions/ClearInstance.tsx
index 885310f41f..d935f99e65 100644
--- a/airflow/www/static/js/dag/details/taskInstance/taskActions/ClearInstance.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/taskActions/ClearInstance.tsx
@@ -41,7 +41,7 @@ import ActionModal from "./ActionModal";
 const canEdit = getMetaValue("can_edit") === "True";
 const dagId = getMetaValue("dag_id");
 
-interface Props extends ButtonProps {
+interface Props {
   runId: string;
   taskId: string;
   executionDate: string;
@@ -50,17 +50,21 @@ interface Props extends ButtonProps {
   mapIndex?: number;
 }
 
-const ClearInstance = ({
+interface ClearModalProps extends Props {
+  isOpen: boolean;
+  onClose: () => void;
+}
+
+const ClearModal = ({
   runId,
   taskId,
   mapIndex,
   executionDate,
   isGroup,
   isMapped,
-  ...otherProps
-}: Props) => {
-  const { onOpen, onClose, isOpen } = useDisclosure();
-
+  isOpen,
+  onClose,
+}: ClearModalProps) => {
   const [past, setPast] = useState(false);
   const onTogglePast = () => setPast(!past);
 
@@ -81,8 +85,6 @@ const ClearInstance = ({
 
   const initialClearButtonFocusRef = useRef<HTMLButtonElement>(null);
 
-  useKeysPress(keyboardShortcutIdentifier.taskRunClear, onOpen);
-
   const mapIndexes =
     mapIndex !== undefined && mapIndex !== -1 ? [mapIndex] : undefined;
 
@@ -134,6 +136,110 @@ const ClearInstance = ({
     resetModal();
   };
 
+  return (
+    <ActionModal
+      isOpen={isOpen}
+      onClose={resetModal}
+      header="Clear and Retry"
+      subheader={
+        <>
+          <Text>
+            <Text as="strong" mr={1}>
+              Task:
+            </Text>
+            {taskId}
+          </Text>
+          <Text>
+            <Text as="strong" mr={1}>
+              Run:
+            </Text>
+            {runId}
+          </Text>
+          {isMapped && (
+            <Text>
+              <Text as="strong" mr={1}>
+                Map Index:
+              </Text>
+              {mapIndex !== undefined ? mapIndex : `All mapped tasks`}
+            </Text>
+          )}
+        </>
+      }
+      affectedTasks={affectedTasks}
+      submitButton={
+        <Button
+          ref={initialClearButtonFocusRef}
+          colorScheme="blue"
+          isLoading={isLoading || isLoadingDryRun}
+          isDisabled={!affectedTasks?.length}
+          onClick={onClear}
+        >
+          Clear
+        </Button>
+      }
+      initialFocusRef={initialClearButtonFocusRef}
+    >
+      <Box>
+        <Text>Include: </Text>
+        <ButtonGroup isAttached variant="outline" isDisabled={!canEdit}>
+          <ActionButton
+            bg={past ? "gray.100" : undefined}
+            onClick={onTogglePast}
+            name="Past"
+          />
+          <ActionButton
+            bg={future ? "gray.100" : undefined}
+            onClick={onToggleFuture}
+            name="Future"
+          />
+          <ActionButton
+            bg={upstream ? "gray.100" : undefined}
+            onClick={onToggleUpstream}
+            name="Upstream"
+          />
+          <ActionButton
+            bg={downstream ? "gray.100" : undefined}
+            onClick={onToggleDownstream}
+            name="Downstream"
+          />
+          <ActionButton
+            bg={recursive ? "gray.100" : undefined}
+            onClick={onToggleRecursive}
+            name="Recursive"
+          />
+          <ActionButton
+            bg={failed ? "gray.100" : undefined}
+            onClick={onToggleFailed}
+            name="Failed"
+          />
+        </ButtonGroup>
+      </Box>
+      {isGroup && (past || future) && (
+        <Alert status="warning" my={3}>
+          <AlertIcon />
+          Clearing a TaskGroup in the future and/or past will affect all the
+          tasks of this group across multiple dag runs.
+          <br />
+          This can take a while to complete.
+        </Alert>
+      )}
+    </ActionModal>
+  );
+};
+
+const ClearInstance = ({
+  runId,
+  taskId,
+  mapIndex,
+  executionDate,
+  isGroup,
+  isMapped,
+  ...otherProps
+}: Props & ButtonProps) => {
+  const { onOpen, onClose, isOpen } = useDisclosure();
+
+  useKeysPress(keyboardShortcutIdentifier.taskRunClear, onOpen);
+
   const clearLabel = "Clear and retry task.";
 
   return (
@@ -148,93 +254,19 @@ const ClearInstance = ({
       >
         Clear task
       </Button>
-      <ActionModal
-        isOpen={isOpen}
-        onClose={resetModal}
-        header="Clear and Retry"
-        subheader={
-          <>
-            <Text>
-              <Text as="strong" mr={1}>
-                Task:
-              </Text>
-              {taskId}
-            </Text>
-            <Text>
-              <Text as="strong" mr={1}>
-                Run:
-              </Text>
-              {runId}
-            </Text>
-            {isMapped && (
-              <Text>
-                <Text as="strong" mr={1}>
-                  Map Index:
-                </Text>
-                {mapIndex !== undefined ? mapIndex : `All mapped tasks`}
-              </Text>
-            )}
-          </>
-        }
-        affectedTasks={affectedTasks}
-        submitButton={
-          <Button
-            ref={initialClearButtonFocusRef}
-            colorScheme="blue"
-            isLoading={isLoading || isLoadingDryRun}
-            isDisabled={!affectedTasks?.length}
-            onClick={onClear}
-          >
-            Clear
-          </Button>
-        }
-        initialFocusRef={initialClearButtonFocusRef}
-      >
-        <Box>
-          <Text>Include: </Text>
-          <ButtonGroup isAttached variant="outline" isDisabled={!canEdit}>
-            <ActionButton
-              bg={past ? "gray.100" : undefined}
-              onClick={onTogglePast}
-              name="Past"
-            />
-            <ActionButton
-              bg={future ? "gray.100" : undefined}
-              onClick={onToggleFuture}
-              name="Future"
-            />
-            <ActionButton
-              bg={upstream ? "gray.100" : undefined}
-              onClick={onToggleUpstream}
-              name="Upstream"
-            />
-            <ActionButton
-              bg={downstream ? "gray.100" : undefined}
-              onClick={onToggleDownstream}
-              name="Downstream"
-            />
-            <ActionButton
-              bg={recursive ? "gray.100" : undefined}
-              onClick={onToggleRecursive}
-              name="Recursive"
-            />
-            <ActionButton
-              bg={failed ? "gray.100" : undefined}
-              onClick={onToggleFailed}
-              name="Failed"
-            />
-          </ButtonGroup>
-        </Box>
-        {isGroup && (past || future) && (
-          <Alert status="warning" my={3}>
-            <AlertIcon />
-            Clearing a TaskGroup in the future and/or past will affect all the
-            tasks of this group across multiple dag runs.
-            <br />
-            This can take a while to complete.
-          </Alert>
-        )}
-      </ActionModal>
+      {/* Only mount modal if user can edit */}
+      {canEdit && (
+        <ClearModal
+          runId={runId}
+          taskId={taskId}
+          mapIndex={mapIndex}
+          executionDate={executionDate}
+          isGroup={isGroup}
+          isMapped={isMapped}
+          isOpen={isOpen}
+          onClose={onClose}
+        />
+      )}
     </>
   );
 };
diff --git a/airflow/www/static/js/dag/details/taskInstance/taskActions/MarkInstanceAs.tsx b/airflow/www/static/js/dag/details/taskInstance/taskActions/MarkInstanceAs.tsx
index 09045877d0..e88108e098 100644
--- a/airflow/www/static/js/dag/details/taskInstance/taskActions/MarkInstanceAs.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/taskActions/MarkInstanceAs.tsx
@@ -53,7 +53,7 @@ import ActionModal from "./ActionModal";
 const canEdit = getMetaValue("can_edit") === "True";
 const dagId = getMetaValue("dag_id");
 
-interface Props extends MenuButtonProps {
+interface Props {
   runId: string;
   taskId: string;
   state?: TaskState;
@@ -62,19 +62,22 @@ interface Props extends MenuButtonProps {
   isMapped?: boolean;
 }
 
-const MarkInstanceAs = ({
+interface ModalProps extends Props {
+  isOpen: boolean;
+  onClose: () => void;
+  state: TaskState;
+}
+
+const MarkAsModal = ({
   runId,
   taskId,
   isGroup,
   mapIndex,
   isMapped,
-  state: currentState,
-  ...otherProps
-}: Props) => {
-  const { onOpen, onClose, isOpen } = useDisclosure();
-
-  const [newState, setNewState] = useState<"failed" | "success">("success");
-
+  state,
+  isOpen,
+  onClose,
+}: ModalProps) => {
   const [past, setPast] = useState(false);
   const onTogglePast = () => setPast(!past);
 
@@ -89,16 +92,6 @@ const MarkInstanceAs = ({
 
   const initialMarkAsButtonFocusRef = useRef<HTMLButtonElement>(null);
 
-  const markAsFailed = () => {
-    setNewState("failed");
-    onOpen();
-  };
-
-  const markAsSuccess = () => {
-    setNewState("success");
-    onOpen();
-  };
-
   const mapIndexes =
     mapIndex !== undefined && mapIndex !== -1 ? [mapIndex] : undefined;
 
@@ -107,7 +100,7 @@ const MarkInstanceAs = ({
       dagId,
       runId,
       taskId,
-      state: newState,
+      state,
       isGroup: !!isGroup,
       past,
       future,
@@ -142,7 +135,7 @@ const MarkInstanceAs = ({
   };
 
   const onMarkState = () => {
-    if (newState === "success") {
+    if (state === "success") {
       markSuccessMutation({
         past,
         future,
@@ -150,7 +143,7 @@ const MarkInstanceAs = ({
         downstream,
         mapIndexes,
       });
-    } else if (newState === "failed") {
+    } else if (state === "failed") {
       markFailedMutation({
         past,
         future,
@@ -162,6 +155,116 @@ const MarkInstanceAs = ({
     resetModal();
   };
 
+  return (
+    <ActionModal
+      isOpen={isOpen}
+      onClose={resetModal}
+      header={`Mark as ${capitalize(state || "")}`}
+      subheader={
+        <>
+          <Text>
+            <Text as="strong" mr={1}>
+              Task:
+            </Text>
+            {taskId}
+          </Text>
+          <Text>
+            <Text as="strong" mr={1}>
+              Run:
+            </Text>
+            {runId}
+          </Text>
+          {isMapped && (
+            <Text>
+              <Text as="strong" mr={1}>
+                Map Index:
+              </Text>
+              {mapIndex !== undefined ? mapIndex : `All mapped tasks`}
+            </Text>
+          )}
+        </>
+      }
+      affectedTasks={affectedTasks}
+      submitButton={
+        <Button
+          ref={initialMarkAsButtonFocusRef}
+          colorScheme={
+            (state === "success" && "green") ||
+            (state === "failed" && "red") ||
+            "grey"
+          }
+          isLoading={
+            isLoadingDryRun || isMarkSuccessLoading || isMarkFailedLoading
+          }
+          isDisabled={!affectedTasks?.length || !state}
+          onClick={onMarkState}
+        >
+          Mark as {state}
+        </Button>
+      }
+      initialFocusRef={initialMarkAsButtonFocusRef}
+    >
+      <Box>
+        <Text>Include: </Text>
+        <ButtonGroup isAttached variant="outline" isDisabled={!canEdit}>
+          <ActionButton
+            bg={past ? "gray.100" : undefined}
+            onClick={onTogglePast}
+            name="Past"
+          />
+          <ActionButton
+            bg={future ? "gray.100" : undefined}
+            onClick={onToggleFuture}
+            name="Future"
+          />
+          <ActionButton
+            bg={upstream ? "gray.100" : undefined}
+            onClick={onToggleUpstream}
+            name="Upstream"
+          />
+          <ActionButton
+            bg={downstream ? "gray.100" : undefined}
+            onClick={onToggleDownstream}
+            name="Downstream"
+          />
+        </ButtonGroup>
+      </Box>
+      {isGroup && (past || future) && (
+        <Alert status="warning" my={3}>
+          <AlertIcon />
+          Marking a TaskGroup as {capitalize(state || "")} in the future and/or
+          past will affect all the tasks of this group across multiple dag runs.
+          <br />
+          This can take a while to complete.
+        </Alert>
+      )}
+    </ActionModal>
+  );
+};
+
+const MarkInstanceAs = ({
+  runId,
+  taskId,
+  isGroup,
+  mapIndex,
+  isMapped,
+  state: currentState,
+  ...otherProps
+}: Props & MenuButtonProps) => {
+  const { onOpen, onClose, isOpen } = useDisclosure();
+
+  const [newState, setNewState] = useState<"failed" | "success">("success");
+
+  const markAsFailed = () => {
+    setNewState("failed");
+    onOpen();
+  };
+
+  const markAsSuccess = () => {
+    setNewState("success");
+    onOpen();
+  };
+
   const markLabel = "Manually set task instance state";
   const isMappedSummary = isMapped && mapIndex === undefined;
 
@@ -209,90 +312,19 @@ const MarkInstanceAs = ({
           </MenuItem>
         </MenuList>
       </Menu>
-      <ActionModal
-        isOpen={isOpen}
-        onClose={resetModal}
-        header={`Mark as ${capitalize(newState)}`}
-        subheader={
-          <>
-            <Text>
-              <Text as="strong" mr={1}>
-                Task:
-              </Text>
-              {taskId}
-            </Text>
-            <Text>
-              <Text as="strong" mr={1}>
-                Run:
-              </Text>
-              {runId}
-            </Text>
-            {isMapped && (
-              <Text>
-                <Text as="strong" mr={1}>
-                  Map Index:
-                </Text>
-                {mapIndex !== undefined ? mapIndex : `All mapped tasks`}
-              </Text>
-            )}
-          </>
-        }
-        affectedTasks={affectedTasks}
-        submitButton={
-          <Button
-            ref={initialMarkAsButtonFocusRef}
-            colorScheme={
-              (newState === "success" && "green") ||
-              (newState === "failed" && "red") ||
-              "grey"
-            }
-            isLoading={
-              isLoadingDryRun || isMarkSuccessLoading || isMarkFailedLoading
-            }
-            isDisabled={!affectedTasks?.length || !newState}
-            onClick={onMarkState}
-          >
-            Mark as {newState}
-          </Button>
-        }
-        initialFocusRef={initialMarkAsButtonFocusRef}
-      >
-        <Box>
-          <Text>Include: </Text>
-          <ButtonGroup isAttached variant="outline" isDisabled={!canEdit}>
-            <ActionButton
-              bg={past ? "gray.100" : undefined}
-              onClick={onTogglePast}
-              name="Past"
-            />
-            <ActionButton
-              bg={future ? "gray.100" : undefined}
-              onClick={onToggleFuture}
-              name="Future"
-            />
-            <ActionButton
-              bg={upstream ? "gray.100" : undefined}
-              onClick={onToggleUpstream}
-              name="Upstream"
-            />
-            <ActionButton
-              bg={downstream ? "gray.100" : undefined}
-              onClick={onToggleDownstream}
-              name="Downstream"
-            />
-          </ButtonGroup>
-        </Box>
-        {isGroup && (past || future) && (
-          <Alert status="warning" my={3}>
-            <AlertIcon />
-            Marking a TaskGroup as {capitalize(newState)} in the future and/or
-            past will affect all the tasks of this group across multiple dag
-            runs.
-            <br />
-            This can take a while to complete.
-          </Alert>
-        )}
-      </ActionModal>
+      {/* Only load modal is user can edit */}
+      {canEdit && (
+        <MarkAsModal
+          runId={runId}
+          taskId={taskId}
+          isGroup={isGroup}
+          mapIndex={mapIndex}
+          isMapped={isMapped}
+          state={newState}
+          isOpen={isOpen}
+          onClose={onClose}
+        />
+      )}
     </>
   );
 };