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 9c592cbe43 Upgrade API files to typescript (#25098)
9c592cbe43 is described below

commit 9c592cbe4300f64be5698d0fc7a79e067b5b6832
Author: pierrejeambrun <[email protected]>
AuthorDate: Mon Aug 29 18:50:20 2022 +0200

    Upgrade API files to typescript (#25098)
    
    * Upgrade some of the migrations to ts.
    
    * Update types.
    
    * Update get type for useConfirmMarkTask.
    
    * Migrate useMarkFailedRun
    
    * migrate useMarkFailedTask, useMarkSuccessRun, useMarkSuccessTask
    
    * Migrate more
    
    * Use API types when possible
    
    * Migrate more
    
    * Add URLSearchParamsWrapper
    
    * Migrate more
---
 .../js/api/{useClearRun.js => useClearRun.ts}      | 13 ++++---
 .../js/api/{useClearTask.js => useClearTask.ts}    | 27 +++++++++----
 ...useConfirmMarkTask.js => useConfirmMarkTask.ts} | 23 +++++++----
 airflow/www/static/js/api/useDataset.ts            | 10 ++---
 airflow/www/static/js/api/useDatasetEvents.ts      | 37 ++++++------------
 .../js/api/{useExtraLinks.js => useExtraLinks.ts}  | 11 +++++-
 .../{useGridData.test.js => useGridData.test.ts}   | 45 ++++++++++++++--------
 airflow/www/static/js/api/useMappedInstances.ts    | 28 ++++----------
 .../{useMarkFailedRun.js => useMarkFailedRun.ts}   |  9 +++--
 .../{useMarkFailedTask.js => useMarkFailedTask.ts} | 17 ++++++--
 .../{useMarkSuccessRun.js => useMarkSuccessRun.ts} |  9 +++--
 ...useMarkSuccessTask.js => useMarkSuccessTask.ts} | 18 ++++++---
 .../js/api/{useQueueRun.js => useQueueRun.ts}      | 10 ++---
 .../static/js/api/{useRunTask.js => useRunTask.ts} | 12 ++++--
 .../{useTaskInstance.tsx => useTaskInstance.ts}    |  0
 .../js/api/{useTaskLog.tsx => useTaskLog.ts}       | 10 +----
 .../www/static/js/api/useUpstreamDatasetEvents.ts  |  7 +---
 .../js/dag/details/dagRun/DatasetTriggerEvents.tsx |  2 +-
 airflow/www/static/js/dag/details/dagRun/index.tsx |  5 ++-
 .../details/taskInstance/DatasetUpdateEvents.tsx   |  8 +++-
 .../js/dag/details/taskInstance/ExtraLinks.tsx     |  5 +--
 .../js/dag/details/taskInstance/Logs/index.tsx     |  3 +-
 .../dag/details/taskInstance/MappedInstances.tsx   |  6 +--
 .../www/static/js/dag/details/taskInstance/Nav.tsx | 11 +++---
 airflow/www/static/js/dag/useFilters.tsx           |  3 +-
 airflow/www/static/js/dag/useSelection.ts          |  3 +-
 airflow/www/static/js/datasets/DatasetEvents.tsx   |  6 +--
 airflow/www/static/js/datasets/Details.tsx         | 10 ++---
 airflow/www/static/js/datasets/index.tsx           |  2 +-
 .../URLSearchParamWrapper.ts}                      | 30 +++++++--------
 30 files changed, 202 insertions(+), 178 deletions(-)

diff --git a/airflow/www/static/js/api/useClearRun.js 
b/airflow/www/static/js/api/useClearRun.ts
similarity index 80%
rename from airflow/www/static/js/api/useClearRun.js
rename to airflow/www/static/js/api/useClearRun.ts
index f58fc45718..eea285034a 100644
--- a/airflow/www/static/js/api/useClearRun.js
+++ b/airflow/www/static/js/api/useClearRun.ts
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-import axios from 'axios';
+import axios, { AxiosResponse } from 'axios';
 import { useMutation, useQueryClient } from 'react-query';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import { useAutoRefresh } from '../context/autorefresh';
 import useErrorToast from '../utils/useErrorToast';
@@ -26,21 +27,21 @@ import useErrorToast from '../utils/useErrorToast';
 const csrfToken = getMetaValue('csrf_token');
 const clearRunUrl = getMetaValue('dagrun_clear_url');
 
