From 749fe1380f1627cc5848f83e1ff16fbca5396950 Mon Sep 17 00:00:00 2001
From: Julin <142230457+c-julin@users.noreply.github.com>
Date: Mon, 16 Feb 2026 12:42:33 +0000
Subject: [PATCH 1/4] fix: handle FailedPrecondition in shadow links route
loader
---
frontend/src/routes/shadowlinks/index.tsx | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/frontend/src/routes/shadowlinks/index.tsx b/frontend/src/routes/shadowlinks/index.tsx
index a71168475..a1b29f69f 100644
--- a/frontend/src/routes/shadowlinks/index.tsx
+++ b/frontend/src/routes/shadowlinks/index.tsx
@@ -10,23 +10,30 @@
*/
import { create } from '@bufbuild/protobuf';
+import { Code, ConnectError } from '@connectrpc/connect';
import { createQueryOptions } from '@connectrpc/connect-query';
import { createFileRoute } from '@tanstack/react-router';
import { ShieldIcon } from 'components/icons';
+import { ShadowLinkListPage } from 'components/pages/shadowlinks/list/shadowlink-list-page';
import { ListShadowLinksRequestSchema } from 'protogen/redpanda/api/console/v1alpha1/shadowlink_pb';
import { listShadowLinks } from 'protogen/redpanda/api/console/v1alpha1/shadowlink-ShadowLinkService_connectquery';
-import { ShadowLinkListPage } from '../../components/pages/shadowlinks/list/shadowlink-list-page';
-
export const Route = createFileRoute('/shadowlinks/')({
staticData: {
title: 'Shadow Links',
icon: ShieldIcon,
},
loader: async ({ context: { queryClient, dataplaneTransport } }) => {
- await queryClient.ensureQueryData(
- createQueryOptions(listShadowLinks, create(ListShadowLinksRequestSchema, {}), { transport: dataplaneTransport })
- );
+ try {
+ await queryClient.ensureQueryData(
+ createQueryOptions(listShadowLinks, create(ListShadowLinksRequestSchema, {}), { transport: dataplaneTransport })
+ );
+ } catch (error) {
+ if (error instanceof ConnectError && error.code === Code.FailedPrecondition) {
+ return;
+ }
+ throw error;
+ }
},
component: ShadowLinkListPage,
});
From 5e784e1f47ae5c2a5cbe38c285e686b4257dceb6 Mon Sep 17 00:00:00 2001
From: Martin Schneppenheim <23424570+weeco@users.noreply.github.com>
Date: Mon, 16 Feb 2026 14:25:36 +0000
Subject: [PATCH 2/4] fix: remove ShadowLinkService from
HIDE_IF_NOT_SUPPORTED_FEATURES
Shadow Links should remain visible in the sidebar even when the feature
is disabled so users can see instructions on how to enable it. The
loader try-catch handles FailedPrecondition gracefully for disabled
clusters.
---
frontend/src/state/supported-features.ts | 2 +-
frontend/src/utils/route-utils.tsx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/frontend/src/state/supported-features.ts b/frontend/src/state/supported-features.ts
index fb58796c2..f14c67e80 100644
--- a/frontend/src/state/supported-features.ts
+++ b/frontend/src/state/supported-features.ts
@@ -118,7 +118,7 @@ export function isSupported(f: FeatureEntry): boolean {
/**
* A list of features we should hide instead of showing a disabled message.
*/
-const HIDE_IF_NOT_SUPPORTED_FEATURES = [Feature.GetQuotas, Feature.ShadowLinkService, Feature.TracingService];
+const HIDE_IF_NOT_SUPPORTED_FEATURES = [Feature.GetQuotas, Feature.TracingService];
export function shouldHideIfNotSupported(f: FeatureEntry): boolean {
return HIDE_IF_NOT_SUPPORTED_FEATURES.includes(f);
}
diff --git a/frontend/src/utils/route-utils.tsx b/frontend/src/utils/route-utils.tsx
index 97b5c911e..76cb43e13 100644
--- a/frontend/src/utils/route-utils.tsx
+++ b/frontend/src/utils/route-utils.tsx
@@ -290,7 +290,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
if (isEmbedded()) {
return isFeatureFlagEnabled('shadowlinkCloudUi') && !isServerless();
}
- return true; // self-hosted always visible
+ return true;
}),
},
{
From 5b33afb9b731901a1c8a9d7ae8b24e244be9c2ac Mon Sep 17 00:00:00 2001
From: Julin <142230457+c-julin@users.noreply.github.com>
Date: Mon, 16 Feb 2026 15:26:33 +0000
Subject: [PATCH 3/4] fix: hide shadow links tab on non-Redpanda clusters
---
frontend/src/utils/route-utils.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/src/utils/route-utils.tsx b/frontend/src/utils/route-utils.tsx
index 76cb43e13..c75340c22 100644
--- a/frontend/src/utils/route-utils.tsx
+++ b/frontend/src/utils/route-utils.tsx
@@ -290,7 +290,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
if (isEmbedded()) {
return isFeatureFlagEnabled('shadowlinkCloudUi') && !isServerless();
}
- return true;
+ return api.isRedpanda;
}),
},
{
From e18768772420796b75ea69265338bc785e25a798 Mon Sep 17 00:00:00 2001
From: Julin <142230457+c-julin@users.noreply.github.com>
Date: Mon, 16 Feb 2026 17:28:35 +0000
Subject: [PATCH 4/4] fix: show distinct unavailable state for shadow links on
non-Redpanda clusters
Non-Redpanda clusters (e.g. Apache Kafka) return Code.Unavailable because
the Redpanda Admin API doesn't exist. Previously this showed the same
FeatureDisabled card with an `rpk` command, which is incorrect for these
clusters. Add a separate ShadowLinkUnavailableState with an info alert
explaining that shadowing requires a Redpanda cluster with the Admin API.
---
.../list/shadowlink-empty-state.tsx | 20 ++++++++++++++++++-
.../shadowlinks/list/shadowlink-list-page.tsx | 14 +++++++++++--
frontend/src/routes/shadowlinks/index.tsx | 5 ++++-
frontend/src/utils/route-utils.tsx | 2 +-
4 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/frontend/src/components/pages/shadowlinks/list/shadowlink-empty-state.tsx b/frontend/src/components/pages/shadowlinks/list/shadowlink-empty-state.tsx
index d22e5f5d7..45fbb631a 100644
--- a/frontend/src/components/pages/shadowlinks/list/shadowlink-empty-state.tsx
+++ b/frontend/src/components/pages/shadowlinks/list/shadowlink-empty-state.tsx
@@ -9,11 +9,12 @@
* by the Apache License, Version 2.0
*/
+import { Alert, AlertDescription } from 'components/redpanda-ui/components/alert';
import { Button } from 'components/redpanda-ui/components/button';
import { Card, CardContent, CardHeader, CardTitle } from 'components/redpanda-ui/components/card';
import { CodeBlock, Pre } from 'components/redpanda-ui/components/code-block';
import { Text } from 'components/redpanda-ui/components/typography';
-import { AlertCircle, SearchX } from 'lucide-react';
+import { AlertCircle, Info, SearchX } from 'lucide-react';
const ShadowingDescription = () => (
<>
@@ -86,6 +87,23 @@ export const ShadowLinkFeatureDisabledState = () => (
);
+export const ShadowLinkUnavailableState = () => (
+