From 1b4b6995908259731b36bfb5463317eca6328891 Mon Sep 17 00:00:00 2001 From: Brent Bovenzi Date: Tue, 28 Jun 2022 15:26:13 -0400 Subject: [PATCH 1/3] upgrade more js files to ts --- .../grid/{AutoRefresh.jsx => AutoRefresh.tsx} | 2 +- .../js/grid/{ResetRoot.jsx => ResetRoot.tsx} | 0 .../{ToggleGroups.jsx => ToggleGroups.tsx} | 19 ++++++++----- .../{autorefresh.jsx => autorefresh.tsx} | 22 ++++++++++----- .../grid/dagRuns/{Tooltip.jsx => Tooltip.tsx} | 7 ++++- .../{ConfirmDialog.jsx => ConfirmDialog.tsx} | 14 ++++++++-- .../content/dagRun/{index.jsx => index.tsx} | 7 ++++- .../taskInstance/{Details.jsx => Details.tsx} | 20 +++++++++----- .../{ExtraLinks.jsx => ExtraLinks.tsx} | 12 +++++++-- .../content/taskInstance/{Nav.jsx => Nav.tsx} | 27 +++++++++++++------ .../details/content/taskInstance/index.tsx | 3 ++- 11 files changed, 98 insertions(+), 35 deletions(-) rename airflow/www/static/js/grid/{AutoRefresh.jsx => AutoRefresh.tsx} (97%) rename airflow/www/static/js/grid/{ResetRoot.jsx => ResetRoot.tsx} (100%) rename airflow/www/static/js/grid/{ToggleGroups.jsx => ToggleGroups.tsx} (81%) rename airflow/www/static/js/grid/context/{autorefresh.jsx => autorefresh.tsx} (87%) rename airflow/www/static/js/grid/dagRuns/{Tooltip.jsx => Tooltip.tsx} (93%) rename airflow/www/static/js/grid/details/content/{ConfirmDialog.jsx => ConfirmDialog.tsx} (90%) rename airflow/www/static/js/grid/details/content/dagRun/{index.jsx => index.tsx} (96%) rename airflow/www/static/js/grid/details/content/taskInstance/{Details.jsx => Details.tsx} (87%) rename airflow/www/static/js/grid/details/content/taskInstance/{ExtraLinks.jsx => ExtraLinks.tsx} (87%) rename airflow/www/static/js/grid/details/content/taskInstance/{Nav.jsx => Nav.tsx} (86%) diff --git a/airflow/www/static/js/grid/AutoRefresh.jsx b/airflow/www/static/js/grid/AutoRefresh.tsx similarity index 97% rename from airflow/www/static/js/grid/AutoRefresh.jsx rename to airflow/www/static/js/grid/AutoRefresh.tsx index b7c1c29206095..b198647fb2122 100644 --- a/airflow/www/static/js/grid/AutoRefresh.jsx +++ b/airflow/www/static/js/grid/AutoRefresh.tsx @@ -44,7 +44,7 @@ const AutoRefresh = () => { toggleRefresh(true)} + onChange={toggleRefresh} isDisabled={isPaused} isChecked={isRefreshOn} size="lg" diff --git a/airflow/www/static/js/grid/ResetRoot.jsx b/airflow/www/static/js/grid/ResetRoot.tsx similarity index 100% rename from airflow/www/static/js/grid/ResetRoot.jsx rename to airflow/www/static/js/grid/ResetRoot.tsx diff --git a/airflow/www/static/js/grid/ToggleGroups.jsx b/airflow/www/static/js/grid/ToggleGroups.tsx similarity index 81% rename from airflow/www/static/js/grid/ToggleGroups.jsx rename to airflow/www/static/js/grid/ToggleGroups.tsx index 2f027cd668776..9936042a863c0 100644 --- a/airflow/www/static/js/grid/ToggleGroups.jsx +++ b/airflow/www/static/js/grid/ToggleGroups.tsx @@ -20,12 +20,13 @@ import React from 'react'; import { Flex, IconButton } from '@chakra-ui/react'; import { MdExpand, MdCompress } from 'react-icons/md'; +import type { Task } from './types'; -const getGroupIds = (groups) => { - const groupIds = []; - const checkTasks = (tasks) => tasks.forEach((task) => { +const getGroupIds = (groups: Task[]) => { + const groupIds: string[] = []; + const checkTasks = (tasks: Task[]) => tasks.forEach((task) => { if (task.children) { - groupIds.push(task.label); + groupIds.push(task.label!); checkTasks(task.children); } }); @@ -33,12 +34,18 @@ const getGroupIds = (groups) => { return groupIds; }; -const ToggleGroups = ({ groups, openGroupIds, onToggleGroups }) => { +interface Props { + groups: Task; + openGroupIds: string[]; + onToggleGroups: (groupIds: string[]) => void; +} + +const ToggleGroups = ({ groups, openGroupIds, onToggleGroups }: Props) => { // Don't show button if the DAG has no task groups const hasGroups = groups.children && groups.children.find((c) => !!c.children); if (!hasGroups) return null; - const allGroupIds = getGroupIds(groups.children); + const allGroupIds = getGroupIds(groups.children || []); const isExpandDisabled = allGroupIds.length === openGroupIds.length; const isCollapseDisabled = !openGroupIds.length; diff --git a/airflow/www/static/js/grid/context/autorefresh.jsx b/airflow/www/static/js/grid/context/autorefresh.tsx similarity index 87% rename from airflow/www/static/js/grid/context/autorefresh.jsx rename to airflow/www/static/js/grid/context/autorefresh.tsx index 11c987fe34493..6ac37f854b6a8 100644 --- a/airflow/www/static/js/grid/context/autorefresh.jsx +++ b/airflow/www/static/js/grid/context/autorefresh.tsx @@ -27,7 +27,7 @@ import { getMetaValue } from '../../utils'; const autoRefreshKey = 'disabledAutoRefresh'; const initialIsPaused = getMetaValue('is_paused') === 'True'; -const isRefreshDisabled = JSON.parse(localStorage.getItem(autoRefreshKey)); +const isRefreshDisabled = JSON.parse(localStorage.getItem(autoRefreshKey) || 'false'); const AutoRefreshContext = React.createContext({ isRefreshOn: false, @@ -37,7 +37,11 @@ const AutoRefreshContext = React.createContext({ startRefresh: () => {}, }); -export const AutoRefreshProvider = ({ children }) => { +interface Props { + children: React.ReactNode; +} + +export const AutoRefreshProvider = ({ children }: Props) => { const [isPaused, setIsPaused] = useState(initialIsPaused); const isRefreshAllowed = !(isPaused || isRefreshDisabled); const initialState = isRefreshAllowed; @@ -72,10 +76,16 @@ export const AutoRefreshProvider = ({ children }) => { ); useEffect(() => { - const handleChange = (e) => { - setIsPaused(!e.detail); - if (!e.detail) { - stopRefresh(); + function isCustomEvent(event: Event): event is CustomEvent { + return 'detail' in event; + } + + const handleChange = (e: Event) => { + if (isCustomEvent(e)) { + setIsPaused(!e.detail); + if (!e.detail) { + stopRefresh(); + } } }; diff --git a/airflow/www/static/js/grid/dagRuns/Tooltip.jsx b/airflow/www/static/js/grid/dagRuns/Tooltip.tsx similarity index 93% rename from airflow/www/static/js/grid/dagRuns/Tooltip.jsx rename to airflow/www/static/js/grid/dagRuns/Tooltip.tsx index 5f04f36d30bfb..bf388094c0dee 100644 --- a/airflow/www/static/js/grid/dagRuns/Tooltip.jsx +++ b/airflow/www/static/js/grid/dagRuns/Tooltip.tsx @@ -22,12 +22,17 @@ import { Box, Text } from '@chakra-ui/react'; import { formatDuration } from '../../datetime_utils'; import Time from '../components/Time'; +import type { RunWithDuration } from './index'; + +interface Props { + dagRun: RunWithDuration; +} const DagRunTooltip = ({ dagRun: { state, duration, dataIntervalStart, executionDate, runType, }, -}) => ( +}: Props) => ( Status: diff --git a/airflow/www/static/js/grid/details/content/ConfirmDialog.jsx b/airflow/www/static/js/grid/details/content/ConfirmDialog.tsx similarity index 90% rename from airflow/www/static/js/grid/details/content/ConfirmDialog.jsx rename to airflow/www/static/js/grid/details/content/ConfirmDialog.tsx index 823fddc4eb53c..9bdd7586a17c8 100644 --- a/airflow/www/static/js/grid/details/content/ConfirmDialog.jsx +++ b/airflow/www/static/js/grid/details/content/ConfirmDialog.tsx @@ -32,10 +32,20 @@ import { import { useContainerRef } from '../../context/containerRef'; +interface Props { + isOpen: boolean; + onClose: () => void; + title?: string; + description: string; + body?: string[]; + onConfirm: () => void; + isLoading?: boolean; +} + const ConfirmDialog = ({ isOpen, onClose, title = 'Wait a minute', description, body = [], onConfirm, isLoading = false, -}) => { - const initialFocusRef = useRef(); +}: Props) => { + const initialFocusRef = useRef(null); const containerRef = useContainerRef(); return ( { +interface Props { + runId: DagRunType['runId']; +} + +const DagRun = ({ runId }: Props) => { const { data: { dagRuns } } = useGridData(); const run = dagRuns.find((dr) => dr.runId === runId); if (!run) return null; diff --git a/airflow/www/static/js/grid/details/content/taskInstance/Details.jsx b/airflow/www/static/js/grid/details/content/taskInstance/Details.tsx similarity index 87% rename from airflow/www/static/js/grid/details/content/taskInstance/Details.jsx rename to airflow/www/static/js/grid/details/content/taskInstance/Details.tsx index e82d2b63a1fbb..bb3a86ddcd0aa 100644 --- a/airflow/www/static/js/grid/details/content/taskInstance/Details.jsx +++ b/airflow/www/static/js/grid/details/content/taskInstance/Details.tsx @@ -29,10 +29,17 @@ import { getDuration, formatDuration } from '../../../../datetime_utils'; import { SimpleStatus } from '../../../components/StatusBox'; import Time from '../../../components/Time'; import { ClipboardText } from '../../../components/Clipboard'; +import type { Task, TaskInstance, TaskState } from '../../../types'; -const Details = ({ instance, group, operator }) => { +interface Props { + instance: TaskInstance; + group: Task; + operator: string; +} + +const Details = ({ instance, group, operator }: Props) => { const isGroup = !!group.children; - const summary = []; + const summary: React.ReactNode[] = []; const { taskId, @@ -45,18 +52,17 @@ const Details = ({ instance, group, operator }) => { const { isMapped, - children, tooltip, } = group; const numMap = finalStatesMap(); let numMapped = 0; if (isGroup) { - children.forEach((child) => { + group.children?.forEach((child) => { const taskInstance = child.instances.find((ti) => ti.runId === runId); if (taskInstance) { const stateKey = taskInstance.state == null ? 'no_status' : taskInstance.state; - if (numMap.has(stateKey)) numMap.set(stateKey, numMap.get(stateKey) + 1); + if (numMap.has(stateKey)) numMap.set(stateKey, (numMap.get(stateKey) || 0) + 1); } }); } else if (isMapped && mappedStates) { @@ -72,7 +78,7 @@ const Details = ({ instance, group, operator }) => { summary.push( // eslint-disable-next-line react/no-array-index-key - + {val} {': '} {key} @@ -82,7 +88,7 @@ const Details = ({ instance, group, operator }) => { }); const taskIdTitle = isGroup ? 'Task Group Id: ' : 'Task Id: '; - const isStateFinal = ['success', 'failed', 'upstream_failed', 'skipped'].includes(state); + const isStateFinal = state && ['success', 'failed', 'upstream_failed', 'skipped'].includes(state); const isOverall = (isMapped || isGroup) && 'Overall '; return ( diff --git a/airflow/www/static/js/grid/details/content/taskInstance/ExtraLinks.jsx b/airflow/www/static/js/grid/details/content/taskInstance/ExtraLinks.tsx similarity index 87% rename from airflow/www/static/js/grid/details/content/taskInstance/ExtraLinks.jsx rename to airflow/www/static/js/grid/details/content/taskInstance/ExtraLinks.tsx index b9b60b4c017fd..d9d1269ee3109 100644 --- a/airflow/www/static/js/grid/details/content/taskInstance/ExtraLinks.jsx +++ b/airflow/www/static/js/grid/details/content/taskInstance/ExtraLinks.tsx @@ -26,19 +26,27 @@ import { } from '@chakra-ui/react'; import { useExtraLinks } from '../../../api'; +import type { Task } from '../../../types'; + +interface Props { + dagId: string; + taskId: Task['id']; + executionDate: string; + extraLinks: string[]; +} const ExtraLinks = ({ dagId, taskId, executionDate, extraLinks = [], -}) => { +}: Props) => { const { data: links = [] } = useExtraLinks({ dagId, taskId, executionDate, extraLinks, }); if (!links.length) return null; - const isExternal = (url) => /^(?:[a-z]+:)?\/\//.test(url); + const isExternal = (url: string) => /^(?:[a-z]+:)?\/\//.test(url); return ( <> diff --git a/airflow/www/static/js/grid/details/content/taskInstance/Nav.jsx b/airflow/www/static/js/grid/details/content/taskInstance/Nav.tsx similarity index 86% rename from airflow/www/static/js/grid/details/content/taskInstance/Nav.jsx rename to airflow/www/static/js/grid/details/content/taskInstance/Nav.tsx index 14e95c7ee7405..64973f762706e 100644 --- a/airflow/www/static/js/grid/details/content/taskInstance/Nav.jsx +++ b/airflow/www/static/js/grid/details/content/taskInstance/Nav.tsx @@ -25,8 +25,9 @@ import { import { getMetaValue, appendSearchParams } from '../../../../utils'; import LinkButton from '../../../components/LinkButton'; +import type { Task, DagRun } from '../../../types'; -const dagId = getMetaValue('dag_id'); +const dagId = getMetaValue('dag_id') || ''; const isK8sExecutor = getMetaValue('k8s_or_k8scelery_executor') === 'True'; const numRuns = getMetaValue('num_runs'); const baseDate = getMetaValue('base_date'); @@ -36,12 +37,21 @@ const renderedTemplatesUrl = getMetaValue('rendered_templates_url'); const xcomUrl = getMetaValue('xcom_url'); const logUrl = getMetaValue('log_url'); const taskUrl = getMetaValue('task_url'); -const gridUrl = getMetaValue('grid_url'); +const gridUrl = getMetaValue('grid_url') || ''; const gridUrlNoRoot = getMetaValue('grid_url_no_root'); +interface Props { + runId: DagRun['runId']; + taskId: Task['id']; + executionDate: string; + operator: string; + isMapped?: boolean; +} + const Nav = ({ - runId, taskId, executionDate, operator, isMapped, -}) => { + runId, taskId, executionDate, operator, isMapped = false, +}: Props) => { + if (!taskId) return null; const params = new URLSearchParams({ task_id: taskId, execution_date: executionDate, @@ -63,14 +73,15 @@ const Nav = ({ const filterParams = new URLSearchParams({ task_id: taskId, dag_run_id: runId, - base_date: baseDate, - num_runs: numRuns, root: taskId, - }).toString(); + }); + + if (baseDate) filterParams.append('base_date', baseDate); + if (numRuns) filterParams.append('num_runs', numRuns); const allInstancesLink = `${taskInstancesUrl}?${listParams.toString()}`; - const filterUpstreamLink = appendSearchParams(gridUrlNoRoot, filterParams); + const filterUpstreamLink = appendSearchParams(gridUrlNoRoot, filterParams.toString()); const subDagLink = appendSearchParams(gridUrl.replace(dagId, `${dagId}.${taskId}`), subDagParams); // TODO: base subdag zooming as its own attribute instead of via operator name diff --git a/airflow/www/static/js/grid/details/content/taskInstance/index.tsx b/airflow/www/static/js/grid/details/content/taskInstance/index.tsx index bbb262eedae6e..8f556dc97255a 100644 --- a/airflow/www/static/js/grid/details/content/taskInstance/index.tsx +++ b/airflow/www/static/js/grid/details/content/taskInstance/index.tsx @@ -116,6 +116,7 @@ const TaskInstance = ({ taskId, runId }: Props) => { const operator = (task?.classRef && task?.classRef?.className) ?? ''; const instance = group.instances.find((ti) => ti.runId === runId); + if (!instance) return null; let taskActionsTitle = 'Task Actions'; if (isMapped) { @@ -185,7 +186,7 @@ const TaskInstance = ({ taskId, runId }: Props) => {
From 4b4f6fbe85103d439d14c065b36ab1b74d657762 Mon Sep 17 00:00:00 2001 From: Brent Bovenzi Date: Tue, 28 Jun 2022 17:48:21 -0400 Subject: [PATCH 2/3] upgrade more component files --- .../{Clipboard.test.jsx => Clipboard.test.tsx} | 0 .../grid/components/{Clipboard.jsx => Clipboard.tsx} | 6 +++++- .../{LinkButton.test.jsx => LinkButton.test.tsx} | 0 .../components/{LinkButton.jsx => LinkButton.tsx} | 3 ++- .../{TaskName.test.jsx => TaskName.test.tsx} | 6 +++--- .../js/grid/components/{TaskName.jsx => TaskName.tsx} | 11 ++++++++++- 6 files changed, 20 insertions(+), 6 deletions(-) rename airflow/www/static/js/grid/components/{Clipboard.test.jsx => Clipboard.test.tsx} (100%) rename airflow/www/static/js/grid/components/{Clipboard.jsx => Clipboard.tsx} (95%) rename airflow/www/static/js/grid/components/{LinkButton.test.jsx => LinkButton.test.tsx} (100%) rename airflow/www/static/js/grid/components/{LinkButton.jsx => LinkButton.tsx} (85%) rename airflow/www/static/js/grid/components/{TaskName.test.jsx => TaskName.test.tsx} (86%) rename airflow/www/static/js/grid/components/{TaskName.jsx => TaskName.tsx} (91%) diff --git a/airflow/www/static/js/grid/components/Clipboard.test.jsx b/airflow/www/static/js/grid/components/Clipboard.test.tsx similarity index 100% rename from airflow/www/static/js/grid/components/Clipboard.test.jsx rename to airflow/www/static/js/grid/components/Clipboard.test.tsx diff --git a/airflow/www/static/js/grid/components/Clipboard.jsx b/airflow/www/static/js/grid/components/Clipboard.tsx similarity index 95% rename from airflow/www/static/js/grid/components/Clipboard.jsx rename to airflow/www/static/js/grid/components/Clipboard.tsx index a4e0acca2884c..bb9b1d0d5522a 100644 --- a/airflow/www/static/js/grid/components/Clipboard.jsx +++ b/airflow/www/static/js/grid/components/Clipboard.tsx @@ -75,7 +75,11 @@ export const ClipboardButton = forwardRef( }, ); -export const ClipboardText = ({ value }) => ( +interface Props { + value: string +} + +export const ClipboardText = ({ value }: Props) => ( <> {value} diff --git a/airflow/www/static/js/grid/components/LinkButton.test.jsx b/airflow/www/static/js/grid/components/LinkButton.test.tsx similarity index 100% rename from airflow/www/static/js/grid/components/LinkButton.test.jsx rename to airflow/www/static/js/grid/components/LinkButton.test.tsx diff --git a/airflow/www/static/js/grid/components/LinkButton.jsx b/airflow/www/static/js/grid/components/LinkButton.tsx similarity index 85% rename from airflow/www/static/js/grid/components/LinkButton.jsx rename to airflow/www/static/js/grid/components/LinkButton.tsx index 00cff8d188442..ea9f71f9517f2 100644 --- a/airflow/www/static/js/grid/components/LinkButton.jsx +++ b/airflow/www/static/js/grid/components/LinkButton.tsx @@ -20,9 +20,10 @@ import React from 'react'; import { Button, + ButtonProps, Link, } from '@chakra-ui/react'; -const LinkButton = ({ children, ...rest }) => (); +const LinkButton = ({ children, ...rest }: ButtonProps) => (); export default LinkButton; diff --git a/airflow/www/static/js/grid/components/TaskName.test.jsx b/airflow/www/static/js/grid/components/TaskName.test.tsx similarity index 86% rename from airflow/www/static/js/grid/components/TaskName.test.jsx rename to airflow/www/static/js/grid/components/TaskName.test.tsx index a9760da303592..f2f8e0fd6a8de 100644 --- a/airflow/www/static/js/grid/components/TaskName.test.jsx +++ b/airflow/www/static/js/grid/components/TaskName.test.tsx @@ -27,19 +27,19 @@ import { ChakraWrapper } from '../utils/testUtils'; describe('Test TaskName', () => { test('Displays a normal task name', () => { - const { getByText } = render(, { wrapper: ChakraWrapper }); + const { getByText } = render( {}} />, { wrapper: ChakraWrapper }); expect(getByText('test')).toBeDefined(); }); test('Displays a mapped task name', () => { - const { getByText } = render(, { wrapper: ChakraWrapper }); + const { getByText } = render( {}} />, { wrapper: ChakraWrapper }); expect(getByText('test [ ]')).toBeDefined(); }); test('Displays a group task name', () => { - const { getByText, getByTestId } = render(, { wrapper: ChakraWrapper }); + const { getByText, getByTestId } = render( {}} />, { wrapper: ChakraWrapper }); expect(getByText('test')).toBeDefined(); expect(getByTestId('closed-group')).toBeDefined(); diff --git a/airflow/www/static/js/grid/components/TaskName.jsx b/airflow/www/static/js/grid/components/TaskName.tsx similarity index 91% rename from airflow/www/static/js/grid/components/TaskName.jsx rename to airflow/www/static/js/grid/components/TaskName.tsx index b46c6f03808a2..d7c074bfa1625 100644 --- a/airflow/www/static/js/grid/components/TaskName.jsx +++ b/airflow/www/static/js/grid/components/TaskName.tsx @@ -24,9 +24,18 @@ import { } from '@chakra-ui/react'; import { FiChevronUp, FiChevronDown } from 'react-icons/fi'; +interface Props { + isGroup?: boolean; + isMapped?: boolean; + onToggle: () => void; + isOpen?: boolean; + level?: number; + label: string; +} + const TaskName = ({ isGroup = false, isMapped = false, onToggle, isOpen = false, level = 0, label, -}) => ( +}: Props) => ( Date: Tue, 28 Jun 2022 17:54:05 -0400 Subject: [PATCH 3/3] fix linting issues --- airflow/www/static/js/grid/components/LinkButton.tsx | 6 +++++- airflow/www/static/js/grid/renderTaskRows.tsx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/airflow/www/static/js/grid/components/LinkButton.tsx b/airflow/www/static/js/grid/components/LinkButton.tsx index ea9f71f9517f2..1473713de7f57 100644 --- a/airflow/www/static/js/grid/components/LinkButton.tsx +++ b/airflow/www/static/js/grid/components/LinkButton.tsx @@ -24,6 +24,10 @@ import { Link, } from '@chakra-ui/react'; -const LinkButton = ({ children, ...rest }: ButtonProps) => (); +interface Props extends ButtonProps { + href?: string; +} + +const LinkButton = ({ children, ...rest }: Props) => (); export default LinkButton; diff --git a/airflow/www/static/js/grid/renderTaskRows.tsx b/airflow/www/static/js/grid/renderTaskRows.tsx index f35d1a2c9e17e..42ee268d3f3ea 100644 --- a/airflow/www/static/js/grid/renderTaskRows.tsx +++ b/airflow/www/static/js/grid/renderTaskRows.tsx @@ -168,7 +168,7 @@ const Row = (props: RowProps) => { onToggle={memoizedToggle} isGroup={isGroup} isMapped={task.isMapped} - label={task.label} + label={task.label || task.id || ''} isOpen={isOpen} level={level} />