-export default function useClearRun(dagId, runId) {
+export default function useClearRun(dagId: string, runId: string) {
   const queryClient = useQueryClient();
   const errorToast = useErrorToast();
   const { startRefresh } = useAutoRefresh();
   return useMutation(
     ['dagRunClear', dagId, runId],
-    ({ confirmed = false }) => {
-      const params = new URLSearchParams({
+    ({ confirmed = false }: { confirmed: boolean }) => {
+      const params = new URLSearchParamsWrapper({
         csrf_token: csrfToken,
         confirmed,
         dag_id: dagId,
         dag_run_id: runId,
       }).toString();
 
-      return axios.post(clearRunUrl, params, {
+      return axios.post<AxiosResponse, string>(clearRunUrl, params, {
         headers: {
           'Content-Type': 'application/x-www-form-urlencoded',
         },
@@ -52,7 +53,7 @@ export default function useClearRun(dagId, runId) {
         queryClient.invalidateQueries('gridData');
         startRefresh();
       },
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useClearTask.js 
b/airflow/www/static/js/api/useClearTask.ts
similarity index 75%
rename from airflow/www/static/js/api/useClearTask.js
rename to airflow/www/static/js/api/useClearTask.ts
index 5e77404144..a8fc1131aa 100644
--- a/airflow/www/static/js/api/useClearTask.js
+++ b/airflow/www/static/js/api/useClearTask.ts
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-import axios from 'axios';
+import axios, { AxiosResponse } from 'axios';
 import { useMutation, useQueryClient } from 'react-query';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import { useAutoRefresh } from '../context/autorefresh';
 import useErrorToast from '../utils/useErrorToast';
@@ -28,7 +29,10 @@ const clearUrl = getMetaValue('clear_url');
 
 export default function useClearTask({
   dagId, runId, taskId, executionDate,
-}) {
+}: { dagId: string,
+  runId: string,
+  taskId: string,
+  executionDate: string }) {
   const queryClient = useQueryClient();
   const errorToast = useErrorToast();
   const { startRefresh } = useAutoRefresh();
@@ -37,8 +41,15 @@ export default function useClearTask({
     ['clearTask', dagId, runId, taskId],
     ({
       past, future, upstream, downstream, recursive, failed, confirmed, 
mapIndexes = [],
-    }) => {
-      const params = new URLSearchParams({
+    }: { past: boolean,
+      future: boolean,
+      upstream: boolean,
+      downstream: boolean,
+      recursive: boolean,
+      failed: boolean,
+      confirmed: boolean,
+      mapIndexes: number[] }) => {
+      const params = new URLSearchParamsWrapper({
         csrf_token: csrfToken,
         dag_id: dagId,
         dag_run_id: runId,
@@ -53,11 +64,11 @@ export default function useClearTask({
         only_failed: failed,
       });
 
-      mapIndexes.forEach((mi) => {
-        params.append('map_index', mi);
+      mapIndexes.forEach((mi: number) => {
+        params.append('map_index', mi.toString());
       });
 
-      return axios.post(clearUrl, params.toString(), {
+      return axios.post<AxiosResponse, string>(clearUrl, params.toString(), {
         headers: {
           'Content-Type': 'application/x-www-form-urlencoded',
         },
@@ -69,7 +80,7 @@ export default function useClearTask({
         queryClient.invalidateQueries(['mappedInstances', dagId, runId, 
taskId]);
         startRefresh();
       },
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useConfirmMarkTask.js 
b/airflow/www/static/js/api/useConfirmMarkTask.ts
similarity index 69%
rename from airflow/www/static/js/api/useConfirmMarkTask.js
rename to airflow/www/static/js/api/useConfirmMarkTask.ts
index 68328ec7bc..ba654798c4 100644
--- a/airflow/www/static/js/api/useConfirmMarkTask.js
+++ b/airflow/www/static/js/api/useConfirmMarkTask.ts
@@ -17,8 +17,10 @@
  * under the License.
  */
 
-import axios from 'axios';
+import axios, { AxiosResponse } from 'axios';
 import { useMutation } from 'react-query';
+import type { TaskState } from 'src/types';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import useErrorToast from '../utils/useErrorToast';
 
@@ -26,14 +28,20 @@ const confirmUrl = getMetaValue('confirm_url');
 
 export default function useConfirmMarkTask({
   dagId, runId, taskId, state,
-}) {
+}: { dagId: string, runId: string, taskId: string, state: TaskState }) {
   const errorToast = useErrorToast();
   return useMutation(
     ['confirmStateChange', dagId, runId, taskId, state],
     ({
       past, future, upstream, downstream, mapIndexes = [],
+    }: {
+      past: boolean,
+      future: boolean,
+      upstream: boolean,
+      downstream: boolean,
+      mapIndexes: number[],
     }) => {
-      const params = new URLSearchParams({
+      const params = new URLSearchParamsWrapper({
         dag_id: dagId,
         dag_run_id: runId,
         task_id: taskId,
@@ -44,14 +52,13 @@ export default function useConfirmMarkTask({
         state,
       });
 
-      mapIndexes.forEach((mi) => {
-        params.append('map_index', mi);
+      mapIndexes.forEach((mi: number) => {
+        params.append('map_index', mi.toString());
       });
-
-      return axios.get(confirmUrl, { params });
+      return axios.get<AxiosResponse, string[]>(confirmUrl, { params });
     },
     {
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useDataset.ts 
b/airflow/www/static/js/api/useDataset.ts
index 6f213f5ca4..900bdbc2d1 100644
--- a/airflow/www/static/js/api/useDataset.ts
+++ b/airflow/www/static/js/api/useDataset.ts
@@ -23,15 +23,11 @@ import { useQuery } from 'react-query';
 import { getMetaValue } from 'src/utils';
 import type { API } from 'src/types';
 
-interface Props {
-  datasetUri: string;
-}
-
-export default function useDataset({ datasetUri }: Props) {
+export default function useDataset({ uri }: API.GetDatasetVariables) {
   return useQuery(
-    ['dataset', datasetUri],
+    ['dataset', uri],
     () => {
-      const datasetUrl = `${getMetaValue('datasets_api') || 
'/api/v1/datasets'}/${encodeURIComponent(datasetUri)}`;
+      const datasetUrl = `${getMetaValue('datasets_api') || 
'/api/v1/datasets'}/${encodeURIComponent(uri)}`;
       return axios.get<AxiosResponse, API.Dataset>(datasetUrl);
     },
   );
diff --git a/airflow/www/static/js/api/useDatasetEvents.ts 
b/airflow/www/static/js/api/useDatasetEvents.ts
index 9412bceea2..f92899e2de 100644
--- a/airflow/www/static/js/api/useDatasetEvents.ts
+++ b/airflow/www/static/js/api/useDatasetEvents.ts
@@ -22,43 +22,28 @@ import { useQuery } from 'react-query';
 
 import { getMetaValue } from 'src/utils';
 import type { API } from 'src/types';
-
-interface DatasetEventsData {
-  datasetEvents: API.DatasetEvent[];
-  totalEntries: number;
-}
-
-interface Props {
-  datasetId?: number;
-  dagId?: string;
-  taskId?: string;
-  runId?: string;
-  mapIndex?: number;
-  limit?: number;
-  offset?: number;
-  order?: string;
-}
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 
 export default function useDatasetEvents({
-  datasetId, dagId, runId, taskId, mapIndex, limit, offset, order,
-}: Props) {
+  datasetId, sourceDagId, sourceRunId, sourceTaskId, sourceMapIndex, limit, 
offset, orderBy,
+}: API.GetDatasetEventsVariables) {
   const query = useQuery(
-    ['datasets-events', datasetId, dagId, runId, taskId, mapIndex, limit, 
offset, order],
+    ['datasets-events', datasetId, sourceDagId, sourceRunId, sourceTaskId, 
sourceMapIndex, limit, offset, orderBy],
     () => {
       const datasetsUrl = getMetaValue('dataset_events_api') || 
'/api/v1/datasets/events';
 
-      const params = new URLSearchParams();
+      const params = new URLSearchParamsWrapper();
 
       if (limit) params.set('limit', limit.toString());
       if (offset) params.set('offset', offset.toString());
-      if (order) params.set('order_by', order);
+      if (orderBy) params.set('order_by', orderBy);
       if (datasetId) params.set('dataset_id', datasetId.toString());
-      if (dagId) params.set('source_dag_id', dagId);
-      if (runId) params.set('source_run_id', runId);
-      if (taskId) params.set('source_task_id', taskId);
-      if (mapIndex) params.set('source_map_index', mapIndex.toString());
+      if (sourceDagId) params.set('source_dag_id', sourceDagId);
+      if (sourceRunId) params.set('source_run_id', sourceRunId);
+      if (sourceTaskId) params.set('source_task_id', sourceTaskId);
+      if (sourceMapIndex) params.set('source_map_index', 
sourceMapIndex.toString());
 
-      return axios.get<AxiosResponse, DatasetEventsData>(datasetsUrl, {
+      return axios.get<AxiosResponse, API.DatasetEventCollection>(datasetsUrl, 
{
         params,
       });
     },
diff --git a/airflow/www/static/js/api/useExtraLinks.js 
b/airflow/www/static/js/api/useExtraLinks.ts
similarity index 86%
rename from airflow/www/static/js/api/useExtraLinks.js
rename to airflow/www/static/js/api/useExtraLinks.ts
index 24262b6b7c..76fe4610bb 100644
--- a/airflow/www/static/js/api/useExtraLinks.js
+++ b/airflow/www/static/js/api/useExtraLinks.ts
@@ -17,14 +17,21 @@
  * under the License.
  */
 
-import axios from 'axios';
+import axios, { AxiosResponse } from 'axios';
 import { useQuery } from 'react-query';
 import { getMetaValue } from '../utils';
 
 const extraLinksUrl = getMetaValue('extra_links_url');
 
+interface LinkData {
+  url: string | null;
+  error: string | null;
+}
+
 export default function useExtraLinks({
   dagId, taskId, executionDate, extraLinks,
+}: {
+  dagId: string, taskId: string, executionDate: string, extraLinks: string[],
 }) {
   return useQuery(
     ['extraLinks', dagId, taskId, executionDate],
@@ -36,7 +43,7 @@ export default function useExtraLinks({
         }&execution_date=${encodeURIComponent(executionDate)
         }&link_name=${encodeURIComponent(link)}`;
         try {
-          const datum = await axios.get(url);
+          const datum = await axios.get<AxiosResponse, LinkData>(url);
           return {
             name: link,
             url: datum.url,
diff --git a/airflow/www/static/js/api/useGridData.test.js 
b/airflow/www/static/js/api/useGridData.test.ts
similarity index 65%
rename from airflow/www/static/js/api/useGridData.test.js
rename to airflow/www/static/js/api/useGridData.test.ts
index 83fabe0018..c5a0e6c9de 100644
--- a/airflow/www/static/js/api/useGridData.test.js
+++ b/airflow/www/static/js/api/useGridData.test.ts
@@ -19,42 +19,53 @@
 
 /* global describe, test, expect */
 
+import type { DagRun } from 'src/types';
 import { areActiveRuns } from './useGridData';
 
+const commonDagRunParams = {
+  runId: 'runId',
+  executionDate: '2022-01-01T10:00+00:00',
+  dataIntervalStart: '2022-01-01T05:00+00:00',
+  dataIntervalEnd: '2022-01-01T10:00+00:00',
+  startDate: null,
+  endDate: null,
+  lastSchedulingDecision: null,
+};
+
 describe('Test areActiveRuns()', () => {
   test('Correctly detects active runs', () => {
-    const runs = [
-      { runType: 'scheduled', state: 'success' },
-      { runType: 'manual', state: 'queued' },
+    const runs: DagRun[] = [
+      { runType: 'scheduled', state: 'success', ...commonDagRunParams },
+      { runType: 'manual', state: 'queued', ...commonDagRunParams },
     ];
     expect(areActiveRuns(runs)).toBe(true);
   });
 
   test('Returns false when all runs are resolved', () => {
-    const runs = [
-      { runType: 'scheduled', state: 'success' },
-      { runType: 'manual', state: 'failed' },
-      { runType: 'manual', state: 'failed' },
+    const runs: DagRun[] = [
+      { runType: 'scheduled', state: 'success', ...commonDagRunParams },
+      { runType: 'manual', state: 'failed', ...commonDagRunParams },
+      { runType: 'manual', state: 'failed', ...commonDagRunParams },
     ];
     const result = areActiveRuns(runs);
     expect(result).toBe(false);
   });
 
-  test('Returns false when filtering runs runtype ["backfill"] and state 
["failed"]', () => {
-    const runs = [
-      { runType: 'scheduled', state: 'success' },
-      { runType: 'manual', state: 'failed' },
-      { runType: 'backfill', state: 'failed' },
+  test('Returns false when filtering runs runtype ["backfill"]', () => {
+    const runs: DagRun[] = [
+      { runType: 'scheduled', state: 'success', ...commonDagRunParams },
+      { runType: 'manual', state: 'failed', ...commonDagRunParams },
+      { runType: 'backfill', state: 'failed', ...commonDagRunParams },
     ];
     const result = areActiveRuns(runs);
     expect(result).toBe(false);
   });
 
   test('Returns false when filtering runs runtype ["backfill"] and state 
["queued"]', () => {
-    const runs = [
-      { runType: 'scheduled', state: 'success' },
-      { runType: 'manual', state: 'failed' },
-      { runType: 'backfill', state: 'queued' },
+    const runs: DagRun[] = [
+      { runType: 'scheduled', state: 'success', ...commonDagRunParams },
+      { runType: 'manual', state: 'failed', ...commonDagRunParams },
+      { runType: 'backfill', state: 'queued', ...commonDagRunParams },
     ];
     const result = areActiveRuns(runs);
     expect(result).toBe(false);
@@ -87,7 +98,7 @@ describe('Test areActiveRuns()', () => {
     },
   ].forEach(({ state, runType, expectedResult }) => {
     test(`Returns ${expectedResult} when filtering runs with runtype 
["${runType}"] and state ["${state}"]`, () => {
-      const runs = [{ runType, state }];
+      const runs: DagRun[] = [{ runType, state, ...commonDagRunParams } as 
DagRun];
       const result = areActiveRuns(runs);
       expect(result).toBe(expectedResult);
     });
diff --git a/airflow/www/static/js/api/useMappedInstances.ts 
b/airflow/www/static/js/api/useMappedInstances.ts
index 4ddefccf9f..c14557a03a 100644
--- a/airflow/www/static/js/api/useMappedInstances.ts
+++ b/airflow/www/static/js/api/useMappedInstances.ts
@@ -22,33 +22,19 @@ import { useQuery } from 'react-query';
 
 import { getMetaValue } from 'src/utils';
 import { useAutoRefresh } from 'src/context/autorefresh';
-import type { API, DagRun } from 'src/types';
+import type { API } from 'src/types';
 
 const mappedInstancesUrl = getMetaValue('mapped_instances_api');
 
-interface MappedInstanceData {
-  taskInstances: API.TaskInstance[];
-  totalEntries: number;
-}
-
-interface Props {
-  dagId: string;
-  runId: DagRun['runId'];
-  taskId: string;
-  limit?: number;
-  offset?: number;
-  order?: string;
-}
-
 export default function useMappedInstances({
-  dagId, runId, taskId, limit, offset, order,
-}: Props) {
-  const url = mappedInstancesUrl.replace('_DAG_RUN_ID_', 
runId).replace('_TASK_ID_', taskId);
-  const orderParam = order && order !== 'map_index' ? { order_by: order } : {};
+  dagId, dagRunId, taskId, limit, offset, orderBy,
+}: API.GetMappedTaskInstancesVariables) {
+  const url = mappedInstancesUrl.replace('_DAG_RUN_ID_', 
dagRunId).replace('_TASK_ID_', taskId);
+  const orderParam = orderBy && orderBy !== 'map_index' ? { order_by: orderBy 
} : {};
   const { isRefreshOn } = useAutoRefresh();
   return useQuery(
-    ['mappedInstances', dagId, runId, taskId, offset, order],
-    () => axios.get<AxiosResponse, MappedInstanceData>(url, {
+    ['mappedInstances', dagId, dagRunId, taskId, offset, orderBy],
+    () => axios.get<AxiosResponse, API.TaskInstanceCollection>(url, {
       params: { offset, limit, ...orderParam },
     }),
     {
diff --git a/airflow/www/static/js/api/useMarkFailedRun.js 
b/airflow/www/static/js/api/useMarkFailedRun.ts
similarity index 85%
rename from airflow/www/static/js/api/useMarkFailedRun.js
rename to airflow/www/static/js/api/useMarkFailedRun.ts
index 8e37bc4c1a..ac5ef6def4 100644
--- a/airflow/www/static/js/api/useMarkFailedRun.js
+++ b/airflow/www/static/js/api/useMarkFailedRun.ts
@@ -19,6 +19,7 @@
 
 import axios from 'axios';
 import { useMutation, useQueryClient } from 'react-query';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import { useAutoRefresh } from '../context/autorefresh';
 import useErrorToast from '../utils/useErrorToast';
@@ -26,14 +27,14 @@ import useErrorToast from '../utils/useErrorToast';
 const csrfToken = getMetaValue('csrf_token');
 const markFailedUrl = getMetaValue('dagrun_failed_url');
 
-export default function useMarkFailedRun(dagId, runId) {
+export default function useMarkFailedRun(dagId: string, runId: string) {
   const queryClient = useQueryClient();
   const errorToast = useErrorToast();
   const { startRefresh } = useAutoRefresh();
   return useMutation(
     ['dagRunFailed', dagId, runId],
-    ({ confirmed = false }) => {
-      const params = new URLSearchParams({
+    ({ confirmed = false }: { confirmed: boolean }) => {
+      const params = new URLSearchParamsWrapper({
         csrf_token: csrfToken,
         confirmed,
         dag_id: dagId,
@@ -51,7 +52,7 @@ export default function useMarkFailedRun(dagId, runId) {
         queryClient.invalidateQueries('gridData');
         startRefresh();
       },
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useMarkFailedTask.js 
b/airflow/www/static/js/api/useMarkFailedTask.ts
similarity index 82%
rename from airflow/www/static/js/api/useMarkFailedTask.js
rename to airflow/www/static/js/api/useMarkFailedTask.ts
index 4ba8b601f4..caac2fcd9d 100644
--- a/airflow/www/static/js/api/useMarkFailedTask.js
+++ b/airflow/www/static/js/api/useMarkFailedTask.ts
@@ -19,6 +19,7 @@
 
 import axios from 'axios';
 import { useMutation, useQueryClient } from 'react-query';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import { useAutoRefresh } from '../context/autorefresh';
 import useErrorToast from '../utils/useErrorToast';
@@ -28,6 +29,8 @@ const csrfToken = getMetaValue('csrf_token');
 
 export default function useMarkFailedTask({
   dagId, runId, taskId,
+}: {
+  dagId: string, runId: string, taskId: string,
 }) {
   const queryClient = useQueryClient();
   const errorToast = useErrorToast();
@@ -36,8 +39,14 @@ export default function useMarkFailedTask({
     ['markFailed', dagId, runId, taskId],
     ({
       past, future, upstream, downstream, mapIndexes = [],
+    }: {
+      past: boolean,
+      future: boolean,
+      upstream: boolean,
+      downstream: boolean,
+      mapIndexes: number[]
     }) => {
-      const params = new URLSearchParams({
+      const params = new URLSearchParamsWrapper({
         csrf_token: csrfToken,
         dag_id: dagId,
         dag_run_id: runId,
@@ -49,8 +58,8 @@ export default function useMarkFailedTask({
         downstream,
       });
 
-      mapIndexes.forEach((mi) => {
-        params.append('map_index', mi);
+      mapIndexes.forEach((mi: number) => {
+        params.append('map_index', mi.toString());
       });
 
       return axios.post(failedUrl, params.toString(), {
@@ -65,7 +74,7 @@ export default function useMarkFailedTask({
         queryClient.invalidateQueries(['mappedInstances', dagId, runId, 
taskId]);
         startRefresh();
       },
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useMarkSuccessRun.js 
b/airflow/www/static/js/api/useMarkSuccessRun.ts
similarity index 85%
rename from airflow/www/static/js/api/useMarkSuccessRun.js
rename to airflow/www/static/js/api/useMarkSuccessRun.ts
index 7b3cb77665..d90bbb03a8 100644
--- a/airflow/www/static/js/api/useMarkSuccessRun.js
+++ b/airflow/www/static/js/api/useMarkSuccessRun.ts
@@ -19,6 +19,7 @@
 
 import axios from 'axios';
 import { useMutation, useQueryClient } from 'react-query';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import { useAutoRefresh } from '../context/autorefresh';
 import useErrorToast from '../utils/useErrorToast';
@@ -26,14 +27,14 @@ import useErrorToast from '../utils/useErrorToast';
 const markSuccessUrl = getMetaValue('dagrun_success_url');
 const csrfToken = getMetaValue('csrf_token');
 
-export default function useMarkSuccessRun(dagId, runId) {
+export default function useMarkSuccessRun(dagId: string, runId: string) {
   const queryClient = useQueryClient();
   const errorToast = useErrorToast();
   const { startRefresh } = useAutoRefresh();
   return useMutation(
     ['dagRunSuccess', dagId, runId],
-    ({ confirmed = false }) => {
-      const params = new URLSearchParams({
+    ({ confirmed = false }: { confirmed: boolean }) => {
+      const params = new URLSearchParamsWrapper({
         csrf_token: csrfToken,
         confirmed,
         dag_id: dagId,
@@ -51,7 +52,7 @@ export default function useMarkSuccessRun(dagId, runId) {
         queryClient.invalidateQueries('gridData');
         startRefresh();
       },
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useMarkSuccessTask.js 
b/airflow/www/static/js/api/useMarkSuccessTask.ts
similarity index 82%
rename from airflow/www/static/js/api/useMarkSuccessTask.js
rename to airflow/www/static/js/api/useMarkSuccessTask.ts
index b3415a1146..8120b58edf 100644
--- a/airflow/www/static/js/api/useMarkSuccessTask.js
+++ b/airflow/www/static/js/api/useMarkSuccessTask.ts
@@ -19,6 +19,7 @@
 
 import axios from 'axios';
 import { useMutation, useQueryClient } from 'react-query';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import { useAutoRefresh } from '../context/autorefresh';
 import useErrorToast from '../utils/useErrorToast';
@@ -28,6 +29,8 @@ const successUrl = getMetaValue('success_url');
 
 export default function useMarkSuccessTask({
   dagId, runId, taskId,
+}: {
+  dagId: string, runId: string, taskId: string,
 }) {
   const queryClient = useQueryClient();
   const errorToast = useErrorToast();
@@ -36,8 +39,14 @@ export default function useMarkSuccessTask({
     ['markSuccess', dagId, runId, taskId],
     ({
       past, future, upstream, downstream, mapIndexes = [],
+    }: {
+      past: boolean,
+      future: boolean,
+      upstream: boolean,
+      downstream: boolean,
+      mapIndexes: number[]
     }) => {
-      const params = new URLSearchParams({
+      const params = new URLSearchParamsWrapper({
         csrf_token: csrfToken,
         dag_id: dagId,
         dag_run_id: runId,
@@ -47,11 +56,10 @@ export default function useMarkSuccessTask({
         future,
         upstream,
         downstream,
-        map_indexes: mapIndexes,
       });
 
-      mapIndexes.forEach((mi) => {
-        params.append('map_index', mi);
+      mapIndexes.forEach((mi: number) => {
+        params.append('map_index', mi.toString());
       });
 
       return axios.post(successUrl, params.toString(), {
@@ -66,7 +74,7 @@ export default function useMarkSuccessTask({
         queryClient.invalidateQueries(['mappedInstances', dagId, runId, 
taskId]);
         startRefresh();
       },
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useQueueRun.js 
b/airflow/www/static/js/api/useQueueRun.ts
similarity index 85%
rename from airflow/www/static/js/api/useQueueRun.js
rename to airflow/www/static/js/api/useQueueRun.ts
index 5ab3879d07..e919c3f60f 100644
--- a/airflow/www/static/js/api/useQueueRun.js
+++ b/airflow/www/static/js/api/useQueueRun.ts
@@ -19,6 +19,7 @@
 
 import axios from 'axios';
 import { useMutation, useQueryClient } from 'react-query';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import { useAutoRefresh } from '../context/autorefresh';
 import useErrorToast from '../utils/useErrorToast';
@@ -26,20 +27,19 @@ import useErrorToast from '../utils/useErrorToast';
 const csrfToken = getMetaValue('csrf_token');
 const queuedUrl = getMetaValue('dagrun_queued_url');
 
-export default function useQueueRun(dagId, runId) {
+export default function useQueueRun(dagId: string, runId: string) {
   const queryClient = useQueryClient();
   const errorToast = useErrorToast();
   const { startRefresh } = useAutoRefresh();
   return useMutation(
     ['dagRunQueue', dagId, runId],
-    ({ confirmed = false }) => {
-      const params = new URLSearchParams({
+    ({ confirmed = false }: { confirmed: boolean }) => {
+      const params = new URLSearchParamsWrapper({
         csrf_token: csrfToken,
         confirmed,
         dag_id: dagId,
         dag_run_id: runId,
       }).toString();
-
       return axios.post(queuedUrl, params, {
         headers: {
           'Content-Type': 'application/x-www-form-urlencoded',
@@ -51,7 +51,7 @@ export default function useQueueRun(dagId, runId) {
         queryClient.invalidateQueries('gridData');
         startRefresh();
       },
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useRunTask.js 
b/airflow/www/static/js/api/useRunTask.ts
similarity index 84%
rename from airflow/www/static/js/api/useRunTask.js
rename to airflow/www/static/js/api/useRunTask.ts
index 1235acd41c..98b3cc873c 100644
--- a/airflow/www/static/js/api/useRunTask.js
+++ b/airflow/www/static/js/api/useRunTask.ts
@@ -19,6 +19,7 @@
 
 import axios from 'axios';
 import { useMutation, useQueryClient } from 'react-query';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import { getMetaValue } from '../utils';
 import { useAutoRefresh } from '../context/autorefresh';
 import useErrorToast from '../utils/useErrorToast';
@@ -26,7 +27,7 @@ import useErrorToast from '../utils/useErrorToast';
 const csrfToken = getMetaValue('csrf_token');
 const runUrl = getMetaValue('run_url');
 
-export default function useRunTask(dagId, runId, taskId) {
+export default function useRunTask(dagId: string, runId: string, taskId: 
string) {
   const queryClient = useQueryClient();
   const errorToast = useErrorToast();
   const { startRefresh } = useAutoRefresh();
@@ -37,9 +38,14 @@ export default function useRunTask(dagId, runId, taskId) {
       ignoreTaskState,
       ignoreTaskDeps,
       mapIndexes,
+    }:{
+      ignoreAllDeps: boolean,
+      ignoreTaskState: boolean,
+      ignoreTaskDeps: boolean,
+      mapIndexes: number[],
     }) => Promise.all(
       (mapIndexes.length ? mapIndexes : [-1]).map((mi) => {
-        const params = new URLSearchParams({
+        const params = new URLSearchParamsWrapper({
           csrf_token: csrfToken,
           dag_id: dagId,
           dag_run_id: runId,
@@ -63,7 +69,7 @@ export default function useRunTask(dagId, runId, taskId) {
         queryClient.invalidateQueries(['mappedInstances', dagId, runId, 
taskId]);
         startRefresh();
       },
-      onError: (error) => errorToast({ error }),
+      onError: (error: Error) => errorToast({ error }),
     },
   );
 }
diff --git a/airflow/www/static/js/api/useTaskInstance.tsx 
b/airflow/www/static/js/api/useTaskInstance.ts
similarity index 100%
rename from airflow/www/static/js/api/useTaskInstance.tsx
rename to airflow/www/static/js/api/useTaskInstance.ts
diff --git a/airflow/www/static/js/api/useTaskLog.tsx 
b/airflow/www/static/js/api/useTaskLog.ts
similarity index 92%
rename from airflow/www/static/js/api/useTaskLog.tsx
rename to airflow/www/static/js/api/useTaskLog.ts
index f389f4c118..1c8b999de8 100644
--- a/airflow/www/static/js/api/useTaskLog.tsx
+++ b/airflow/www/static/js/api/useTaskLog.ts
@@ -20,6 +20,7 @@
 import axios, { AxiosResponse } from 'axios';
 import { useQuery } from 'react-query';
 import { useAutoRefresh } from 'src/context/autorefresh';
+import type { API } from 'src/types';
 
 import { getMetaValue } from 'src/utils';
 
@@ -27,14 +28,7 @@ const taskLogApi = getMetaValue('task_log_api');
 
 const useTaskLog = ({
   dagId, dagRunId, taskId, taskTryNumber, mapIndex, fullContent,
-}: {
-  dagId: string,
-  dagRunId: string,
-  taskId: string,
-  taskTryNumber: number,
-  mapIndex?: number,
-  fullContent: boolean,
-}) => {
+}: API.GetLogVariables) => {
   let url: string = '';
   if (taskLogApi) {
     url = taskLogApi.replace('_DAG_RUN_ID_', dagRunId).replace('_TASK_ID_', 
taskId).replace(/-1$/, taskTryNumber.toString());
diff --git a/airflow/www/static/js/api/useUpstreamDatasetEvents.ts 
b/airflow/www/static/js/api/useUpstreamDatasetEvents.ts
index 4821b4dd5f..4fa1b76517 100644
--- a/airflow/www/static/js/api/useUpstreamDatasetEvents.ts
+++ b/airflow/www/static/js/api/useUpstreamDatasetEvents.ts
@@ -27,11 +27,6 @@ interface Props {
   runId: string;
 }
 
-interface UpstreamEventsData {
-  datasetEvents: API.DatasetEvent[];
-  totalEntries: number;
-}
-
 export default function useUpstreamDatasetEvents({ runId }: Props) {
   const query = useQuery(
     ['upstreamDatasetEvents', runId],
@@ -41,7 +36,7 @@ export default function useUpstreamDatasetEvents({ runId }: 
Props) {
         getMetaValue('upstream_dataset_events_api')
           || `api/v1/dags/${dagId}/dagRuns/_DAG_RUN_ID_/upstreamDatasetEvents`
       ).replace('_DAG_RUN_ID_', runId);
-      return axios.get<AxiosResponse, UpstreamEventsData>(upstreamEventsUrl);
+      return axios.get<AxiosResponse, 
API.DatasetEventCollection>(upstreamEventsUrl);
     },
   );
   return {
diff --git a/airflow/www/static/js/dag/details/dagRun/DatasetTriggerEvents.tsx 
b/airflow/www/static/js/dag/details/dagRun/DatasetTriggerEvents.tsx
index 81ed63676a..c18bddcfb6 100644
--- a/airflow/www/static/js/dag/details/dagRun/DatasetTriggerEvents.tsx
+++ b/airflow/www/static/js/dag/details/dagRun/DatasetTriggerEvents.tsx
@@ -32,7 +32,7 @@ interface Props {
 }
 
 const DatasetTriggerEvents = ({ runId }: Props) => {
-  const { data: { datasetEvents }, isLoading } = useUpstreamDatasetEvents({ 
runId });
+  const { data: { datasetEvents = [] }, isLoading } = 
useUpstreamDatasetEvents({ runId });
 
   const columns = useMemo(
     () => [
diff --git a/airflow/www/static/js/dag/details/dagRun/index.tsx 
b/airflow/www/static/js/dag/details/dagRun/index.tsx
index b9a1056e21..935a08c64b 100644
--- a/airflow/www/static/js/dag/details/dagRun/index.tsx
+++ b/airflow/www/static/js/dag/details/dagRun/index.tsx
@@ -41,6 +41,7 @@ import { formatDuration, getDuration } from 
'src/datetime_utils';
 import Time from 'src/components/Time';
 import RunTypeIcon from 'src/components/RunTypeIcon';
 
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import MarkFailedRun from './MarkFailedRun';
 import MarkSuccessRun from './MarkSuccessRun';
 import QueueRun from './QueueRun';
@@ -69,10 +70,10 @@ const DagRun = ({ runId }: Props) => {
     startDate,
     endDate,
   } = run;
-  const detailsParams = new URLSearchParams({
+  const detailsParams = new URLSearchParamsWrapper({
     run_id: runId,
   }).toString();
-  const graphParams = new URLSearchParams({
+  const graphParams = new URLSearchParamsWrapper({
     execution_date: executionDate,
   }).toString();
   const graphLink = appendSearchParams(graphUrl, graphParams);
diff --git 
a/airflow/www/static/js/dag/details/taskInstance/DatasetUpdateEvents.tsx 
b/airflow/www/static/js/dag/details/taskInstance/DatasetUpdateEvents.tsx
index 8cc8fb7aee..885819b236 100644
--- a/airflow/www/static/js/dag/details/taskInstance/DatasetUpdateEvents.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/DatasetUpdateEvents.tsx
@@ -36,7 +36,13 @@ interface Props {
 const dagId = getMetaValue('dag_id') || undefined;
 
 const DatasetUpdateEvents = ({ runId, taskId }: Props) => {
-  const { data: { datasetEvents }, isLoading } = useDatasetEvents({ runId, 
taskId, dagId });
+  const { data: { datasetEvents = [] }, isLoading } = useDatasetEvents(
+    {
+      sourceDagId: dagId,
+      sourceRunId: runId,
+      sourceTaskId: taskId,
+    },
+  );
 
   const columns = useMemo(
     () => [
diff --git a/airflow/www/static/js/dag/details/taskInstance/ExtraLinks.tsx 
b/airflow/www/static/js/dag/details/taskInstance/ExtraLinks.tsx
index 580d8c9bca..2c9dbfe303 100644
--- a/airflow/www/static/js/dag/details/taskInstance/ExtraLinks.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/ExtraLinks.tsx
@@ -26,11 +26,10 @@ import {
 } from '@chakra-ui/react';
 
 import { useExtraLinks } from 'src/api';
-import type { Task } from 'src/types';
 
 interface Props {
   dagId: string;
-  taskId: Task['id'];
+  taskId: string;
   executionDate: string;
   extraLinks: string[];
 }
@@ -46,7 +45,7 @@ const ExtraLinks = ({
   });
 
   if (!links.length) return null;
-  const isExternal = (url: string) => /^(?:[a-z]+:)?\/\//.test(url);
+  const isExternal = (url: string | null) => url && 
/^(?:[a-z]+:)?\/\//.test(url);
 
   return (
     <>
diff --git a/airflow/www/static/js/dag/details/taskInstance/Logs/index.tsx 
b/airflow/www/static/js/dag/details/taskInstance/Logs/index.tsx
index d6e8c5fcac..a5324f2c88 100644
--- a/airflow/www/static/js/dag/details/taskInstance/Logs/index.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/Logs/index.tsx
@@ -37,6 +37,7 @@ import { useTimezone } from 'src/context/timezone';
 import type { Dag, DagRun, TaskInstance } from 'src/types';
 import MultiSelect from 'src/components/MultiSelect';
 
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 import LogLink from './LogLink';
 import { LogLevel, logLevelColorMapping, parseLogs } from './utils';
 
@@ -113,7 +114,7 @@ const Logs = ({
     fullContent: shouldRequestFullContent,
   });
 
-  const params = new URLSearchParams({
+  const params = new URLSearchParamsWrapper({
     task_id: taskId,
     execution_date: executionDate,
   });
diff --git a/airflow/www/static/js/dag/details/taskInstance/MappedInstances.tsx 
b/airflow/www/static/js/dag/details/taskInstance/MappedInstances.tsx
index 9796814fcc..fc32a9844b 100644
--- a/airflow/www/static/js/dag/details/taskInstance/MappedInstances.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/MappedInstances.tsx
@@ -50,13 +50,13 @@ const MappedInstances = ({
 
   const sort = sortBy[0];
 
-  const order = sort && (sort.id === 'state' || sort.id === 'mapIndex') ? 
`${sort.desc ? '-' : ''}${snakeCase(sort.id)}` : '';
+  const orderBy = sort && (sort.id === 'state' || sort.id === 'mapIndex') ? 
`${sort.desc ? '-' : ''}${snakeCase(sort.id)}` : '';
 
   const {
-    data: { taskInstances, totalEntries } = { taskInstances: [], totalEntries: 
0 },
+    data: { taskInstances = [], totalEntries = 0 } = { taskInstances: [], 
totalEntries: 0 },
     isLoading,
   } = useMappedInstances({
-    dagId, runId, taskId, limit, offset, order,
+    dagId, dagRunId: runId, taskId, limit, offset, orderBy,
   });
 
   const data = useMemo(() => taskInstances.map((mi) => ({
diff --git a/airflow/www/static/js/dag/details/taskInstance/Nav.tsx 
b/airflow/www/static/js/dag/details/taskInstance/Nav.tsx
index 6a2c314930..833a7b3169 100644
--- a/airflow/www/static/js/dag/details/taskInstance/Nav.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/Nav.tsx
@@ -26,6 +26,7 @@ import {
 import { getMetaValue, appendSearchParams } from 'src/utils';
 import LinkButton from 'src/components/LinkButton';
 import type { Task, DagRun } from 'src/types';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 
 const dagId = getMetaValue('dag_id');
 const isK8sExecutor = getMetaValue('k8s_or_k8scelery_executor') === 'True';
@@ -53,26 +54,26 @@ const Nav = ({
   runId, taskId, executionDate, operator, isMapped = false, mapIndex,
 }: Props) => {
   if (!taskId) return null;
-  const params = new URLSearchParams({
+  const params = new URLSearchParamsWrapper({
     task_id: taskId,
     execution_date: executionDate,
-    map_index: mapIndex?.toString() ?? '-1',
+    map_index: mapIndex ?? -1,
   });
   const detailsLink = `${taskUrl}&${params}`;
   const renderedLink = `${renderedTemplatesUrl}&${params}`;
   const logLink = `${logUrl}&${params}`;
   const xcomLink = `${xcomUrl}&${params}`;
   const k8sLink = `${renderedK8sUrl}&${params}`;
-  const listParams = new URLSearchParams({
+  const listParams = new URLSearchParamsWrapper({
     _flt_3_dag_id: dagId,
     _flt_3_task_id: taskId,
     _oc_TaskInstanceModelView: 'dag_run.execution_date',
   });
-  const subDagParams = new URLSearchParams({
+  const subDagParams = new URLSearchParamsWrapper({
     execution_date: executionDate,
   }).toString();
 
-  const filterParams = new URLSearchParams({
+  const filterParams = new URLSearchParamsWrapper({
     task_id: taskId,
     dag_run_id: runId,
     root: taskId,
diff --git a/airflow/www/static/js/dag/useFilters.tsx 
b/airflow/www/static/js/dag/useFilters.tsx
index 8846f32587..7e7fe2e04d 100644
--- a/airflow/www/static/js/dag/useFilters.tsx
+++ b/airflow/www/static/js/dag/useFilters.tsx
@@ -20,6 +20,7 @@
 /* global moment */
 
 import { useSearchParams } from 'react-router-dom';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 
 declare const defaultDagRunDisplayNumber: number;
 
@@ -66,7 +67,7 @@ const useFilters = (): FilterHookReturn => {
     formatFn?: (arg: string) => string,
   ) => (value: string) => {
     const formattedValue = formatFn ? formatFn(value) : value;
-    const params = new URLSearchParams(searchParams);
+    const params = new URLSearchParamsWrapper(searchParams);
 
     if (formattedValue) params.set(paramName, formattedValue);
     else params.delete(paramName);
diff --git a/airflow/www/static/js/dag/useSelection.ts 
b/airflow/www/static/js/dag/useSelection.ts
index 790e584e83..6242973b49 100644
--- a/airflow/www/static/js/dag/useSelection.ts
+++ b/airflow/www/static/js/dag/useSelection.ts
@@ -18,6 +18,7 @@
  */
 
 import { useSearchParams } from 'react-router-dom';
+import URLSearchParamsWrapper from 'src/utils/URLSearchParamWrapper';
 
 const RUN_ID = 'dag_run_id';
 const TASK_ID = 'task_id';
@@ -41,7 +42,7 @@ const useSelection = () => {
   };
 
   const onSelect = ({ runId, taskId, mapIndex }: SelectionProps) => {
-    const params = new URLSearchParams(searchParams);
+    const params = new URLSearchParamsWrapper(searchParams);
 
     if (runId) params.set(RUN_ID, runId);
     else params.delete(RUN_ID);
diff --git a/airflow/www/static/js/datasets/DatasetEvents.tsx 
b/airflow/www/static/js/datasets/DatasetEvents.tsx
index 384aebd67e..0a236ad0db 100644
--- a/airflow/www/static/js/datasets/DatasetEvents.tsx
+++ b/airflow/www/static/js/datasets/DatasetEvents.tsx
@@ -34,13 +34,13 @@ const Events = ({
   const [sortBy, setSortBy] = useState<SortingRule<object>[]>([{ id: 
'timestamp', desc: true }]);
 
   const sort = sortBy[0];
-  const order = sort ? `${sort.desc ? '-' : ''}${snakeCase(sort.id)}` : '';
+  const orderBy = sort ? `${sort.desc ? '-' : ''}${snakeCase(sort.id)}` : '';
 
   const {
-    data: { datasetEvents, totalEntries },
+    data: { datasetEvents = [], totalEntries = 0 },
     isLoading: isEventsLoading,
   } = useDatasetEvents({
-    datasetId, limit, offset, order,
+    datasetId, limit, offset, orderBy,
   });
 
   const columns = useMemo(
diff --git a/airflow/www/static/js/datasets/Details.tsx 
b/airflow/www/static/js/datasets/Details.tsx
index bf85f8e264..a08044438d 100644
--- a/airflow/www/static/js/datasets/Details.tsx
+++ b/airflow/www/static/js/datasets/Details.tsx
@@ -28,12 +28,12 @@ import InfoTooltip from 'src/components/InfoTooltip';
 import Events from './DatasetEvents';
 
 interface Props {
-  datasetUri: string;
+  uri: string;
   onBack: () => void;
 }
 
-const DatasetDetails = ({ datasetUri, onBack }: Props) => {
-  const { data: dataset, isLoading } = useDataset({ datasetUri });
+const DatasetDetails = ({ uri, onBack }: Props) => {
+  const { data: dataset, isLoading } = useDataset({ uri });
   return (
     <Box mt={[6, 3]}>
       <Button onClick={onBack}>See all datasets</Button>
@@ -42,8 +42,8 @@ const DatasetDetails = ({ datasetUri, onBack }: Props) => {
         <Heading my={2} fontWeight="normal" size="lg">
           Dataset:
           {' '}
-          {datasetUri}
-          <ClipboardButton value={datasetUri} iconOnly ml={2} />
+          {uri}
+          <ClipboardButton value={uri} iconOnly ml={2} />
         </Heading>
       </Box>
       <Flex alignItems="center">
diff --git a/airflow/www/static/js/datasets/index.tsx 
b/airflow/www/static/js/datasets/index.tsx
index 644024c9a5..6e32995e92 100644
--- a/airflow/www/static/js/datasets/index.tsx
+++ b/airflow/www/static/js/datasets/index.tsx
@@ -61,7 +61,7 @@ const Datasets = () => {
     <Flex alignItems="flex-start" justifyContent="space-between">
       <Box width="600px" height="calc(100vh - 125px)" overflowY="scroll">
         {datasetUri
-          ? <DatasetDetails datasetUri={datasetUri} onBack={onBack} />
+          ? <DatasetDetails uri={datasetUri} onBack={onBack} />
           : <DatasetsList onSelect={onSelect} />}
       </Box>
       <Graph selectedUri={datasetUri} onSelect={onSelect} />
diff --git a/airflow/www/static/js/api/useDataset.ts 
b/airflow/www/static/js/utils/URLSearchParamWrapper.ts
similarity index 60%
copy from airflow/www/static/js/api/useDataset.ts
copy to airflow/www/static/js/utils/URLSearchParamWrapper.ts
index 6f213f5ca4..19dbdc6546 100644
--- a/airflow/www/static/js/api/useDataset.ts
+++ b/airflow/www/static/js/utils/URLSearchParamWrapper.ts
@@ -17,22 +17,18 @@
  * under the License.
  */
 
-import axios, { AxiosResponse } from 'axios';
-import { useQuery } from 'react-query';
-
-import { getMetaValue } from 'src/utils';
-import type { API } from 'src/types';
-
-interface Props {
-  datasetUri: string;
+class URLSearchParamsWrapper extends URLSearchParams {
+  constructor(init?: { [keys: string]: any }) {
+    if (init) {
+      const stringValues: { [keys: string]: string } = {};
+      Object.keys(init).forEach(
+        (key) => { stringValues[key] = init[key].toString(); },
+      );
+      super(init);
+      return;
+    }
+    super(init);
+  }
 }
 
-export default function useDataset({ datasetUri }: Props) {
-  return useQuery(
-    ['dataset', datasetUri],
-    () => {
-      const datasetUrl = `${getMetaValue('datasets_api') || 
'/api/v1/datasets'}/${encodeURIComponent(datasetUri)}`;
-      return axios.get<AxiosResponse, API.Dataset>(datasetUrl);
-    },
-  );
-}
+export default URLSearchParamsWrapper;

Reply via email to