diff --git a/frontend/src/components/pages/admin/admin-debug-bundle.tsx b/frontend/src/components/pages/admin/admin-debug-bundle.tsx index 1a2e1c43e3..1b48f8fcf7 100644 --- a/frontend/src/components/pages/admin/admin-debug-bundle.tsx +++ b/frontend/src/components/pages/admin/admin-debug-bundle.tsx @@ -44,6 +44,7 @@ import { type SCRAMAuth, SCRAMAuth_Mechanism, } from '../../../protogen/redpanda/api/console/v1alpha1/debug_bundle_pb'; +import queryClient from '../../../query-client'; import { appGlobal } from '../../../state/app-global'; import { api, useApiStoreHook } from '../../../state/backend-api'; import type { BrokerWithConfigAndStorage } from '../../../state/rest-interfaces'; @@ -216,9 +217,7 @@ const NewDebugBundleForm: FC<{ useEffect(() => { api.refreshBrokers(true); - api.refreshPartitions('all', true).catch(() => { - // Error handling managed by API layer - }); + queryClient.invalidateQueries({ queryKey: ['topicPartitionsAll'] }); }, []); const fieldViolationsMap = error?.details diff --git a/frontend/src/components/pages/connect/connector-details.tsx b/frontend/src/components/pages/connect/connector-details.tsx index 49d53bf867..516cf08be3 100644 --- a/frontend/src/components/pages/connect/connector-details.tsx +++ b/frontend/src/components/pages/connect/connector-details.tsx @@ -12,6 +12,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { ConfigPage } from './dynamic-ui/components'; +import { useTopicsQuery } from '../../../react-query/api/topic'; import { appGlobal } from '../../../state/app-global'; import { api, createMessageSearch, type MessageSearch, type MessageSearchRequest } from '../../../state/backend-api'; import { ConnectClusterStore } from '../../../state/connect/state'; @@ -87,7 +88,8 @@ const KafkaConnectorMain = ({ }) => { const [connectClusterStore] = useState(() => ConnectClusterStore.getInstance(clusterName)); - const logsTopic = api.topics?.first((x) => x.topicName === LOGS_TOPIC_NAME); + const { data: topicsData } = useTopicsQuery(); + const logsTopic = topicsData?.topics?.first((x) => x.topicName === LOGS_TOPIC_NAME); useEffect(() => { const init = async () => { @@ -478,7 +480,8 @@ const ConnectorErrorModal = (p: { error: ConnectorError }) => { const errorType = p.error.type === 'ERROR' ? 'error' : 'warning'; - const hasConnectorLogs = api.topics?.any((x) => x.topicName === LOGS_TOPIC_NAME); + const { data: connectorTopicsData } = useTopicsQuery(); + const hasConnectorLogs = connectorTopicsData?.topics?.any((x) => x.topicName === LOGS_TOPIC_NAME); return ( <> @@ -536,13 +539,11 @@ class KafkaConnectorDetails extends PageComponent<{ clusterName: string; connect appGlobal.onRefresh = () => this.refreshData(true).catch(console.error); } - async refreshData(force: boolean): Promise { + async refreshData(_force: boolean): Promise { ConnectClusterStore.connectClusters.clear(); await api.refreshConnectClusters(); - // refresh topics so we know whether or not we can show the "go to error logs topic" button in the connector details error popup - // and show the logs tab - api.refreshTopics(force); + // React Query handles topics fetching via useTopicsQuery hooks in child components } render() { @@ -553,9 +554,6 @@ class KafkaConnectorDetails extends PageComponent<{ clusterName: string; connect return ; } - // Touch observables so PageComponent's Reaction tracks them for re-renders. - void api.topics; - return ( @@ -658,7 +656,8 @@ const LogsTab = (p: { const { connector } = p; const connectorName = connector.name; const topicName = LOGS_TOPIC_NAME; - const topic = api.topics?.first((x) => x.topicName === topicName); + const { data: logsTopicsData } = useTopicsQuery(); + const topic = logsTopicsData?.topics?.first((x) => x.topicName === topicName); const [logState, setLogState] = useState<{ messages: TopicMessage[]; isComplete: boolean }>({ messages: [], diff --git a/frontend/src/components/pages/connect/dynamic-ui/forms/topic-input.tsx b/frontend/src/components/pages/connect/dynamic-ui/forms/topic-input.tsx index 67773cafcd..e9f26d2dfb 100644 --- a/frontend/src/components/pages/connect/dynamic-ui/forms/topic-input.tsx +++ b/frontend/src/components/pages/connect/dynamic-ui/forms/topic-input.tsx @@ -19,9 +19,9 @@ import { isMultiValue, Select, } from '@redpanda-data/ui'; -import { useEffect, useMemo, useState } from 'react'; +import { useMemo, useState } from 'react'; -import { api } from '../../../../../state/backend-api'; +import { useTopicsQuery } from '../../../../../react-query/api/topic'; import type { Property } from '../../../../../state/connect/state'; import { ExpandableText } from '../../../../misc/expandable-text'; @@ -40,9 +40,7 @@ export const TopicInput = (p: { properties: Property[]; connectorType: 'sink' | const [selected, setSelected] = useState(initialSelection); - useEffect(() => { - api.refreshTopics(); - }, []); + const { data: topicsData } = useTopicsQuery(); const property = propsMap.get(selected); const isRegex = selected === 'topics.regex'; @@ -97,7 +95,7 @@ export const TopicInput = (p: { properties: Property[]; connectorType: 'sink' | setPropertyValue(property, v.map(({ value }) => value)?.join(',') ?? []); } }} - options={api.topics?.map((x) => ({ value: x.topicName, label: x.topicName })) ?? []} + options={topicsData?.topics?.map((x) => ({ value: x.topicName, label: x.topicName })) ?? []} value={ property.value ? property.value diff --git a/frontend/src/components/pages/consumers/modals.tsx b/frontend/src/components/pages/consumers/modals.tsx index dc9a97015b..df69a50368 100644 --- a/frontend/src/components/pages/consumers/modals.tsx +++ b/frontend/src/components/pages/consumers/modals.tsx @@ -37,6 +37,8 @@ import { import { ChevronLeftIcon, ChevronRightIcon, SkipIcon, TrashIcon, WarningIcon } from 'components/icons'; import { Component } from 'react'; +import queryClient from '../../../query-client'; +import { getTopicOffsetsByTimestamp } from '../../../react-query/api/topic'; import { appGlobal } from '../../../state/app-global'; import { api } from '../../../state/backend-api'; import type { @@ -496,7 +498,7 @@ export class EditOffsetsModal extends Component<{ let offsetsForTimestamp: TopicOffset[]; try { - offsetsForTimestamp = await api.getTopicOffsetsByTimestamp(requiredTopics, this.state.timestampUtcMs); + offsetsForTimestamp = await getTopicOffsetsByTimestamp(requiredTopics, this.state.timestampUtcMs); toast.update(toastRef, { status: 'success', duration: 2000, @@ -660,10 +662,9 @@ export class EditOffsetsModal extends Component<{ // need all groups for "other groups" dropdown api.refreshConsumerGroups(); - // need watermarks for all topics the group consumes - // in order to know earliest/latest offsets + // React Query handles partition data; invalidate to force refetch const topics = this.props.group.topicOffsets.map((x) => x.topic).distinct(); - api.refreshPartitions(topics, true); + queryClient.invalidateQueries({ queryKey: ['topicPartitionsAll', ...topics.slice().sort()] }); // reset settings this.setState({ page: 0, selectedOption: 'startOffset' }); @@ -787,7 +788,10 @@ class ColAfter extends Component<{ // not found - no message after given timestamp // use 'latest' - const partition = api.topicPartitions.get(record.topicName)?.first((p) => p.id === record.partitionId); + const partitionsAllData = queryClient.getQueryData< + Map + >(['topicPartitionsAll']); + const partition = partitionsAllData?.get(record.topicName)?.first((p) => p.id === record.partitionId); return (
p.id === record.partitionId); + const partitionsAllData2 = queryClient.getQueryData< + Map + >(['topicPartitionsAll']); + const partition = partitionsAllData2?.get(record.topicName)?.first((p) => p.id === record.partitionId); const content = val === -2 diff --git a/frontend/src/components/pages/reassign-partitions/components/active-reassignments.tsx b/frontend/src/components/pages/reassign-partitions/components/active-reassignments.tsx index 70f21a1163..5e4d29b88c 100644 --- a/frontend/src/components/pages/reassign-partitions/components/active-reassignments.tsx +++ b/frontend/src/components/pages/reassign-partitions/components/active-reassignments.tsx @@ -45,6 +45,7 @@ import { import React, { Component, type FC, type JSX, useRef, useState } from 'react'; import { BandwidthSlider } from './bandwidth-slider'; +import queryClient from '../../../../query-client'; import { api } from '../../../../state/backend-api'; import type { ConfigEntry } from '../../../../state/rest-interfaces'; import { QuickTable } from '../../../../utils/tsx-utils'; @@ -376,19 +377,17 @@ export class ReassignmentDetailsDialog extends Component<{ state: ReassignmentSt // became visible or invisible // force update of topic config, so isThrottle has up to date information setTimeout(async () => { - api.topicConfig.delete(state.topicName); - await api.refreshTopicConfig(state.topicName, true); + await queryClient.invalidateQueries({ queryKey: ['topicConfig', state.topicName] }); this.setState({ shouldThrottle: this.isThrottled() }); }); } this.wasVisible = visible; - const topicConfig = api.topicConfig.get(state.topicName); - if (!topicConfig) { - setTimeout(() => { - api.refreshTopicConfig(state.topicName); - }); - } + const topicConfig = + queryClient.getQueryData([ + 'topicConfig', + state.topicName, + ]) ?? null; const replicas = state.partitions.flatMap((p) => p.replicas).distinct(); const addingReplicas = state.partitions.flatMap((p) => p.addingReplicas).distinct(); @@ -463,7 +462,11 @@ export class ReassignmentDetailsDialog extends Component<{ state: ReassignmentSt if (!this.lastState) { return false; } - const config = api.topicConfig.get(this.lastState.topicName); + const config = + queryClient.getQueryData([ + 'topicConfig', + this.lastState.topicName, + ]) ?? null; if (!config) { return false; } diff --git a/frontend/src/components/pages/reassign-partitions/logic/reassignment-tracker.ts b/frontend/src/components/pages/reassign-partitions/logic/reassignment-tracker.ts index ac87c17297..a3ad760230 100644 --- a/frontend/src/components/pages/reassign-partitions/logic/reassignment-tracker.ts +++ b/frontend/src/components/pages/reassign-partitions/logic/reassignment-tracker.ts @@ -13,6 +13,7 @@ // - manages timers for refreshing current reassignments // - tracks progress history for each reassignment to estimate speed and ETA +import queryClient from '../../../../query-client'; import { api } from '../../../../state/backend-api'; import type { PartitionReassignments } from '../../../../state/rest-interfaces'; import { IsDev } from '../../../../utils/env'; @@ -114,7 +115,7 @@ export class ReassignmentTracker { // Update relevant topic-partitions const topics = liveReassignments.map((r) => r.topicName); if (topics.length > 0) { - await api.refreshPartitions(topics, true); + queryClient.invalidateQueries({ queryKey: ['topicPartitionsAll'] }); } // Add new reassignments @@ -189,7 +190,10 @@ export class ReassignmentTracker { // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: legacy code updateReassignmentState(state: ReassignmentState) { // partition stats - const topicPartitions = api.topicPartitions.get(state.topicName); + const topicPartitionsAllData = queryClient.getQueryData< + Map + >(['topicPartitionsAll']); + const topicPartitions = topicPartitionsAllData?.get(state.topicName); for (const p of state.partitions) { const logDirs = topicPartitions?.first((e) => e.id === p.partitionId)?.partitionLogDirs.filter((l) => !l.error); if (!logDirs || logDirs.length === 0) { diff --git a/frontend/src/components/pages/reassign-partitions/reassign-partitions.tsx b/frontend/src/components/pages/reassign-partitions/reassign-partitions.tsx index 9a533ff7bc..9e33cc2360 100644 --- a/frontend/src/components/pages/reassign-partitions/reassign-partitions.tsx +++ b/frontend/src/components/pages/reassign-partitions/reassign-partitions.tsx @@ -45,6 +45,7 @@ import { import { StepSelectPartitions } from './step1-partitions'; import { StepSelectBrokers } from './step2-brokers'; import { StepReview, type TopicWithMoves } from './step3-review'; +import queryClient from '../../../query-client'; import { appGlobal } from '../../../state/app-global'; import { api, partialTopicConfigs } from '../../../state/backend-api'; import type { @@ -185,8 +186,8 @@ class ReassignPartitions extends PageComponent { refreshData(force: boolean) { api.refreshCluster(force); // need to know brokers for reassignment calculation, will also refresh config - api.refreshTopics(force); - api.refreshPartitions('all', force); + queryClient.invalidateQueries({ queryKey: ['topics'] }); + queryClient.invalidateQueries({ queryKey: ['topicPartitionsAll'] }); api.refreshPartitionReassignments(force); } @@ -200,16 +201,15 @@ class ReassignPartitions extends PageComponent { if (!api.clusterInfo) { return DefaultSkeleton; } - if (!api.topics) { - return DefaultSkeleton; - } - if (api.partitionReassignments === undefined) { return DefaultSkeleton; } - const partitionCountLeaders = api.topics?.sum((t) => t.partitionCount); - const partitionCountOnlyReplicated = api.topics?.sum((t) => t.partitionCount * (t.replicationFactor - 1)); + const cachedTopics = queryClient.getQueryData([ + 'topics', + ])?.topics; + const partitionCountLeaders = cachedTopics?.sum((t) => t.partitionCount); + const partitionCountOnlyReplicated = cachedTopics?.sum((t) => t.partitionCount * (t.replicationFactor - 1)); const { currentStep, requestInProgress, partitionSelection, selectedBrokerIds, reassignmentRequest } = this.state; @@ -236,7 +236,10 @@ class ReassignPartitions extends PageComponent { (); - for (const [topicName, partitions] of api.topicPartitions) { + const cachedTopicPartitions = queryClient.getQueryData< + Map + >(['topicPartitionsAll']); + for (const [topicName, partitions] of cachedTopicPartitions ?? + new Map()) { if (!partitions) { continue; } @@ -505,10 +512,12 @@ class ReassignPartitions extends PageComponent { apiTopicPartitions.set(topicName, validOnly); } + const cachedTopicsData = + queryClient.getQueryData(['topics'])?.topics ?? []; // error checking will happen inside computeReassignments const apiData: ApiData = { brokers: api.clusterInfo?.brokers ?? [], - topics: api.topics as Topic[], + topics: cachedTopicsData as Topic[], topicPartitions: apiTopicPartitions, }; @@ -634,7 +643,10 @@ class ReassignPartitions extends PageComponent { const followerReplicas: { partitionId: number; brokerId: number }[] = []; for (const p of t.partitions) { const partitionId = p.partitionId; - const brokersOld = api.topicPartitions + const cachedTpForTraffic = queryClient.getQueryData< + Map + >(['topicPartitionsAll']); + const brokersOld = cachedTpForTraffic ?.get(t.topicName) ?.first((partition) => partition.id === partitionId)?.replicas; const brokersNew = p.replicas; @@ -773,8 +785,12 @@ class ReassignPartitions extends PageComponent { } get selectedTopicPartitions(): TopicPartitions[] | undefined { - const apiTopics = api.topics; - const apiPartitions = api.topicPartitions; + const apiTopics = queryClient.getQueryData([ + 'topics', + ])?.topics; + const apiPartitions = queryClient.getQueryData< + Map + >(['topicPartitionsAll']); if (!(apiTopics && apiPartitions)) { // biome-ignore lint/suspicious/useGetterReturn: early return for undefined case @@ -788,7 +804,10 @@ class ReassignPartitions extends PageComponent { let maxRf = 0; for (const topicName in this.state.partitionSelection) { if (Object.hasOwn(this.state.partitionSelection, topicName)) { - const topic = api.topics?.first((x) => x.topicName === topicName); + const cachedTopicsForRf = queryClient.getQueryData([ + 'topics', + ])?.topics; + const topic = cachedTopicsForRf?.first((x) => x.topicName === topicName); if (topic && topic.replicationFactor > maxRf) { maxRf = topic.replicationFactor; } @@ -801,14 +820,21 @@ class ReassignPartitions extends PageComponent { if (this.state.reassignmentRequest === null) { return []; } - if (api.topics === null) { + const cachedTopicsForMoves = queryClient.getQueryData([ + 'topics', + ])?.topics; + if (!cachedTopicsForMoves) { return []; } + const cachedTpForMoves = + queryClient.getQueryData>([ + 'topicPartitionsAll', + ]) ?? new Map(); return computeMovedReplicas( this.state.partitionSelection, this.state.reassignmentRequest, - api.topics, - api.topicPartitions + cachedTopicsForMoves, + cachedTpForMoves ); } diff --git a/frontend/src/components/pages/reassign-partitions/step1-partitions.tsx b/frontend/src/components/pages/reassign-partitions/step1-partitions.tsx index 8f0576b4f2..84640bff0c 100644 --- a/frontend/src/components/pages/reassign-partitions/step1-partitions.tsx +++ b/frontend/src/components/pages/reassign-partitions/step1-partitions.tsx @@ -17,8 +17,14 @@ import Highlighter from 'react-highlight-words'; import { SelectionInfoBar } from './components/statistics-bar'; import type { PartitionSelection } from './reassign-partitions'; +import queryClient from '../../../query-client'; import { api } from '../../../state/backend-api'; -import type { Partition, PartitionReassignmentsPartition, Topic } from '../../../state/rest-interfaces'; +import type { + GetTopicsResponse, + Partition, + PartitionReassignmentsPartition, + Topic, +} from '../../../state/rest-interfaces'; import { uiSettings } from '../../../state/ui'; import { DefaultSkeleton, InfoText, ZeroSizeWrapper } from '../../../utils/tsx-utils'; import { prettyBytesOrNA } from '../../../utils/utils'; @@ -54,7 +60,8 @@ export class StepSelectPartitions extends Component<{ } render() { - if (!api.topics) { + const topics = queryClient.getQueryData(['topics']); + if (!topics) { return DefaultSkeleton; } @@ -262,11 +269,13 @@ export class StepSelectPartitions extends Component<{ } get topicPartitions(): TopicWithPartitions[] { - if (api.topics === null) { + const topicsData = queryClient.getQueryData(['topics']); + const topicPartitionsAll = queryClient.getQueryData>(['topicPartitionsAll']); + if (topicsData === null || topicsData === undefined) { return []; } - return api.topics.flatMap((topic) => { - const partitions = api.topicPartitions.get(topic.topicName); + return (topicsData.topics ?? []).flatMap((topic) => { + const partitions = topicPartitionsAll?.get(topic.topicName); if (!partitions) { return []; // skip topics whose partitions haven't loaded yet (e.g. newly created) } diff --git a/frontend/src/components/pages/reassign-partitions/step3-review.tsx b/frontend/src/components/pages/reassign-partitions/step3-review.tsx index 70083f1219..32600db58f 100644 --- a/frontend/src/components/pages/reassign-partitions/step3-review.tsx +++ b/frontend/src/components/pages/reassign-partitions/step3-review.tsx @@ -15,8 +15,14 @@ import { Component } from 'react'; import { BandwidthSlider } from './components/bandwidth-slider'; import type ReassignPartitions from './reassign-partitions'; import type { PartitionSelection } from './reassign-partitions'; -import { api } from '../../../state/backend-api'; -import type { Partition, PartitionReassignmentRequest, Topic, TopicAssignment } from '../../../state/rest-interfaces'; +import queryClient from '../../../query-client'; +import type { + GetTopicsResponse, + Partition, + PartitionReassignmentRequest, + Topic, + TopicAssignment, +} from '../../../state/rest-interfaces'; import { uiSettings } from '../../../state/ui'; import { DefaultSkeleton, InfoText } from '../../../utils/tsx-utils'; import { prettyBytesOrNA, prettyMilliseconds } from '../../../utils/utils'; @@ -46,10 +52,12 @@ export class StepReview extends Component<{ reassignPartitions: ReassignPartitions; // since api is still changing, we pass parent down so we can call functions on it directly }> { render() { - if (!api.topics) { + const topics = queryClient.getQueryData(['topics']); + const topicPartitionsAll = queryClient.getQueryData>(['topicPartitionsAll']); + if (!topics) { return DefaultSkeleton; } - if (api.topicPartitions.size === 0) { + if ((topicPartitionsAll?.size ?? 0) === 0) { return ; } diff --git a/frontend/src/components/pages/rp-connect/pipelines-details.tsx b/frontend/src/components/pages/rp-connect/pipelines-details.tsx index 47215b1a96..0c491db68a 100644 --- a/frontend/src/components/pages/rp-connect/pipelines-details.tsx +++ b/frontend/src/components/pages/rp-connect/pipelines-details.tsx @@ -31,9 +31,9 @@ import { type Pipeline_Resources, Pipeline_State, } from '../../../protogen/redpanda/api/dataplane/v1/pipeline_pb'; +import { useTopicsQuery } from '../../../react-query/api/topic'; import { appGlobal } from '../../../state/app-global'; import { - api, createMessageSearch, type MessageSearch, type MessageSearchRequest, @@ -264,7 +264,8 @@ const PipelineEditor = (p: { pipeline: Pipeline }) => { export const LogsTab = ({ pipeline, variant = 'card' }: { pipeline: Pipeline; variant?: 'ghost' | 'card' }) => { const topicName = '__redpanda.connect.logs'; - const topic = api.topics?.first((x) => x.topicName === topicName); + const { data: topicsData } = useTopicsQuery(); + const topic = topicsData?.topics?.first((x) => x.topicName === topicName); const [logState, setLogState] = useState<{ messages: TopicMessage[]; isComplete: boolean }>({ messages: [], diff --git a/frontend/src/components/pages/schemas/schema-create.tsx b/frontend/src/components/pages/schemas/schema-create.tsx index 2ecae1ff1e..c139a98bf8 100644 --- a/frontend/src/components/pages/schemas/schema-create.tsx +++ b/frontend/src/components/pages/schemas/schema-create.tsx @@ -52,6 +52,7 @@ import { useSchemaRegistryContextsQuery, useSchemaTypesQuery, } from '../../../react-query/api/schema-registry'; +import { useTopicsQuery } from '../../../react-query/api/topic'; import { appGlobal } from '../../../state/app-global'; import { api, useApiStoreHook } from '../../../state/backend-api'; import { @@ -178,7 +179,7 @@ export class SchemaCreatePage extends PageComponent<{ contextName?: string }> { refreshData(force?: boolean) { api.refreshSchemaSubjects(force); // for references editor -> subject selector - api.refreshTopics(force); // for the topics selector + // topics are fetched via useTopicsQuery hook } render() { @@ -523,6 +524,7 @@ const SchemaEditor = (p: { const srContextsEnabled = useSupportedFeaturesStore((s) => s.schemaRegistryContexts); const { data: apiContexts } = useSchemaRegistryContextsQuery(srContextsEnabled); const { data: subjects } = useListSchemasQuery(); + const { data: topicsData } = useTopicsQuery(); useEffect(() => { api.refreshSchemaTypes(true); @@ -657,7 +659,7 @@ const SchemaEditor = (p: { - {(api.topics?.filter((x) => !x.topicName.startsWith('_')) ?? []).map((x) => ( + {(topicsData?.topics.filter((x) => !x.topicName.startsWith('_')) ?? []).map((x) => ( {x.topicName} diff --git a/frontend/src/components/pages/topics/DeleteRecordsModal/delete-records-modal.test.tsx b/frontend/src/components/pages/topics/DeleteRecordsModal/delete-records-modal.test.tsx index ae40da5c79..d87a36cf18 100644 --- a/frontend/src/components/pages/topics/DeleteRecordsModal/delete-records-modal.test.tsx +++ b/frontend/src/components/pages/topics/DeleteRecordsModal/delete-records-modal.test.tsx @@ -9,11 +9,14 @@ * by the Apache License, Version 2.0 */ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { render, screen } from '@testing-library/react'; import DeleteRecordsModal from './delete-records-modal'; import type { Topic } from '../../../../state/rest-interfaces'; +const queryClient = new QueryClient(); + const testTopic: Topic = { allowedActions: ['all'], cleanupPolicy: 'compact', @@ -32,7 +35,15 @@ const testTopic: Topic = { describe('DeleteRecordsModal', () => { test('renders all expected elements in step 1', () => { render( - + + + ); expect(screen.getByText('Delete records in topic')).toBeInTheDocument(); diff --git a/frontend/src/components/pages/transforms/transform-details.tsx b/frontend/src/components/pages/transforms/transform-details.tsx index 585deda30a..08a4eb6b80 100644 --- a/frontend/src/components/pages/transforms/transform-details.tsx +++ b/frontend/src/components/pages/transforms/transform-details.tsx @@ -22,9 +22,9 @@ import { PartitionTransformStatus_PartitionStatus, type TransformMetadata, } from '../../../protogen/redpanda/api/dataplane/v1/transform_pb'; +import { useTopicsQuery } from '../../../react-query/api/topic'; import { appGlobal } from '../../../state/app-global'; import { - api, createMessageSearch, type MessageSearch, type MessageSearchRequest, @@ -187,7 +187,8 @@ const OverviewTab = (p: { transform: TransformMetadata }) => { const LogsTab = (p: { transform: TransformMetadata }) => { const topicName = '_redpanda.transform_logs'; - const topic = api.topics?.first((x) => x.topicName === topicName); + const { data: topicsData } = useTopicsQuery(); + const topic = topicsData?.topics?.first((x) => x.topicName === topicName); const [logState, setLogState] = useState<{ messages: TopicMessage[]; isComplete: boolean }>({ messages: [],