diff --git a/airflow/www/static/js/components/Table/Cells.test.tsx b/airflow/www/static/js/components/Table/Cells.test.tsx
new file mode 100644
index 0000000000000..e92722449c94b
--- /dev/null
+++ b/airflow/www/static/js/components/Table/Cells.test.tsx
@@ -0,0 +1,94 @@
+/*!
+ * 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.
+ */
+
+/* global describe, test, expect */
+
+import React from 'react';
+import '@testing-library/jest-dom';
+import { render } from '@testing-library/react';
+
+import { ChakraWrapper } from 'src/utils/testUtils';
+import * as utils from 'src/utils';
+import { TaskInstanceLink } from './Cells';
+
+const taskId = 'task_id';
+const sourceDagId = 'source_dag_id';
+const sourceRunId = 'source_run_id';
+const originalDagId = 'og_dag_id';
+
+describe('Test TaskInstanceLink', () => {
+ test('Replaces __DAG_ID__ url param correctly', async () => {
+ jest.spyOn(utils, 'getMetaValue').mockImplementation(
+ (meta) => {
+ if (meta === 'grid_url') return '/dags/__DAG_ID__/grid';
+ return null;
+ },
+ );
+
+ const { getByText } = render(
+ ,
+ { wrapper: ChakraWrapper },
+ );
+
+ const link = getByText(`${sourceDagId}.${taskId}`);
+ expect(link).toBeInTheDocument();
+ expect(link).toHaveAttribute('href', `/dags/${sourceDagId}/grid?dag_run_id=${sourceRunId}&task_id=${taskId}`);
+ });
+
+ test('Replaces existing dag id url param correctly', async () => {
+ jest.spyOn(utils, 'getMetaValue').mockImplementation(
+ (meta) => {
+ if (meta === 'dag_id') return originalDagId;
+ if (meta === 'grid_url') return `/dags/${originalDagId}/grid`;
+ return null;
+ },
+ );
+
+ const { getByText } = render(
+ ,
+ { wrapper: ChakraWrapper },
+ );
+
+ const link = getByText(`${sourceDagId}.${taskId}`);
+ expect(link).toBeInTheDocument();
+ expect(link).toHaveAttribute('href', `/dags/${sourceDagId}/grid?dag_run_id=${sourceRunId}&task_id=${taskId}`);
+ });
+});
diff --git a/airflow/www/static/js/components/Table/Cells.tsx b/airflow/www/static/js/components/Table/Cells.tsx
index 0c06d9f7dc1e3..b111a8b6ddc77 100644
--- a/airflow/www/static/js/components/Table/Cells.tsx
+++ b/airflow/www/static/js/components/Table/Cells.tsx
@@ -23,6 +23,7 @@ import {
} from '@chakra-ui/react';
import Time from 'src/components/Time';
+import { getMetaValue } from 'src/utils';
interface CellProps {
cell: {
@@ -35,18 +36,24 @@ interface CellProps {
export const TimeCell = ({ cell: { value } }: CellProps) => ;
-export const DatasetLink = ({ cell: { value, row } }: CellProps) => (
-
- {value}
-
-);
+export const DatasetLink = ({ cell: { value, row } }: CellProps) => {
+ const datasetsUrl = getMetaValue('datasets_url');
+ return (
+
+ {value}
+
+ );
+};
export const TaskInstanceLink = ({ cell: { value, row } }: CellProps) => {
const { sourceRunId, sourceDagId, sourceMapIndex } = row.original;
- const url = `/dags/${sourceDagId}/grid?dag_run_id=${encodeURIComponent(sourceRunId)}&task_id=${encodeURIComponent(value)}`;
+ const gridUrl = getMetaValue('grid_url');
+ const dagId = getMetaValue('dag_id');
+ const stringToReplace = dagId || '__DAG_ID__';
+ const url = `${gridUrl?.replace(stringToReplace, sourceDagId)}?dag_run_id=${encodeURIComponent(sourceRunId)}&task_id=${encodeURIComponent(value)}`;
const mapIndex = sourceMapIndex > -1 ? `[${sourceMapIndex}]` : '';
return (
diff --git a/airflow/www/static/js/datasets/Details.tsx b/airflow/www/static/js/datasets/Details.tsx
index 753f1dc33356e..0a67744080f92 100644
--- a/airflow/www/static/js/datasets/Details.tsx
+++ b/airflow/www/static/js/datasets/Details.tsx
@@ -31,12 +31,15 @@ import {
import { ClipboardButton } from 'src/components/Clipboard';
import type { API } from 'src/types';
import InfoTooltip from 'src/components/InfoTooltip';
+import { getMetaValue } from 'src/utils';
interface Props {
datasetId: string;
onBack: () => void;
}
+const gridUrl = getMetaValue('grid_url');
+
const Details = ({
dataset: {
uri,
@@ -68,7 +71,7 @@ const Details = ({
{`${dagId}.${taskId}`}
@@ -86,7 +89,7 @@ const Details = ({
{dagId}
diff --git a/airflow/www/templates/airflow/datasets.html b/airflow/www/templates/airflow/datasets.html
index 1cd81d547d5df..5b613b28fa31a 100644
--- a/airflow/www/templates/airflow/datasets.html
+++ b/airflow/www/templates/airflow/datasets.html
@@ -24,6 +24,7 @@
{{ super() }}
+
{% endblock %}
{% block content %}