Skip to content

Commit

Permalink
Add search by dag_display_name_pattern on dag list page with rebase (a…
Browse files Browse the repository at this point in the history
…pache#42896)

* Add search by `dag_display_name_pattern` on dag list page.

* refactor search parameter update logic

* Refactor SearchBar component and simplify debounce logic in DagsList.

* Refactor search input change handling for SearchBar and DagsList components

* Update airflow/ui/src/pages/DagsList/DagsList.tsx

Co-authored-by: Brent Bovenzi <brent.bovenzi@gmail.com>

* Refactor search parameter handling and improve type consistency

* Remove typo

* Add `LAST_DAG_RUN_STATE` to `SearchParamsKeys` and update filters

* Add LAST_DAG_RUN_STATE to SearchParamsKeys and update filters

* Fix missing change for add SearchBar component by removing forwardRef and adding debounced search logic.

* minor change for SearchBar and DagsFilters components

* Optimize imports and improve formatting across components

* refactor: move query options from autogenerated useDagServiceGetDags to DagsList.

* Fix formatting.

---------

Co-authored-by: Brent Bovenzi <brent.bovenzi@gmail.com>
  • Loading branch information
2 people authored and Lorin committed Oct 17, 2024
1 parent 0898199 commit b3611f0
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 47 deletions.
3 changes: 2 additions & 1 deletion airflow/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.3.0",
"react-router-dom": "^6.26.2"
"react-router-dom": "^6.26.2",
"use-debounce": "^10.0.3"
},
"devDependencies": {
"@7nohe/openapi-react-query-codegen": "^1.6.0",
Expand Down
13 changes: 13 additions & 0 deletions airflow/ui/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions airflow/ui/src/components/DataTable/searchParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@
*/
import type { SortingState } from "@tanstack/react-table";

import {
SearchParamsKeys,
type SearchParamsKeysType,
} from "src/constants/searchParams";

import type { TableState } from "./types";

export const LIMIT_PARAM = "limit";
export const OFFSET_PARAM = "offset";
export const SORT_PARAM = "sort";
const {
LIMIT: LIMIT_PARAM,
OFFSET: OFFSET_PARAM,
SORT: SORT_PARAM,
}: SearchParamsKeysType = SearchParamsKeys;

export const stateToSearchParams = (
state: TableState,
Expand Down
62 changes: 39 additions & 23 deletions airflow/ui/src/components/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@
*/
import {
Button,
type ButtonProps,
Input,
InputGroup,
type InputGroupProps,
InputLeftElement,
type InputProps,
InputRightElement,
type ButtonProps,
type InputGroupProps,
type InputProps,
} from "@chakra-ui/react";
import type { ChangeEvent } from "react";
import { FiSearch } from "react-icons/fi";
import { useDebouncedCallback } from "use-debounce";

const debounceDelay = 200;

export const SearchBar = ({
buttonProps,
Expand All @@ -36,23 +40,35 @@ export const SearchBar = ({
readonly buttonProps?: ButtonProps;
readonly groupProps?: InputGroupProps;
readonly inputProps?: InputProps;
}) => (
<InputGroup {...groupProps}>
<InputLeftElement pointerEvents="none">
<FiSearch />
</InputLeftElement>
<Input placeholder="Search DAGs" pr={150} {...inputProps} />
<InputRightElement width={150}>
<Button
colorScheme="blue"
fontWeight="normal"
height="1.75rem"
variant="ghost"
width={140}
{...buttonProps}
>
Advanced Search
</Button>
</InputRightElement>
</InputGroup>
);
}) => {
const handleSearchChange = useDebouncedCallback(
(event: ChangeEvent<HTMLInputElement>) => inputProps?.onChange?.(event),
debounceDelay,
);

return (
<InputGroup {...groupProps}>
<InputLeftElement pointerEvents="none">
<FiSearch />
</InputLeftElement>
<Input
placeholder="Search DAGs"
pr={150}
{...inputProps}
onChange={handleSearchChange}
/>
<InputRightElement width={150}>
<Button
colorScheme="blue"
fontWeight="normal"
height="1.75rem"
variant="ghost"
width={140}
{...buttonProps}
>
Advanced Search
</Button>
</InputRightElement>
</InputGroup>
);
};
31 changes: 31 additions & 0 deletions airflow/ui/src/constants/searchParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*!
* 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.
*/
export enum SearchParamsKeys {
LAST_DAG_RUN_STATE = "last_dag_run_state",
LIMIT = "limit",
NAME_PATTERN = "name_pattern",
OFFSET = "offset",
PAUSED = "paused",
SORT = "sort",
}

export type SearchParamsKeysType = Record<
keyof typeof SearchParamsKeys,
string
>;
16 changes: 11 additions & 5 deletions airflow/ui/src/pages/DagsList/DagsFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,21 @@ import { useSearchParams } from "react-router-dom";

import { useTableURLState } from "src/components/DataTable/useTableUrlState";
import { QuickFilterButton } from "src/components/QuickFilterButton";
import {
SearchParamsKeys,
type SearchParamsKeysType,
} from "src/constants/searchParams";

const PAUSED_PARAM = "paused";
const STATE_PARAM = "last_dag_run_state";
const {
LAST_DAG_RUN_STATE: LAST_DAG_RUN_STATE_PARAM,
PAUSED: PAUSED_PARAM,
}: SearchParamsKeysType = SearchParamsKeys;

export const DagsFilters = () => {
const [searchParams, setSearchParams] = useSearchParams();

const showPaused = searchParams.get(PAUSED_PARAM);
const state = searchParams.get(STATE_PARAM);
const state = searchParams.get(LAST_DAG_RUN_STATE_PARAM);
const isAll = state === null;
const isRunning = state === "running";
const isFailed = state === "failed";
Expand Down Expand Up @@ -61,9 +67,9 @@ export const DagsFilters = () => {
useCallback(
({ currentTarget: { value } }) => {
if (value === "all") {
searchParams.delete(STATE_PARAM);
searchParams.delete(LAST_DAG_RUN_STATE_PARAM);
} else {
searchParams.set(STATE_PARAM, value);
searchParams.set(LAST_DAG_RUN_STATE_PARAM, value);
}
setSearchParams(searchParams);
setTableURLState({
Expand Down
78 changes: 63 additions & 15 deletions airflow/ui/src/pages/DagsList/DagsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ import {
VStack,
} from "@chakra-ui/react";
import type { ColumnDef } from "@tanstack/react-table";
import { type ChangeEventHandler, useCallback, useState } from "react";
import {
type ChangeEvent,
type ChangeEventHandler,
useCallback,
useState,
} from "react";
import { useSearchParams } from "react-router-dom";

import { useDagServiceGetDags } from "openapi/queries";
Expand All @@ -37,6 +42,10 @@ import { useTableURLState } from "src/components/DataTable/useTableUrlState";
import { ErrorAlert } from "src/components/ErrorAlert";
import { SearchBar } from "src/components/SearchBar";
import { TogglePause } from "src/components/TogglePause";
import {
SearchParamsKeys,
type SearchParamsKeysType,
} from "src/constants/searchParams";
import { pluralize } from "src/utils/pluralize";

import { DagCard } from "./DagCard";
Expand Down Expand Up @@ -90,38 +99,74 @@ const columns: Array<ColumnDef<DAGResponse>> = [
},
];

const {
LAST_DAG_RUN_STATE: LAST_DAG_RUN_STATE_PARAM,
NAME_PATTERN: NAME_PATTERN_PARAM,
PAUSED: PAUSED_PARAM,
}: SearchParamsKeysType = SearchParamsKeys;

const cardDef: CardDef<DAGResponse> = {
card: ({ row }) => <DagCard dag={row} />,
meta: {
customSkeleton: <Skeleton height="120px" width="100%" />,
},
};

const PAUSED_PARAM = "paused";
const STATE_PARAM = "last_dag_run_state";

export const DagsList = () => {
const [searchParams] = useSearchParams();
const [searchParams, setSearchParams] = useSearchParams();
const [display, setDisplay] = useState<"card" | "table">("card");

const showPaused = searchParams.get(PAUSED_PARAM);
const lastDagRunState = searchParams.get(STATE_PARAM) as DagRunState;
const lastDagRunState = searchParams.get(
LAST_DAG_RUN_STATE_PARAM,
) as DagRunState;

const { setTableURLState, tableURLState } = useTableURLState();
const { pagination, sorting } = tableURLState;
const [dagDisplayNamePattern, setDagDisplayNamePattern] = useState(
searchParams.get(NAME_PATTERN_PARAM) ?? undefined,
);

// TODO: update API to accept multiple orderBy params
const [sort] = sorting;
const orderBy = sort ? `${sort.desc ? "-" : ""}${sort.id}` : undefined;

const { data, error, isFetching, isLoading } = useDagServiceGetDags({
lastDagRunState,
limit: pagination.pageSize,
offset: pagination.pageIndex * pagination.pageSize,
onlyActive: true,
orderBy,
paused: showPaused === null ? undefined : showPaused === "true",
});
const handleSearchChange = ({
target: { value },
}: ChangeEvent<HTMLInputElement>) => {
if (value) {
searchParams.set(NAME_PATTERN_PARAM, value);
} else {
searchParams.delete(NAME_PATTERN_PARAM);
}
setSearchParams(searchParams);
setTableURLState({
pagination: { ...pagination, pageIndex: 0 },
sorting,
});
setDagDisplayNamePattern(value);
};

const { data, error, isFetching, isLoading } = useDagServiceGetDags(
{
dagDisplayNamePattern: Boolean(dagDisplayNamePattern)
? `%${dagDisplayNamePattern}%`
: undefined,
lastDagRunState,
limit: pagination.pageSize,
offset: pagination.pageIndex * pagination.pageSize,
onlyActive: true,
orderBy,
paused: showPaused === null ? undefined : showPaused === "true",
},
[dagDisplayNamePattern, showPaused],
{
refetchOnMount: true,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 1000,
},
);

const handleSortChange = useCallback<ChangeEventHandler<HTMLSelectElement>>(
({ currentTarget: { value } }) => {
Expand All @@ -140,7 +185,10 @@ export const DagsList = () => {
<VStack alignItems="none">
<SearchBar
buttonProps={{ isDisabled: true }}
inputProps={{ isDisabled: true }}
inputProps={{
defaultValue: dagDisplayNamePattern,
onChange: handleSearchChange,
}}
/>
<DagsFilters />
<HStack justifyContent="space-between">
Expand Down

0 comments on commit b3611f0

Please sign in to comment.