Pei-Cheng-Yu commented on code in PR #56920:
URL: https://github.com/apache/airflow/pull/56920#discussion_r2454308084
##########
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstancesFilter.tsx:
##########
@@ -16,39 +16,122 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { HStack, type SelectValueChangeDetails } from "@chakra-ui/react";
-import { useCallback } from "react";
+import { HStack, VStack, type SelectValueChangeDetails, Box } from
"@chakra-ui/react";
+import { useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useSearchParams, useParams } from "react-router-dom";
-import type { TaskInstanceState } from "openapi/requests/types.gen";
+import type { TaskInstanceCollectionResponse } from "openapi/requests";
import { useTableURLState } from "src/components/DataTable/useTableUrlState";
+import { FilterBar, type FilterValue } from "src/components/FilterBar";
import { SearchBar } from "src/components/SearchBar";
-import { StateBadge } from "src/components/StateBadge";
-import { Select } from "src/components/ui";
+import { ResetButton } from "src/components/ui";
import { SearchParamsKeys, type SearchParamsKeysType } from
"src/constants/searchParams";
-import { taskInstanceStateOptions } from "src/constants/stateOptions";
+import { useFiltersHandler, type FilterableSearchParamsKeys } from "src/utils";
+
+import { AttrSelectFilterMulti } from "./AttrSelectFilterMulti";
+import { StateFilter } from "./StateFilter";
const {
DAG_ID_PATTERN: DAG_ID_PATTERN_PARAM,
+ DAG_VERSION: DAG_VERSION_PARAM,
+ DURATION_GTE: DURATION_GTE_PARAM,
+ DURATION_LTE: DURATION_LTE_PARAM,
+ END_DATE: END_DATE_PARAM,
+ LOGICAL_DATE_GTE: LOGICAL_DATE_GTE_PARAM,
+ LOGICAL_DATE_LTE: LOGICAL_DATE_LTE_PARAM,
+ MAP_INDEX: MAP_INDEX_PARAM,
NAME_PATTERN: NAME_PATTERN_PARAM,
+ OPERATOR: OPERATOR_PARAM,
+ POOL: POOL_PARAM,
+ QUEUE: QUEUE_PARAM,
+ RUN_ID: RUN_ID_PARAM,
+ START_DATE: START_DATE_PARAM,
STATE: STATE_PARAM,
+ TRY_NUMBER: TRY_NUMBER_PARAM,
}: SearchParamsKeysType = SearchParamsKeys;
+type Props = {
+ readonly instances?: TaskInstanceCollectionResponse | undefined;
+ readonly setTaskDisplayNamePattern:
React.Dispatch<React.SetStateAction<string | undefined>>;
+ readonly taskDisplayNamePattern: string | undefined;
+};
+
export const TaskInstancesFilter = ({
+ instances,
setTaskDisplayNamePattern,
taskDisplayNamePattern,
-}: {
- readonly setTaskDisplayNamePattern:
React.Dispatch<React.SetStateAction<string | undefined>>;
- readonly taskDisplayNamePattern: string | undefined;
-}) => {
+}: Props) => {
const { dagId, runId } = useParams();
+ const paramKeys = useMemo((): Array<FilterableSearchParamsKeys> => {
+ const keys: Array<FilterableSearchParamsKeys> = [
+ LOGICAL_DATE_GTE_PARAM as FilterableSearchParamsKeys,
+ LOGICAL_DATE_LTE_PARAM as FilterableSearchParamsKeys,
+ START_DATE_PARAM as FilterableSearchParamsKeys,
+ END_DATE_PARAM as FilterableSearchParamsKeys,
+ DURATION_GTE_PARAM as FilterableSearchParamsKeys,
+ DURATION_LTE_PARAM as FilterableSearchParamsKeys,
+ TRY_NUMBER_PARAM as FilterableSearchParamsKeys,
+ MAP_INDEX_PARAM as FilterableSearchParamsKeys,
+ DAG_VERSION_PARAM as FilterableSearchParamsKeys,
+ ];
+
+ if (runId === undefined) {
+ keys.splice(1, 0, RUN_ID_PARAM as FilterableSearchParamsKeys);
+ }
+
+ return keys;
+ }, [runId]);
+
const [searchParams, setSearchParams] = useSearchParams();
const { setTableURLState, tableURLState } = useTableURLState();
const { pagination, sorting } = tableURLState;
const { t: translate } = useTranslation();
+ const { filterConfigs, handleFiltersChange } = useFiltersHandler(paramKeys);
+
+ const uniq = (xs: Array<string | null | undefined>) => [
+ ...new Set(xs.filter((x): x is string => x !== null && x !== undefined &&
x !== "")),
+ ];
+
+ const resetPagination = useCallback(() => {
+ setTableURLState({
+ pagination: { ...pagination, pageIndex: 0 },
+ sorting,
+ });
+ }, [pagination, sorting, setTableURLState]);
+
+ const setMultiParam = useCallback(
+ (key: string, values: Array<string>) => {
+ resetPagination();
+ setSearchParams((prev) => {
+ const next = new URLSearchParams(prev);
+
+ next.delete(key);
+ values.forEach((val) => next.append(key, val));
+
+ return next;
+ });
+ },
+ [resetPagination, setSearchParams],
+ );
+
+ const allOperatorNames: Array<string> = uniq(
+ instances?.task_instances.map((ti) => ti.operator_name as string | null |
undefined) ?? [],
+ );
+ const allQueueValues: Array<string> = uniq(
+ instances?.task_instances.map((ti) => ti.queue as string | null |
undefined) ?? [],
+ );
+ const allPoolValues: Array<string> = uniq(
+ instances?.task_instances.map((ti) => ti.pool as string | null |
undefined) ?? [],
+ );
Review Comment:
@bbovenzi Hi, I noticed a mismatch between what we display and what we
filter on.
UI shows `custom_operator_name` on `Operator` Column
<img width="1252" height="131" alt="image"
src="https://github.com/user-attachments/assets/61241159-d6a8-4332-821a-c2c2a480dd6a"
/>
<img width="372" height="81" alt="image"
src="https://github.com/user-attachments/assets/1dd79b44-d421-4b6c-a596-be8a17ced1b6"
/>
while the query logic in
`airflow-core/src/airflow/api_fastapi/core_api/routes/public/task_instances.py`
is filtering on `operator`.[#54773]
In this situation, when a user types the operator name shown on the frontend
(e.g., @task), the filter won’t return any results unless they type the actual
class name (e.g., _Python........).
Should I fix the query logic for the `operator` from filtering `operator`
to filtering `custom_operator_name` ?
If I am going to fix it, I will need to open another PR for that, right?
Let me know which approach you prefer.
Thanks!
--
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]