You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by bb...@apache.org on 2022/08/02 16:07:12 UTC

[airflow] branch main updated: Show upstream/downstreams from a dataset (#25403)

This is an automated email from the ASF dual-hosted git repository.

bbovenzi 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 b7f2206621 Show upstream/downstreams from a dataset (#25403)
b7f2206621 is described below

commit b7f2206621365bd957c61567be49fe8447c71d3a
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Tue Aug 2 17:07:02 2022 +0100

    Show upstream/downstreams from a dataset (#25403)
    
    * add links to upstream/downstream dags, fix typing
    
    * tooltip descriptions
    
    * Update airflow/www/static/js/datasets/Details.tsx
    
    Co-authored-by: Daniel Standish <15...@users.noreply.github.com>
    
    * remove created/updated at, separate links
    
    * update copy
    
    Co-authored-by: Daniel Standish <15...@users.noreply.github.com>
---
 airflow/www/alias-rest-types.js                  |   4 +-
 airflow/www/package.json                         |   1 +
 airflow/www/static/js/components/InfoTooltip.tsx |  48 +++++++
 airflow/www/static/js/components/Table/index.tsx |   4 +-
 airflow/www/static/js/datasets/Details.tsx       |  96 ++++++++++----
 airflow/www/static/js/datasets/List.tsx          |  30 ++++-
 airflow/www/static/js/types/api-generated.ts     | 160 +++++++++++------------
 airflow/www/static/js/types/index.ts             |  11 --
 airflow/www/yarn.lock                            |   5 +
 9 files changed, 229 insertions(+), 130 deletions(-)

diff --git a/airflow/www/alias-rest-types.js b/airflow/www/alias-rest-types.js
index 97ed7b4cca..bc89630b16 100644
--- a/airflow/www/alias-rest-types.js
+++ b/airflow/www/alias-rest-types.js
@@ -81,7 +81,7 @@ const generateAliases = (rootNode, writeText, prefix = '') => {
 
       const types = schemaMemberNames.map((n) => [
         `${n}`,
-        `export type ${n} = SnakeToCamelCaseNested<${prefixPath(prefix, 'components')}['schemas']['${n}']>;`,
+        `export type ${n} = CamelCasedPropertiesDeep<${prefixPath(prefix, 'components')}['schemas']['${n}']>;`,
       ]);
       if (types.length) {
         writeText.push(['comment', `Types for returned data ${prefix}`]);
@@ -172,7 +172,7 @@ function generate(file) {
   writeText.push(['block', license]);
   writeText.push(['comment', 'eslint-disable']);
   // eslint-disable-next-line quotes
-  writeText.push(['block', `import type { SnakeToCamelCaseNested } from '.';`]);
+  writeText.push(['block', `import type { CamelCasedPropertiesDeep } from 'type-fest';`]);
   writeText.push(['block', sourceFile.text]);
   generateAliases(sourceFile, writeText);
 
diff --git a/airflow/www/package.json b/airflow/www/package.json
index a85bf0ca7d..f9091602f0 100644
--- a/airflow/www/package.json
+++ b/airflow/www/package.json
@@ -108,6 +108,7 @@
     "react-router-dom": "^6.3.0",
     "react-table": "^7.8.0",
     "redoc": "^2.0.0-rc.72",
+    "type-fest": "^2.17.0",
     "url-search-params-polyfill": "^8.1.0"
   }
 }
diff --git a/airflow/www/static/js/components/InfoTooltip.tsx b/airflow/www/static/js/components/InfoTooltip.tsx
new file mode 100644
index 0000000000..0cf593d466
--- /dev/null
+++ b/airflow/www/static/js/components/InfoTooltip.tsx
@@ -0,0 +1,48 @@
+/*!
+ * 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.
+ */
+
+import React, { ReactNode } from 'react';
+import {
+  Box, Tooltip,
+} from '@chakra-ui/react';
+import { MdInfo } from 'react-icons/md';
+import { useContainerRef } from 'src/context/containerRef';
+import type { IconBaseProps } from 'react-icons';
+
+interface InfoTooltipProps extends IconBaseProps {
+  label: ReactNode;
+}
+
+const InfoTooltip = ({ label, ...rest }: InfoTooltipProps) => {
+  const containerRef = useContainerRef();
+  return (
+    <Tooltip
+      label={label}
+      hasArrow
+      placement="top"
+      portalProps={{ containerRef }}
+    >
+      <Box display="inline" ml={1} color="gray.500">
+        <MdInfo {...rest} />
+      </Box>
+    </Tooltip>
+  );
+};
+
+export default InfoTooltip;
diff --git a/airflow/www/static/js/components/Table/index.tsx b/airflow/www/static/js/components/Table/index.tsx
index 534cc50f61..11087bdb26 100644
--- a/airflow/www/static/js/components/Table/index.tsx
+++ b/airflow/www/static/js/components/Table/index.tsx
@@ -198,7 +198,7 @@ export const Table = ({
               <Th
                 {...column.getHeaderProps(column.getSortByToggleProps())}
               >
-                <>
+                <Flex>
                   {column.render('Header')}
                   {column.isSorted && (
                     column.isSortedDesc ? (
@@ -208,7 +208,7 @@ export const Table = ({
                     )
                   )}
                   {(!column.isSorted && column.canSort) && (<TiArrowUnsorted aria-label="unsorted" style={{ display: 'inline' }} size="1em" />)}
-                </>
+                </Flex>
               </Th>
             ))}
           </Tr>
diff --git a/airflow/www/static/js/datasets/Details.tsx b/airflow/www/static/js/datasets/Details.tsx
index 7cc16c101c..753f1dc333 100644
--- a/airflow/www/static/js/datasets/Details.tsx
+++ b/airflow/www/static/js/datasets/Details.tsx
@@ -19,23 +19,84 @@
 
 import React, { useMemo, useState } from 'react';
 import {
-  Box, Heading, Text, Code, Flex, Spinner, Button,
+  Box, Heading, Text, Code, Flex, Spinner, Button, Link,
 } from '@chakra-ui/react';
 import { snakeCase } from 'lodash';
 import type { SortingRule } from 'react-table';
 
-import Time from 'src/components/Time';
 import { useDatasetEvents, useDataset } from 'src/api';
 import {
   Table, TimeCell, CodeCell, TaskInstanceLink,
 } from 'src/components/Table';
 import { ClipboardButton } from 'src/components/Clipboard';
+import type { API } from 'src/types';
+import InfoTooltip from 'src/components/InfoTooltip';
 
 interface Props {
   datasetId: string;
   onBack: () => void;
 }
 
+const Details = ({
+  dataset: {
+    uri,
+    extra,
+    upstreamTaskReferences,
+    downstreamDagReferences,
+  },
+}: { dataset: API.Dataset }) => (
+  <Box>
+    <Heading my={2} fontWeight="normal">
+      Dataset:
+      {' '}
+      {uri}
+      <ClipboardButton value={uri} iconOnly ml={2} />
+    </Heading>
+    {!!extra && (
+      <Flex>
+        <Text mr={1}>Extra:</Text>
+        <Code>{JSON.stringify(extra)}</Code>
+      </Flex>
+    )}
+    {upstreamTaskReferences && !!upstreamTaskReferences.length && (
+    <Box mb={2}>
+      <Flex alignItems="center">
+        <Heading size="md" fontWeight="normal">Producing Tasks</Heading>
+        <InfoTooltip label="Tasks that will update this dataset." size={14} />
+      </Flex>
+      {upstreamTaskReferences.map(({ dagId, taskId }) => (
+        <Link
+          key={`${dagId}.${taskId}`}
+          color="blue.600"
+          href={`/dags/${dagId}/grid`}
+          display="block"
+        >
+          {`${dagId}.${taskId}`}
+        </Link>
+      ))}
+    </Box>
+    )}
+    {downstreamDagReferences && !!downstreamDagReferences.length && (
+    <Box>
+      <Flex alignItems="center">
+        <Heading size="md" fontWeight="normal">Consuming DAGs</Heading>
+        <InfoTooltip label="DAGs that depend on this dataset updating to trigger a run." size={14} />
+      </Flex>
+      {downstreamDagReferences.map(({ dagId }) => (
+        <Link
+          key={dagId}
+          color="blue.600"
+          href={`/dags/${dagId}/grid`}
+          display="block"
+        >
+          {dagId}
+        </Link>
+      ))}
+    </Box>
+    )}
+  </Box>
+);
+
 const DatasetDetails = ({ datasetId, onBack }: Props) => {
   const limit = 25;
   const [offset, setOffset] = useState(0);
@@ -85,32 +146,11 @@ const DatasetDetails = ({ datasetId, onBack }: Props) => {
     <Box mt={[6, 3]} maxWidth="1500px">
       <Button onClick={onBack}>See all datasets</Button>
       {isLoading && <Spinner display="block" />}
-      {!!dataset && (
-        <Box>
-          <Heading my={2} fontWeight="normal">
-            Dataset:
-            {' '}
-            {dataset.uri}
-            <ClipboardButton value={dataset.uri} iconOnly ml={2} />
-          </Heading>
-          {!!dataset.extra && (
-            <Flex>
-              <Text mr={1}>Extra:</Text>
-              <Code>{JSON.stringify(dataset.extra)}</Code>
-            </Flex>
-          )}
-          <Flex my={2}>
-            <Text mr={1}>Updated At:</Text>
-            <Time dateTime={dataset.updatedAt} />
-          </Flex>
-          <Flex my={2}>
-            <Text mr={1}>Created At:</Text>
-            <Time dateTime={dataset.createdAt} />
-          </Flex>
-        </Box>
-      )}
-      <Heading size="lg" mt={3} mb={2} fontWeight="normal">Upstream Events</Heading>
-      <Text>Whenever a DAG has updated this dataset.</Text>
+      {!!dataset && (<Details dataset={dataset} />)}
+      <Flex alignItems="center">
+        <Heading size="lg" mt={3} mb={2} fontWeight="normal">Events</Heading>
+        <InfoTooltip label="Whenever a DAG has updated this dataset." size={18} />
+      </Flex>
       <Table
         data={data}
         columns={columns}
diff --git a/airflow/www/static/js/datasets/List.tsx b/airflow/www/static/js/datasets/List.tsx
index a4c08fc2c7..674834c36b 100644
--- a/airflow/www/static/js/datasets/List.tsx
+++ b/airflow/www/static/js/datasets/List.tsx
@@ -24,19 +24,35 @@ import {
   Flex,
   Button,
   Link,
+  Text,
 } from '@chakra-ui/react';
 import { snakeCase } from 'lodash';
 import type { Row, SortingRule } from 'react-table';
 
 import { useDatasets } from 'src/api';
-import { Table, TimeCell, CodeCell } from 'src/components/Table';
+import { Table, CodeCell } from 'src/components/Table';
 import type { API } from 'src/types';
 import { MdOutlineAccountTree } from 'react-icons/md';
+import InfoTooltip from 'src/components/InfoTooltip';
 
 interface Props {
   onSelect: (datasetId: string) => void;
 }
 
+const UpstreamHeader = () => (
+  <Flex>
+    <Text>Producing Tasks</Text>
+    <InfoTooltip size={12} label="Number of tasks that will update this dataset." />
+  </Flex>
+);
+
+const DownstreamHeader = () => (
+  <Flex>
+    <Text>Consuming DAGs</Text>
+    <InfoTooltip size={12} label="Number of DAGs that will run based on updates to this dataset." />
+  </Flex>
+);
+
 const DatasetsList = ({ onSelect }: Props) => {
   const limit = 25;
   const [offset, setOffset] = useState(0);
@@ -60,14 +76,14 @@ const DatasetsList = ({ onSelect }: Props) => {
         Cell: CodeCell,
       },
       {
-        Header: 'Created At',
-        accessor: 'createdAt',
-        Cell: TimeCell,
+        Header: UpstreamHeader,
+        accessor: 'upstreamTaskReferences',
+        Cell: ({ cell: { value } }: any) => value.length,
       },
       {
-        Header: 'Updated At',
-        accessor: 'updatedAt',
-        Cell: TimeCell,
+        Header: DownstreamHeader,
+        accessor: 'downstreamDagReferences',
+        Cell: ({ cell: { value } }: any) => value.length,
       },
     ],
     [],
diff --git a/airflow/www/static/js/types/api-generated.ts b/airflow/www/static/js/types/api-generated.ts
index b0d7110d64..509cf41c3f 100644
--- a/airflow/www/static/js/types/api-generated.ts
+++ b/airflow/www/static/js/types/api-generated.ts
@@ -18,7 +18,7 @@
 */
 
 /* eslint-disable */
-import type { SnakeToCamelCaseNested } from '.';
+import type { CamelCasedPropertiesDeep } from 'type-fest';
 /**
  * This file was auto-generated by openapi-typescript.
  * Do not make direct changes to the file.
@@ -4027,85 +4027,85 @@ export interface external {}
 export type Paths = paths;
 
 /* Types for returned data  */
-export type UserCollectionItem = SnakeToCamelCaseNested<components['schemas']['UserCollectionItem']>;
-export type User = SnakeToCamelCaseNested<components['schemas']['User']>;
-export type UserCollection = SnakeToCamelCaseNested<components['schemas']['UserCollection']>;
-export type ConnectionCollectionItem = SnakeToCamelCaseNested<components['schemas']['ConnectionCollectionItem']>;
-export type ConnectionCollection = SnakeToCamelCaseNested<components['schemas']['ConnectionCollection']>;
-export type Connection = SnakeToCamelCaseNested<components['schemas']['Connection']>;
-export type ConnectionTest = SnakeToCamelCaseNested<components['schemas']['ConnectionTest']>;
-export type DAG = SnakeToCamelCaseNested<components['schemas']['DAG']>;
-export type DAGCollection = SnakeToCamelCaseNested<components['schemas']['DAGCollection']>;
-export type DAGRun = SnakeToCamelCaseNested<components['schemas']['DAGRun']>;
-export type UpdateDagRunState = SnakeToCamelCaseNested<components['schemas']['UpdateDagRunState']>;
-export type DAGRunCollection = SnakeToCamelCaseNested<components['schemas']['DAGRunCollection']>;
-export type DagWarning = SnakeToCamelCaseNested<components['schemas']['DagWarning']>;
-export type DagWarningCollection = SnakeToCamelCaseNested<components['schemas']['DagWarningCollection']>;
-export type EventLog = SnakeToCamelCaseNested<components['schemas']['EventLog']>;
-export type EventLogCollection = SnakeToCamelCaseNested<components['schemas']['EventLogCollection']>;
-export type ImportError = SnakeToCamelCaseNested<components['schemas']['ImportError']>;
-export type ImportErrorCollection = SnakeToCamelCaseNested<components['schemas']['ImportErrorCollection']>;
-export type HealthInfo = SnakeToCamelCaseNested<components['schemas']['HealthInfo']>;
-export type MetadatabaseStatus = SnakeToCamelCaseNested<components['schemas']['MetadatabaseStatus']>;
-export type SchedulerStatus = SnakeToCamelCaseNested<components['schemas']['SchedulerStatus']>;
-export type Pool = SnakeToCamelCaseNested<components['schemas']['Pool']>;
-export type PoolCollection = SnakeToCamelCaseNested<components['schemas']['PoolCollection']>;
-export type Provider = SnakeToCamelCaseNested<components['schemas']['Provider']>;
-export type ProviderCollection = SnakeToCamelCaseNested<components['schemas']['ProviderCollection']>;
-export type SLAMiss = SnakeToCamelCaseNested<components['schemas']['SLAMiss']>;
-export type TaskInstance = SnakeToCamelCaseNested<components['schemas']['TaskInstance']>;
-export type TaskInstanceCollection = SnakeToCamelCaseNested<components['schemas']['TaskInstanceCollection']>;
-export type TaskInstanceReference = SnakeToCamelCaseNested<components['schemas']['TaskInstanceReference']>;
-export type TaskInstanceReferenceCollection = SnakeToCamelCaseNested<components['schemas']['TaskInstanceReferenceCollection']>;
-export type VariableCollectionItem = SnakeToCamelCaseNested<components['schemas']['VariableCollectionItem']>;
-export type VariableCollection = SnakeToCamelCaseNested<components['schemas']['VariableCollection']>;
-export type Variable = SnakeToCamelCaseNested<components['schemas']['Variable']>;
-export type XComCollectionItem = SnakeToCamelCaseNested<components['schemas']['XComCollectionItem']>;
-export type XComCollection = SnakeToCamelCaseNested<components['schemas']['XComCollection']>;
-export type XCom = SnakeToCamelCaseNested<components['schemas']['XCom']>;
-export type DAGDetail = SnakeToCamelCaseNested<components['schemas']['DAGDetail']>;
-export type ExtraLink = SnakeToCamelCaseNested<components['schemas']['ExtraLink']>;
-export type ExtraLinkCollection = SnakeToCamelCaseNested<components['schemas']['ExtraLinkCollection']>;
-export type Task = SnakeToCamelCaseNested<components['schemas']['Task']>;
-export type TaskCollection = SnakeToCamelCaseNested<components['schemas']['TaskCollection']>;
-export type PluginCollectionItem = SnakeToCamelCaseNested<components['schemas']['PluginCollectionItem']>;
-export type PluginCollection = SnakeToCamelCaseNested<components['schemas']['PluginCollection']>;
-export type Role = SnakeToCamelCaseNested<components['schemas']['Role']>;
-export type RoleCollection = SnakeToCamelCaseNested<components['schemas']['RoleCollection']>;
-export type Action = SnakeToCamelCaseNested<components['schemas']['Action']>;
-export type ActionCollection = SnakeToCamelCaseNested<components['schemas']['ActionCollection']>;
-export type Resource = SnakeToCamelCaseNested<components['schemas']['Resource']>;
-export type ActionResource = SnakeToCamelCaseNested<components['schemas']['ActionResource']>;
-export type Dataset = SnakeToCamelCaseNested<components['schemas']['Dataset']>;
-export type DatasetTaskRef = SnakeToCamelCaseNested<components['schemas']['DatasetTaskRef']>;
-export type DatasetDagRef = SnakeToCamelCaseNested<components['schemas']['DatasetDagRef']>;
-export type DatasetCollection = SnakeToCamelCaseNested<components['schemas']['DatasetCollection']>;
-export type DatasetEvent = SnakeToCamelCaseNested<components['schemas']['DatasetEvent']>;
-export type DatasetEventCollection = SnakeToCamelCaseNested<components['schemas']['DatasetEventCollection']>;
-export type ConfigOption = SnakeToCamelCaseNested<components['schemas']['ConfigOption']>;
-export type ConfigSection = SnakeToCamelCaseNested<components['schemas']['ConfigSection']>;
-export type Config = SnakeToCamelCaseNested<components['schemas']['Config']>;
-export type VersionInfo = SnakeToCamelCaseNested<components['schemas']['VersionInfo']>;
-export type ClearDagRun = SnakeToCamelCaseNested<components['schemas']['ClearDagRun']>;
-export type ClearTaskInstance = SnakeToCamelCaseNested<components['schemas']['ClearTaskInstance']>;
-export type UpdateTaskInstancesState = SnakeToCamelCaseNested<components['schemas']['UpdateTaskInstancesState']>;
-export type ListDagRunsForm = SnakeToCamelCaseNested<components['schemas']['ListDagRunsForm']>;
-export type ListTaskInstanceForm = SnakeToCamelCaseNested<components['schemas']['ListTaskInstanceForm']>;
-export type ScheduleInterval = SnakeToCamelCaseNested<components['schemas']['ScheduleInterval']>;
-export type TimeDelta = SnakeToCamelCaseNested<components['schemas']['TimeDelta']>;
-export type RelativeDelta = SnakeToCamelCaseNested<components['schemas']['RelativeDelta']>;
-export type CronExpression = SnakeToCamelCaseNested<components['schemas']['CronExpression']>;
-export type Timezone = SnakeToCamelCaseNested<components['schemas']['Timezone']>;
-export type Tag = SnakeToCamelCaseNested<components['schemas']['Tag']>;
-export type Color = SnakeToCamelCaseNested<components['schemas']['Color']>;
-export type ClassReference = SnakeToCamelCaseNested<components['schemas']['ClassReference']>;
-export type Error = SnakeToCamelCaseNested<components['schemas']['Error']>;
-export type CollectionInfo = SnakeToCamelCaseNested<components['schemas']['CollectionInfo']>;
-export type TaskState = SnakeToCamelCaseNested<components['schemas']['TaskState']>;
-export type DagState = SnakeToCamelCaseNested<components['schemas']['DagState']>;
-export type TriggerRule = SnakeToCamelCaseNested<components['schemas']['TriggerRule']>;
-export type WeightRule = SnakeToCamelCaseNested<components['schemas']['WeightRule']>;
-export type HealthStatus = SnakeToCamelCaseNested<components['schemas']['HealthStatus']>;
+export type UserCollectionItem = CamelCasedPropertiesDeep<components['schemas']['UserCollectionItem']>;
+export type User = CamelCasedPropertiesDeep<components['schemas']['User']>;
+export type UserCollection = CamelCasedPropertiesDeep<components['schemas']['UserCollection']>;
+export type ConnectionCollectionItem = CamelCasedPropertiesDeep<components['schemas']['ConnectionCollectionItem']>;
+export type ConnectionCollection = CamelCasedPropertiesDeep<components['schemas']['ConnectionCollection']>;
+export type Connection = CamelCasedPropertiesDeep<components['schemas']['Connection']>;
+export type ConnectionTest = CamelCasedPropertiesDeep<components['schemas']['ConnectionTest']>;
+export type DAG = CamelCasedPropertiesDeep<components['schemas']['DAG']>;
+export type DAGCollection = CamelCasedPropertiesDeep<components['schemas']['DAGCollection']>;
+export type DAGRun = CamelCasedPropertiesDeep<components['schemas']['DAGRun']>;
+export type UpdateDagRunState = CamelCasedPropertiesDeep<components['schemas']['UpdateDagRunState']>;
+export type DAGRunCollection = CamelCasedPropertiesDeep<components['schemas']['DAGRunCollection']>;
+export type DagWarning = CamelCasedPropertiesDeep<components['schemas']['DagWarning']>;
+export type DagWarningCollection = CamelCasedPropertiesDeep<components['schemas']['DagWarningCollection']>;
+export type EventLog = CamelCasedPropertiesDeep<components['schemas']['EventLog']>;
+export type EventLogCollection = CamelCasedPropertiesDeep<components['schemas']['EventLogCollection']>;
+export type ImportError = CamelCasedPropertiesDeep<components['schemas']['ImportError']>;
+export type ImportErrorCollection = CamelCasedPropertiesDeep<components['schemas']['ImportErrorCollection']>;
+export type HealthInfo = CamelCasedPropertiesDeep<components['schemas']['HealthInfo']>;
+export type MetadatabaseStatus = CamelCasedPropertiesDeep<components['schemas']['MetadatabaseStatus']>;
+export type SchedulerStatus = CamelCasedPropertiesDeep<components['schemas']['SchedulerStatus']>;
+export type Pool = CamelCasedPropertiesDeep<components['schemas']['Pool']>;
+export type PoolCollection = CamelCasedPropertiesDeep<components['schemas']['PoolCollection']>;
+export type Provider = CamelCasedPropertiesDeep<components['schemas']['Provider']>;
+export type ProviderCollection = CamelCasedPropertiesDeep<components['schemas']['ProviderCollection']>;
+export type SLAMiss = CamelCasedPropertiesDeep<components['schemas']['SLAMiss']>;
+export type TaskInstance = CamelCasedPropertiesDeep<components['schemas']['TaskInstance']>;
+export type TaskInstanceCollection = CamelCasedPropertiesDeep<components['schemas']['TaskInstanceCollection']>;
+export type TaskInstanceReference = CamelCasedPropertiesDeep<components['schemas']['TaskInstanceReference']>;
+export type TaskInstanceReferenceCollection = CamelCasedPropertiesDeep<components['schemas']['TaskInstanceReferenceCollection']>;
+export type VariableCollectionItem = CamelCasedPropertiesDeep<components['schemas']['VariableCollectionItem']>;
+export type VariableCollection = CamelCasedPropertiesDeep<components['schemas']['VariableCollection']>;
+export type Variable = CamelCasedPropertiesDeep<components['schemas']['Variable']>;
+export type XComCollectionItem = CamelCasedPropertiesDeep<components['schemas']['XComCollectionItem']>;
+export type XComCollection = CamelCasedPropertiesDeep<components['schemas']['XComCollection']>;
+export type XCom = CamelCasedPropertiesDeep<components['schemas']['XCom']>;
+export type DAGDetail = CamelCasedPropertiesDeep<components['schemas']['DAGDetail']>;
+export type ExtraLink = CamelCasedPropertiesDeep<components['schemas']['ExtraLink']>;
+export type ExtraLinkCollection = CamelCasedPropertiesDeep<components['schemas']['ExtraLinkCollection']>;
+export type Task = CamelCasedPropertiesDeep<components['schemas']['Task']>;
+export type TaskCollection = CamelCasedPropertiesDeep<components['schemas']['TaskCollection']>;
+export type PluginCollectionItem = CamelCasedPropertiesDeep<components['schemas']['PluginCollectionItem']>;
+export type PluginCollection = CamelCasedPropertiesDeep<components['schemas']['PluginCollection']>;
+export type Role = CamelCasedPropertiesDeep<components['schemas']['Role']>;
+export type RoleCollection = CamelCasedPropertiesDeep<components['schemas']['RoleCollection']>;
+export type Action = CamelCasedPropertiesDeep<components['schemas']['Action']>;
+export type ActionCollection = CamelCasedPropertiesDeep<components['schemas']['ActionCollection']>;
+export type Resource = CamelCasedPropertiesDeep<components['schemas']['Resource']>;
+export type ActionResource = CamelCasedPropertiesDeep<components['schemas']['ActionResource']>;
+export type Dataset = CamelCasedPropertiesDeep<components['schemas']['Dataset']>;
+export type DatasetTaskRef = CamelCasedPropertiesDeep<components['schemas']['DatasetTaskRef']>;
+export type DatasetDagRef = CamelCasedPropertiesDeep<components['schemas']['DatasetDagRef']>;
+export type DatasetCollection = CamelCasedPropertiesDeep<components['schemas']['DatasetCollection']>;
+export type DatasetEvent = CamelCasedPropertiesDeep<components['schemas']['DatasetEvent']>;
+export type DatasetEventCollection = CamelCasedPropertiesDeep<components['schemas']['DatasetEventCollection']>;
+export type ConfigOption = CamelCasedPropertiesDeep<components['schemas']['ConfigOption']>;
+export type ConfigSection = CamelCasedPropertiesDeep<components['schemas']['ConfigSection']>;
+export type Config = CamelCasedPropertiesDeep<components['schemas']['Config']>;
+export type VersionInfo = CamelCasedPropertiesDeep<components['schemas']['VersionInfo']>;
+export type ClearDagRun = CamelCasedPropertiesDeep<components['schemas']['ClearDagRun']>;
+export type ClearTaskInstance = CamelCasedPropertiesDeep<components['schemas']['ClearTaskInstance']>;
+export type UpdateTaskInstancesState = CamelCasedPropertiesDeep<components['schemas']['UpdateTaskInstancesState']>;
+export type ListDagRunsForm = CamelCasedPropertiesDeep<components['schemas']['ListDagRunsForm']>;
+export type ListTaskInstanceForm = CamelCasedPropertiesDeep<components['schemas']['ListTaskInstanceForm']>;
+export type ScheduleInterval = CamelCasedPropertiesDeep<components['schemas']['ScheduleInterval']>;
+export type TimeDelta = CamelCasedPropertiesDeep<components['schemas']['TimeDelta']>;
+export type RelativeDelta = CamelCasedPropertiesDeep<components['schemas']['RelativeDelta']>;
+export type CronExpression = CamelCasedPropertiesDeep<components['schemas']['CronExpression']>;
+export type Timezone = CamelCasedPropertiesDeep<components['schemas']['Timezone']>;
+export type Tag = CamelCasedPropertiesDeep<components['schemas']['Tag']>;
+export type Color = CamelCasedPropertiesDeep<components['schemas']['Color']>;
+export type ClassReference = CamelCasedPropertiesDeep<components['schemas']['ClassReference']>;
+export type Error = CamelCasedPropertiesDeep<components['schemas']['Error']>;
+export type CollectionInfo = CamelCasedPropertiesDeep<components['schemas']['CollectionInfo']>;
+export type TaskState = CamelCasedPropertiesDeep<components['schemas']['TaskState']>;
+export type DagState = CamelCasedPropertiesDeep<components['schemas']['DagState']>;
+export type TriggerRule = CamelCasedPropertiesDeep<components['schemas']['TriggerRule']>;
+export type WeightRule = CamelCasedPropertiesDeep<components['schemas']['WeightRule']>;
+export type HealthStatus = CamelCasedPropertiesDeep<components['schemas']['HealthStatus']>;
 
 /* Alias operations to PascalCase. */
 export type Operations = operations;
diff --git a/airflow/www/static/js/types/index.ts b/airflow/www/static/js/types/index.ts
index c8eb5d9ac8..d65e68115d 100644
--- a/airflow/www/static/js/types/index.ts
+++ b/airflow/www/static/js/types/index.ts
@@ -79,15 +79,6 @@ interface Task {
   hasOutletDatasets?: boolean;
 }
 
-type SnakeToCamelCase<S extends string> =
-  S extends `${infer T}_${infer U}`
-    ? `${T}${Capitalize<SnakeToCamelCase<U>>}`
-    : S;
-
-type SnakeToCamelCaseNested<T> = T extends object ? {
-  [K in keyof T as SnakeToCamelCase<K & string>]: SnakeToCamelCaseNested<T[K]>
-} : T;
-
 export type {
   Dag,
   DagRun,
@@ -96,6 +87,4 @@ export type {
   TaskInstance,
   Task,
   API,
-  SnakeToCamelCase,
-  SnakeToCamelCaseNested,
 };
diff --git a/airflow/www/yarn.lock b/airflow/www/yarn.lock
index 4295236051..c4c02ca5d7 100644
--- a/airflow/www/yarn.lock
+++ b/airflow/www/yarn.lock
@@ -9811,6 +9811,11 @@ type-fest@^1.2.1:
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
   integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
 
+type-fest@^2.17.0:
+  version "2.17.0"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.17.0.tgz#c677030ce61e5be0c90c077d52571eb73c506ea9"
+  integrity sha512-U+g3/JVXnOki1kLSc+xZGPRll3Ah9u2VIG6Sn9iH9YX6UkPERmt6O/0fIyTgsd2/whV0+gAaHAg8fz6sG1QzMA==
+
 typedarray-to-buffer@^3.1.5:
   version "3.1.5"
   resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"