diff --git a/airflow/ui/src/constants/searchParams.ts b/airflow/ui/src/constants/searchParams.ts index 821fb6d474460..65c5b2056f5c6 100644 --- a/airflow/ui/src/constants/searchParams.ts +++ b/airflow/ui/src/constants/searchParams.ts @@ -26,6 +26,7 @@ export enum SearchParamsKeys { OFFSET = "offset", PAUSED = "paused", SORT = "sort", + SOURCE = "log_source", START_DATE = "start_date", STATE = "state", TAGS = "tags", diff --git a/airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx b/airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx index 5c7306381270e..e06c301da2c9e 100644 --- a/airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx +++ b/airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx @@ -35,6 +35,7 @@ export const Logs = () => { const tryNumberParam = searchParams.get(SearchParamsKeys.TRY_NUMBER); const logLevelFilters = searchParams.getAll(SearchParamsKeys.LOG_LEVEL); + const sourceFilters = searchParams.getAll(SearchParamsKeys.SOURCE); const { data: taskInstance, @@ -77,6 +78,7 @@ export const Logs = () => { } = useLogs({ dagId, logLevelFilters, + sourceFilters, taskInstance, tryNumber: tryNumber === 0 ? 1 : tryNumber, }); @@ -85,6 +87,7 @@ export const Logs = () => { void; + readonly sourceOptions?: Array; readonly taskInstance?: TaskInstanceResponse; readonly toggleFullscreen: () => void; readonly toggleWrap: () => void; @@ -40,6 +48,7 @@ type Props = { export const TaskLogHeader = ({ isFullscreen = false, onSelectTryNumber, + sourceOptions, taskInstance, toggleFullscreen, toggleWrap, @@ -47,11 +56,21 @@ export const TaskLogHeader = ({ wrap, }: Props) => { const [searchParams, setSearchParams] = useSearchParams(); - + const sources = searchParams.getAll(SearchParamsKeys.SOURCE); const logLevels = searchParams.getAll(SearchParamsKeys.LOG_LEVEL); const hasLogLevels = logLevels.length > 0; - const handleStateChange = useCallback( + const sourceOptionList = createListCollection<{ + label: string; + value: string; + }>({ + items: [ + { label: "All Sources", value: "all" }, + ...(sourceOptions ?? []).map((source) => ({ label: source, value: source })), + ], + }); + + const handleLevelChange = useCallback( ({ value }: SelectValueChangeDetails) => { const [val, ...rest] = value; @@ -68,6 +87,23 @@ export const TaskLogHeader = ({ [searchParams, setSearchParams], ); + const handleSourceChange = useCallback( + ({ value }: SelectValueChangeDetails) => { + const [val, ...rest] = value; + + if ((val === undefined || val === "all") && rest.length === 0) { + searchParams.delete(SearchParamsKeys.SOURCE); + } else { + searchParams.delete(SearchParamsKeys.SOURCE); + value + .filter((state) => state !== "all") + .map((state) => searchParams.append(SearchParamsKeys.SOURCE, state)); + } + setSearchParams(searchParams); + }, + [searchParams, setSearchParams], + ); + return ( {taskInstance === undefined || tryNumber === undefined || taskInstance.try_number <= 1 ? undefined : ( @@ -82,7 +118,7 @@ export const TaskLogHeader = ({ collection={logLevelOptions} maxW="250px" multiple - onValueChange={handleStateChange} + onValueChange={handleLevelChange} value={hasLogLevels ? logLevels : ["all"]} > @@ -114,6 +150,26 @@ export const TaskLogHeader = ({ ))} + {sourceOptions !== undefined && sourceOptions.length > 0 ? ( + + + + + + {sourceOptionList.items.map((option) => ( + + {option.label} + + ))} + + + ) : undefined}