This is an automated email from the ASF dual-hosted git repository.
phanikumv pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 95ed08ef3b Made filters bar collapsible and add a full screen toggle
(#38296)
95ed08ef3b is described below
commit 95ed08ef3bbd634f9bd06dcb619b476c7b4baa61
Author: Brent Bovenzi <[email protected]>
AuthorDate: Tue Mar 19 20:33:40 2024 -0700
Made filters bar collapsible and add a full screen toggle (#38296)
---
airflow/www/static/js/dag/Main.tsx | 65 ++++++++++++++++++++--
airflow/www/static/js/dag/details/graph/index.tsx | 34 +++++++----
airflow/www/static/js/dag/details/index.tsx | 8 +++
.../js/dag/details/taskInstance/Logs/index.tsx | 20 ++++++-
airflow/www/static/js/dag/nav/FilterBar.tsx | 9 +--
5 files changed, 111 insertions(+), 25 deletions(-)
diff --git a/airflow/www/static/js/dag/Main.tsx
b/airflow/www/static/js/dag/Main.tsx
index 9a4ace85eb..d64534113b 100644
--- a/airflow/www/static/js/dag/Main.tsx
+++ b/airflow/www/static/js/dag/Main.tsx
@@ -20,15 +20,27 @@
/* global localStorage */
import React, { useState, useRef, useEffect, useCallback } from "react";
-import { Box, Flex, Divider, Spinner, useDisclosure } from "@chakra-ui/react";
+import {
+ Box,
+ Flex,
+ Spinner,
+ useDisclosure,
+ IconButton,
+ Accordion,
+ AccordionItem,
+ AccordionButton,
+ AccordionPanel,
+} from "@chakra-ui/react";
import { isEmpty, debounce } from "lodash";
+import { MdDoubleArrow } from "react-icons/md";
+import { useSearchParams } from "react-router-dom";
import { useGridData } from "src/api";
import { hoverDelay } from "src/utils";
import ShortcutCheatSheet from "src/components/ShortcutCheatSheet";
import { useKeysPress } from "src/utils/useKeysPress";
-import { useSearchParams } from "react-router-dom";
+
import Details, { TAB_PARAM } from "./details";
import Grid from "./grid";
import FilterBar from "./nav/FilterBar";
@@ -68,11 +80,20 @@ const MainInContext = () => {
isLoading,
} = useGridData();
const [isGridCollapsed, setIsGridCollapsed] = useState(false);
+
+ const [accordionIndexes, setAccordionIndexes] = useState<Array<number>>([0]);
+ const isFilterCollapsed = !accordionIndexes.length;
+ const toggleFilterCollapsed = () => {
+ if (isFilterCollapsed) setAccordionIndexes([0]);
+ else setAccordionIndexes([]);
+ };
+
const [searchParams] = useSearchParams();
const resizeRef = useRef<HTMLDivElement>(null);
const gridRef = useRef<HTMLDivElement>(null);
const gridScrollRef = useRef<HTMLDivElement>(null);
const ganttScrollRef = useRef<HTMLDivElement>(null);
+
const isPanelOpen =
localStorage.getItem(detailsPanelKey) !== "true" ||
!!searchParams.get(TAB_PARAM);
@@ -182,6 +203,17 @@ const MainInContext = () => {
onToggleShortcut
);
+ const isFullScreen = isFilterCollapsed && isGridCollapsed;
+ const toggleFullScreen = () => {
+ if (!isFullScreen) {
+ setAccordionIndexes([]);
+ setIsGridCollapsed(true);
+ } else {
+ setAccordionIndexes([0]);
+ setIsGridCollapsed(false);
+ }
+ };
+
return (
<Box
flex={1}
@@ -191,9 +223,30 @@ const MainInContext = () => {
overflow="hidden"
position="relative"
>
- <FilterBar />
- <LegendRow onStatusHover={onStatusHover} onStatusLeave={onStatusLeave} />
- <Divider mb={5} borderBottomWidth={2} />
+ <IconButton
+ position="absolute"
+ variant="ghost"
+ color="gray.400"
+ top={0}
+ left={0}
+ onClick={toggleFilterCollapsed}
+ icon={<MdDoubleArrow />}
+ aria-label="Toggle filters bar"
+ transform={isFilterCollapsed ? "rotateZ(90deg)" : "rotateZ(270deg)"}
+ transition="all 0.2s"
+ />
+ <Accordion allowToggle index={accordionIndexes} borderTopWidth={0}>
+ <AccordionItem>
+ <AccordionButton display="none" />
+ <AccordionPanel p={0}>
+ <FilterBar />
+ <LegendRow
+ onStatusHover={onStatusHover}
+ onStatusLeave={onStatusLeave}
+ />
+ </AccordionPanel>
+ </AccordionItem>
+ </Accordion>
<Flex height="100%">
{isLoading || isEmpty(groups) ? (
<Spinner />
@@ -240,6 +293,8 @@ const MainInContext = () => {
hoveredTaskState={hoveredTaskState}
gridScrollRef={gridScrollRef}
ganttScrollRef={ganttScrollRef}
+ isFullScreen={isFullScreen}
+ toggleFullScreen={toggleFullScreen}
/>
</Box>
</>
diff --git a/airflow/www/static/js/dag/details/graph/index.tsx
b/airflow/www/static/js/dag/details/graph/index.tsx
index 84f71313a3..3f34b86c73 100644
--- a/airflow/www/static/js/dag/details/graph/index.tsx
+++ b/airflow/www/static/js/dag/details/graph/index.tsx
@@ -28,7 +28,9 @@ import ReactFlow, {
Panel,
useOnViewportChange,
Viewport,
+ ControlButton,
} from "reactflow";
+import { BiCollapse, BiExpand } from "react-icons/bi";
import { useDatasets, useGraphData, useGridData } from "src/api";
import useSelection from "src/dag/useSelection";
@@ -47,11 +49,19 @@ interface Props {
openGroupIds: string[];
onToggleGroups: (groupIds: string[]) => void;
hoveredTaskState?: string | null;
+ isFullScreen?: boolean;
+ toggleFullScreen?: () => void;
}
const dagId = getMetaValue("dag_id");
-const Graph = ({ openGroupIds, onToggleGroups, hoveredTaskState }: Props) => {
+const Graph = ({
+ openGroupIds,
+ onToggleGroups,
+ hoveredTaskState,
+ isFullScreen,
+ toggleFullScreen,
+}: Props) => {
const graphRef = useRef(null);
const { data } = useGraphData();
const [arrange, setArrange] = useState(data?.arrange || "LR");
@@ -224,7 +234,15 @@ const Graph = ({ openGroupIds, onToggleGroups,
hoveredTaskState }: Props) => {
</Box>
</Panel>
<Background />
- <Controls showInteractive={false} />
+ <Controls showInteractive={false}>
+ <ControlButton
+ onClick={toggleFullScreen}
+ aria-label="Toggle full screen"
+ title="Toggle full screen"
+ >
+ {isFullScreen ? <BiCollapse /> : <BiExpand />}
+ </ControlButton>
+ </Controls>
<MiniMap
nodeStrokeWidth={15}
nodeStrokeColor={(props) => nodeStrokeColor(props, colors)}
@@ -238,17 +256,9 @@ const Graph = ({ openGroupIds, onToggleGroups,
hoveredTaskState }: Props) => {
);
};
-const GraphWrapper = ({
- openGroupIds,
- onToggleGroups,
- hoveredTaskState,
-}: Props) => (
+const GraphWrapper = (props: Props) => (
<ReactFlowProvider>
- <Graph
- openGroupIds={openGroupIds}
- onToggleGroups={onToggleGroups}
- hoveredTaskState={hoveredTaskState}
- />
+ <Graph {...props} />
</ReactFlowProvider>
);
diff --git a/airflow/www/static/js/dag/details/index.tsx
b/airflow/www/static/js/dag/details/index.tsx
index 6ef60e0120..0305fe0a2d 100644
--- a/airflow/www/static/js/dag/details/index.tsx
+++ b/airflow/www/static/js/dag/details/index.tsx
@@ -77,6 +77,8 @@ interface Props {
hoveredTaskState?: string | null;
gridScrollRef: React.RefObject<HTMLDivElement>;
ganttScrollRef: React.RefObject<HTMLDivElement>;
+ isFullScreen?: boolean;
+ toggleFullScreen?: () => void;
}
const tabToIndex = (tab?: string) => {
@@ -148,6 +150,8 @@ const Details = ({
hoveredTaskState,
gridScrollRef,
ganttScrollRef,
+ isFullScreen,
+ toggleFullScreen,
}: Props) => {
const {
selected: { runId, taskId, mapIndex },
@@ -407,6 +411,8 @@ const Details = ({
openGroupIds={openGroupIds}
onToggleGroups={onToggleGroups}
hoveredTaskState={hoveredTaskState}
+ isFullScreen={isFullScreen}
+ toggleFullScreen={toggleFullScreen}
/>
</TabPanel>
<TabPanel p={0} height="100%">
@@ -456,6 +462,8 @@ const Details = ({
? undefined
: instance.state
}
+ isFullScreen={isFullScreen}
+ toggleFullScreen={toggleFullScreen}
/>
</TabPanel>
)}
diff --git a/airflow/www/static/js/dag/details/taskInstance/Logs/index.tsx
b/airflow/www/static/js/dag/details/taskInstance/Logs/index.tsx
index 2b1035fb23..9e664fda20 100644
--- a/airflow/www/static/js/dag/details/taskInstance/Logs/index.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/Logs/index.tsx
@@ -27,8 +27,10 @@ import {
Icon,
Spinner,
Select,
+ IconButton,
} from "@chakra-ui/react";
import { MdWarning } from "react-icons/md";
+import { BiCollapse, BiExpand } from "react-icons/bi";
import { getMetaValue } from "src/utils";
import useTaskLog from "src/api/useTaskLog";
@@ -36,7 +38,6 @@ import LinkButton from "src/components/LinkButton";
import { useTimezone } from "src/context/timezone";
import type { Dag, DagRun, TaskInstance } from "src/types";
import MultiSelect from "src/components/MultiSelect";
-
import URLSearchParamsWrapper from "src/utils/URLSearchParamWrapper";
import LogLink from "./LogLink";
@@ -95,6 +96,8 @@ interface Props {
executionDate: DagRun["executionDate"];
tryNumber: TaskInstance["tryNumber"];
state?: TaskInstance["state"];
+ isFullScreen?: boolean;
+ toggleFullScreen?: () => void;
}
const Logs = ({
@@ -105,6 +108,8 @@ const Logs = ({
executionDate,
tryNumber,
state,
+ isFullScreen,
+ toggleFullScreen,
}: Props) => {
const [internalIndexes, externalIndexes] = getLinkIndexes(tryNumber);
const [selectedTryNumber, setSelectedTryNumber] = useState<
@@ -294,6 +299,19 @@ const Logs = ({
<LinkButton href={`${logUrl}&${params.toString()}`}>
See More
</LinkButton>
+ <IconButton
+ variant="ghost"
+ aria-label="Toggle full screen"
+ title="Toggle full screen"
+ onClick={toggleFullScreen}
+ icon={
+ isFullScreen ? (
+ <BiCollapse height="24px" />
+ ) : (
+ <BiExpand height="24px" />
+ )
+ }
+ />
</Flex>
</Flex>
</Box>
diff --git a/airflow/www/static/js/dag/nav/FilterBar.tsx
b/airflow/www/static/js/dag/nav/FilterBar.tsx
index 935ddac8d6..f03ea734b8 100644
--- a/airflow/www/static/js/dag/nav/FilterBar.tsx
+++ b/airflow/www/static/js/dag/nav/FilterBar.tsx
@@ -121,13 +121,8 @@ const FilterBar = () => {
});
return (
- <Flex
- backgroundColor="blackAlpha.200"
- mt={4}
- p={4}
- justifyContent="space-between"
- >
- <Flex>
+ <Flex backgroundColor="blackAlpha.200" p={4}
justifyContent="space-between">
+ <Flex ml={10}>
<Box px={2}>
<Input
{...inputStyles}